Skip to content

Request Lifecycle

What happens when a client calls a REST endpoint on dichit-backend, end to end.

Sequence

sequenceDiagram
    autonumber
    participant C as Client
    participant F as Fastify
    participant P as Plugins
    participant R as Route/Controller
    participant UC as Use case
    participant RPO as Repository (infra)
    participant DB as PostgreSQL

    C->>F: HTTP request
    F->>P: shared + infrastructure plugins
    P->>P: security (helmet), CORS, correlation id, request logging, auth
    F->>R: route matched + JSON-schema validation (body/query/params)
    alt validation fails
        R-->>C: 400/422 error response
    end
    R->>UC: controller calls use case (thin)
    UC->>UC: business rules, authz checks, UnitOfWork when needed
    UC->>RPO: repository interface
    RPO->>DB: Prisma / raw SQL
    DB-->>RPO: rows
    RPO-->>UC: mapped result
    UC-->>R: result
    R-->>C: HTTP response (BigInt serialized to string)

Stage details

1. Boot & env

server.tsinit.ts loads the env file for NODE_ENV and initializes Sentry before the app is built (see overview.md).

2. Plugins (ordered)

Plugins in src/infrastructure/plugins are autoloaded in numeric order:

00-websocket    01-security     02-correlation-id   03-error-handler
04-cors         05-route-not-found-handler         06-auth
07-cookie       08-sentry       09-raw-body         10-request-logging
  • 01-security — Helmet headers.
  • 02-correlation-id — request/correlation id used by logs.
  • 03-error-handler — maps typed errors to HTTP responses (see development/error-handling).
  • 04-cors — allowed origins from config.
  • 06-auth — JWT strategy/hooks (see development/authentication).
  • 10-request-logging — structured pino logging with the request id.

3. Route validation

Every route declares a JSON schema (built with @fastify/type-provider-json-schema-to-ts and/or Zod). Fastify validates body, querystring, params, and headers; a failed validation short-circuits to an error response (see development/validation).

4. Thin controller → use case

Controllers validate input, delegate to an application use case, and format the response. Business rules live in use cases, never in the controller.

5. Data access

Use cases go through repository interfaces. Repositories live under src/infrastructure/db/postgres/repositories. Multi-step writes use the UnitOfWork transaction pattern (see database/optimization).

6. Response

Responses are serialized with bigint: 'string', so BigInt column values are returned as JSON strings. Errors are handled centrally and never leak stack traces (see development/error-handling).

Lifecycle for background work

Heavy or asynchronous work is offloaded to BullMQ queue processors rather than done inline (see event-driven.md):

flowchart LR
    R["Request handler"] -->|enqueue| Q["BullMQ (Redis)"]
    Q --> W["Queue worker"]
    W --> S["S3 / FCM / mail / SMS"]