Backend Integration
CRM — Backend Integration
For backend developers extending or maintaining the CRM (the object
module, class CrmModule in crm.module.ts).
Services
Controllers call DataService (records/services/data.service.ts) — the
facade — and nothing else. It delegates:
| Type | Examples | Rule |
|---|---|---|
| Facade | DataService | The only records entry point for controllers. |
| Query | records/queries/ — list, search, lookup, single, facets, relation-batch | Read paths + pagination + filtering. No writes. |
| Mutation | records/mutations/ — record-create, record-update, record-delete, record-bulk | Writes in a transaction, then emit a data.* event. |
| Response | DataResponseService | Shape rows into the { fields, data } envelope via response DTOs. |
Add a read concern → a new query service; a write concern → a new mutation service. Don't grow the controllers.
Validation (field-type registry)
Record data is validated per field before persistence:
DynamicValidationService(fields/services/validation/dynamic-validation.service.ts) walks the object's fields, checks required-ness (FieldProcessor— a missing slug on arequiredfield throwsField '<name>' is required), and dispatches each value to its type handler.FieldTypeRegistry(_shared/field-types/) is the factory: at boot it auto-discovers every@HandlesFieldType(...)provider and builds aFieldType → handlermap (validate + serialize). It fails fast if any of the 17FieldTypes has no handler — a new type can't silently pass through.ValidationEngineServiceadditionally enforces conditional-requirement rules (a field required only when another field has a given value).
select / multi_select / status / priority / tag values are validated
against the field's allowed options after the required check.
Controllers & guards
Record and schema controllers are reachable by both a human JWT and an API
key — they stack @UseGuards(ApiAuthGuard, PermissionGuard):
DataReadController/DataWriteController(object/data)ObjectController(object),FieldController(object/field)
ApiAuthGuard extends AdminAuthGuard: it routes by credential
(crtk_live_… → API key, crtk_oauth_… → OAuth, else JWT) and attaches the
same acting-as-admin AdminUser — so PermissionGuard and the row-level
filters behave identically downstream. API keys never inherit the
super-admin bypass.
Sibling controllers are admin-JWT-only (AdminAuthGuard, no API key):
RelationController (object/relation), CustomViewController
(object/custom/view), DataExportImportController, AnalyticsController, and
CommentController (comments/:objectSlug/:dataSlug, AdminAuthGuard only —
no PermissionGuard).
Permissions
Record endpoints use the derived route names {verb}.{objectSlug}
(read.deals, create.deals, …), tagged with @RouteName('create.{objectSlug}')
— PermissionGuard resolves {objectSlug} from the request param. Object
schema endpoints use static object.* / relation.* route names. There is no
separate binary per-object permission — the level owns the gate (the
single-gate, Kommo-style model). See Authorization.
Row-level scope is applied even past the gate via
access-filter.builder.ts (A: no filter, G: group members, M:
admin_id = me, D: 1=0).
Events
Mutations emit through RecordEventsService (records/mutations/helpers/):
| Event | When | Payload highlights |
|---|---|---|
data.created | Record created | objectSlug, dataSlug, newData, sourceType, enrichedRecord |
data.updated | Record updated | oldData, newData, changedRelations |
data.deleted | Record deleted | objectSlug, dataSlug |
data.bulk_deleted / bulk_updated / bulk_assigned | Bulk ops | affectedSlugs, affectedCount |
sourceType is manual / automation / system / api / ai; API-key and
OAuth writes are auto-tagged api with sourceApiKeyId / sourceOauthClientId
for webhook loop prevention. See Events.
Multi-tenant safety
The CRM runs on the shared hyper-tenant DB. All DB access must go through the
pinned repoProvider; Bull processors (import/export) decorate the handler with
@TenantScoped(). Never reach the raw DataSource — RLS would return zero rows or
reject the insert. Read the isolation rules before touching any query or worker.
Next
- The endpoints → REST API
- Event shapes → Events
- Recommended patterns → Best Practices