Selegic CRM Docs
ServerCRUD

Services

Effect-TS service implementations for the CRUD engine.

CrudService

Main entry point in services/crud.service.ts.

export class CrudService extends Context.Tag("CrudService") {
  static readonly execute = ...
}

Interface

interface CrudService {
  execute<T>(
    model: string,
    op: CrudOperation,
    params: unknown,
    context: CrudContext
  ): Effect<never, CrudError, T>;
}

Responsibilities

  • Orchestrates the Operation Pipeline
  • Provides high-level API for other features
  • Does not perform DB work directly

CrudRepository

Database wrapper in services/crud-repository.service.ts.

// Dynamic delegate selection
const delegate = prisma[model];
return yield* withDbRetry(model, op, Effect.tryPromise({
  try: () => delegate[op](params),
  catch: (e) => new Error(String(e))
}));

Features

  • Uses PrismaTag to access global Prisma client
  • Dynamic model/delegate selection
  • Retry logic via withDbRetry
  • Error mapping to CrudError

CrudHookService

Hook executor in services/crud-hook.service.ts.

Responsibilities

  • Resolves hooks from the crudHooks registry
  • Executes runBeforeHooks to modify params
  • Executes runAfterSuccessHooks for side-effects
  • Uses shared hook-executor.ts utility

Hook Context

interface HookContext {
  model: string;
  op: string;
  params: unknown;
  result?: unknown;
  context: {
    org: string;
    user: User;
    session: Session;
  };
}

OperationHandlerService

Orchestrates validation, hooks, and repository execution in services/operation-handler.service.ts.

Flow

  1. Validate input against Zod schema
  2. Execute before hooks
  3. Call repository
  4. Execute after hooks (on success)
  5. Return result

Dependency Injection

All services are composed in layers.ts:

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

To use CRUD in an Effect program:

Effect.provide(CrudServiceLive)

On this page