ServerCRUD
Architecture
Execution pipeline, layer composition, and request flow in the CRUD engine.
Request Flow
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 operationrunAfterSuccessHooks: Side-effects after successful writerunAfterFailureHooks: 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
- Dynamic delegate selection:
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