DataEngine (Write Layer)
Purpose: centralize write operations that should emit standard events, so indexing and other subscribers remain consistent regardless of where writes originate.
API
setCustomFields({ entityId, recordId, organizationId?, tenantId?, values, notify? })- Persists custom field values (using definitions where available).
- Emits
<module>.<entity>.updatedwith{ id, organizationId, tenantId }whennotify !== false(default true).
DI registration
- Resolved via
dataEnginefrom the request container:packages/shared/src/lib/di/container.ts- Default implementation:
DefaultDataEngineinpackages/shared/src/lib/data/engine.ts.
Usage
- CRUD routes (already wired):
packages/shared/src/lib/crud/factory.tscallsdataEngine.setCustomFields(...)on create/update when custom fields are enabled.
- Manual scripts / CLIs:
- Resolve and call
dataEngine.setCustomFields(...)instead of writing CFs directly.
- Resolve and call
See also
Example
const { resolve } = await createRequestContainer()
const de = resolve('dataEngine') as DataEngine
await de.setCustomFields({
entityId: 'example:todo',
recordId: todoId,
organizationId: orgId,
tenantId,
values: { priority: 3, severity: 'high' },
})
Why this matters
- Guarantees a single, coherent source of CRUD-related events used by the indexing layer and other subscribers.
- Avoids UI-level
onChangedhooks for CF writes; events are emitted at the data layer.
Extending
- You can add
create,update, anddeletehelpers toDataEngineto funnel all entity mutations through the same layer (for audit, validation, or derived writes) while keeping module boundaries clean.
Related files
packages/shared/src/lib/data/engine.tspackages/shared/src/lib/di/container.ts: queryEngine, dataEnginepackages/shared/src/lib/crud/factory.tspackages/example/src/modules/example/cli.ts