Skip to content

06 — Backend Use Cases

The backend should be organized around use cases rather than generic repositories.

Use Drizzle directly inside services and use-case functions to keep native type inference, autocomplete, SQL composition, and transaction support.

Suggested Module Structure

text
apps/backend/src/modules/entity-platform-admin/

├── model-versions.routes.ts
├── model-versions.service.ts
├── model-validation.service.ts
├── model-publishing.service.ts

├── entity-types/
│   ├── entity-types.routes.ts
│   ├── create-entity-type.ts
│   ├── update-entity-type.ts
│   ├── delete-entity-type.ts
│   └── clone-entity-types-to-draft.ts

├── properties/
│   ├── property-groups.routes.ts
│   ├── property-definitions.routes.ts
│   ├── create-property-definition.ts
│   ├── update-property-definition.ts
│   └── delete-property-definition.ts

├── relationships/
│   ├── relationship-definitions.routes.ts
│   ├── create-relationship-definition.ts
│   ├── update-relationship-definition.ts
│   └── delete-relationship-definition.ts

├── templates/
│   ├── templates.routes.ts
│   ├── create-template.ts
│   ├── update-template.ts
│   └── delete-template.ts

├── runtime/
│   ├── runtime-entities.routes.ts
│   ├── create-runtime-entity.ts
│   ├── update-runtime-entity.ts
│   ├── set-runtime-property.ts
│   ├── add-runtime-relationship.ts
│   └── delete-runtime-entity.ts

└── shared/
    ├── assert-draft-model.ts
    ├── assert-published-model.ts
    ├── assert-model-admin-permission.ts
    ├── resolve-published-model.ts
    ├── validate-property-value.ts
    └── audit-model-event.ts

Use Case: Create Draft Model

Purpose:

Create a draft model from the current published model or from an empty baseline.

Steps:

  1. Check model.admin permission.
  2. Ensure there is not already an active draft unless multiple drafts are explicitly supported.
  3. Create entity_model_versions row with status draft.
  4. Clone published metadata into the draft, or create empty baseline metadata.
  5. Write audit event.
  6. Return draft summary.

Use Case: Create Entity Type

Steps:

  1. Check model admin permission.
  2. Verify target model version exists and is draft.
  3. Validate key format.
  4. Ensure key is unique in draft.
  5. Insert entity type definition.
  6. Optionally insert hierarchy rules.
  7. Write audit event.
  8. Return DTO.

Use Case: Create Property Definition

Steps:

  1. Check model admin permission.
  2. Verify model version is draft.
  3. Verify property group exists in same model version.
  4. Validate property key and value type.
  5. Validate value-type-specific validation JSON.
  6. Insert property definition.
  7. Write audit event.
  8. Return DTO.

Use Case: Publish Model

Publishing must be transactional.

Steps:

  1. Check model.publish permission.
  2. Load draft metadata.
  3. Run full validation.
  4. Run compatibility analysis against runtime data.
  5. Require approval for destructive changes.
  6. Mark existing published model as archived.
  7. Mark draft as published.
  8. Write audit event.
  9. Invalidate model metadata caches.
  10. Return published model version.

Use Case: Create Runtime Entity

Steps:

  1. Resolve published model version.
  2. Resolve entity type by key.
  3. Check user permission and root scope.
  4. Validate parent rules.
  5. Generate entity id and path label.
  6. Build ltree path.
  7. Validate template if provided.
  8. Validate property values against property definitions.
  9. Validate tag assignments.
  10. Insert entity row.
  11. Insert property values.
  12. Insert tag assignments.
  13. Write audit event.
  14. Return entity DTO.

Use Case: Update Runtime Property

Steps:

  1. Resolve entity.
  2. Check user root scope and capability.
  3. Resolve published property definition by key.
  4. Verify property is allowed for entity type.
  5. Validate value.
  6. If sensitive, route to Vault instead of property value table.
  7. Upsert value.
  8. Write audit event.
  9. Return updated property value.

Use Case: Add Runtime Relationship

Steps:

  1. Resolve source and target entities.
  2. Check root scope for source and target.
  3. Resolve relationship definition.
  4. Verify source type and target type match definition.
  5. Enforce cardinality.
  6. Enforce self-reference rules.
  7. Insert relationship.
  8. Write audit event.
  9. Return relationship DTO.

Invariants

These rules should be enforced consistently:

  • Published model versions are immutable.
  • Runtime CRUD uses only the current published model.
  • Draft metadata never affects runtime CRUD.
  • Entity hierarchy is not stored in relationship definitions.
  • Sensitive values are not stored as normal property values.
  • Root-scope authorization applies before runtime reads and writes.
  • Deletions are soft by default.
  • Destructive metadata changes require compatibility checks.

Caching

The published model should be cached in memory for fast validation.

Cache invalidation should occur on publish.

Do not cache drafts aggressively unless needed.