Selegic CRM Docs
ServerCRUD

Architecture

Execution pipeline, layer composition, and request flow in the CRUD engine.

Request Flow

POST /contact/createOne execute("contact", "createOne", params) run() runBeforeHooks() processedParams execute("contact", "createOne", processedParams) prisma.contact.create() dbResult dbResult runAfterSuccessHooks() success finalResult Result JSON Response Hono Client createCrudRoutes CrudService OperationPipeline CrudHookService CrudRepository Prisma

Layered Design

The CRUD implementation follows a four-layer architecture:

1. Transport Layer (Hono)

  • Location: features/crud/crud.routes.ts
  • Purpose: Maps HTTP requests to CRUD operations using zValidator
  • Generated endpoints: Standard REST-like POST endpoints per model

2. Service Layer (Effect)

  • Location: features/crud/services/crud.service.ts
  • Purpose: Orchestrates the Operation Pipeline
  • Interface: execute<T>(model, op, params, context)

3. Logic Layer (Hooks)

  • Location: features/crud/services/crud-hook.service.ts
  • Purpose: Manages lifecycle hooks via hook-executor.ts
  • Stages:
    • runBeforeHooks: Modify params before DB operation
    • runAfterSuccessHooks: Side-effects after successful write
    • runAfterFailureHooks: Error handling

4. Data Layer (Prisma)

  • Location: features/crud/services/crud-repository.service.ts
  • Purpose: Low-level database access
  • Features:
    • Dynamic delegate selection: prisma[model]
    • Retry logic via withDbRetry
    • Error mapping to CrudError

Hook Registration

Hooks are registered using registerCrudHook in factory.ts:

import { registerCrudHook } from "./factory";

registerCrudHook(
  { model: "contact", op: "createOne" },
  {
    before: async (ctx) => {
      // Validate or enrich params
      return ctx.params;
    },
    after: async (ctx) => {
      // Side-effect after creation
    },
  }
);

Dependency Injection

Services are composed in layers.ts using Effect-TS:

export const CrudServiceLive = Layer.provide(
  CrudService.of({ ... }),
  [CrudRepositoryLive, CrudHookServiceLive, MetricsServiceLive]
);

Shared Pipeline

CRUD leverages the shared OperationPipeline from features/shared/operation-pipeline.ts, ensuring Dynamic Objects and other features share the same:

  • Observability (metrics, tracing)
  • Lifecycle hooks
  • Error handling
  • Retry logic

On this page