Skip to content

Architecture & Request Lifecycle ​

The API server is a layered application. Each layer has one job, and a request passes through them in a fixed order. Knowing the order explains most of the server's behaviour: where a request can be rejected, where validation happens, and when side effects such as events become visible.

Layers ​

   HTTPS client (web app, mobile app, integration, plugin)
          │
   ┌──────▼──────────────────────────────────────────────┐
   │ Gateway            TLS termination, routing          │
   └──────┬──────────────────────────────────────────────┘
   ┌──────▼──────────────────────────────────────────────┐
   │ Routes             generated from the API contract   │
   │ Authentication     user · API key · device           │
   │ Authorization      required scopes per endpoint      │
   │ Validation         request models from the schema    │
   └──────┬──────────────────────────────────────────────┘
   ┌──────▼──────────────────────────────────────────────┐
   │ Controllers        one per resource, thin            │
   └──────┬──────────────────────────────────────────────┘
   ┌──────▼──────────────────────────────────────────────┐
   │ Services           business rules, transactions      │
   │                    events written with the change    │
   └──────┬──────────────────────────────────────────────┘
   ┌──────▼──────────────────────────────────────────────┐
   │ Repositories       query building, filtering, paging │
   └──────┬──────────────────────────────────────────────┘
   ┌──────▼──────────────────────────────────────────────┐
   │ ORM · PostgreSQL   generated models, JSONB payloads  │
   └─────────────────────────────────────────────────────┘
LayerResponsibility
RoutesThe HTTP surface. Paths, methods, request and response models are generated from the platform schema, so the OpenAPI document and the server never disagree.
AuthenticationEstablishes who is calling: a signed-in user, an API key or a paired patient device. Anonymous access exists only for endpoints that explicitly allow it.
AuthorizationEach endpoint declares the scopes it requires. The caller's role must grant at least one of them before the controller runs.
ValidationRequest bodies and query parameters are validated against the generated models. Invalid input never reaches business logic.
ControllersTranslate HTTP into service calls and back. They contain no business rules.
ServicesThe business layer: folder configuration resolution, revision rules, schedule and slot rules, permission resolution, vault references, event creation. Each operation runs in one database transaction.
RepositoriesTyped data access with a shared query engine that implements filtering, sorting, pagination and soft-delete rules uniformly for every collection.
ORMModel classes generated from the schema over PostgreSQL. Questionnaire definitions, answers, configuration and workflow graphs are stored as JSONB.

Request lifecycle ​

  1. Transport. The gateway in front of the instance terminates TLS and routes the request to the API server. The server itself only speaks to the gateway.
  2. Authentication. The request is resolved to a principal: a user session token, an API key or a device token. Requests that carry nothing usable stop here unless the endpoint allows anonymous access.
  3. Account checks. Session tokens are checked against account status and pending obligations such as an unfinished multi-factor challenge or a forced password change.
  4. Authorization. The endpoint's required scopes are compared with the scopes granted by the caller's roles. For content, folder and questionnaire permissions are checked in the service layer as a second gate.
  5. Validation. The body and query parameters are parsed into the generated request models. Unknown fields, wrong types and unsupported filter operators are rejected with a structured error.
  6. Service call. The controller invokes one service operation. The service opens a unit of work, applies the rules, and writes data and any resulting event in the same transaction.
  7. Response. The result is serialised into the generated response model. Errors raised anywhere in the pipeline are converted into the standard error envelope described in API Design.
  8. After the response. Events committed in step 6 are picked up by the background delivery jobs and reach workflows, subscriptions and webhooks. See Events & Delivery.

Schema-driven contract ​

The platform has a single schema that defines every entity, its fields and its API operations. From that schema the following are generated in the same release: the request and response models, the ORM models and migrations, the OpenAPI document, and the typed clients used by the web and mobile apps. Hand-written code in the server is limited to the layers below the routes, which keeps the contract stable and verifiable. See Data Model.

Error handling ​

Business errors are typed: not found, validation, conflict, permission denied, unauthorized and upstream unavailable. Each maps to a fixed HTTP status and a stable error code, and carries only details that are safe to show to a caller. Unexpected failures are logged with a correlation to the request and returned as a generic server error without internal information.

Stateless service, single scheduler ​

API processes hold no session state, so an instance can run several replicas behind the gateway and scale horizontally. Background work is different: exactly one process at a time acts as the scheduler leader. Leadership is taken through a database-level lock, so it moves automatically when the leading process stops. See Background Jobs.

Where things run ​

ComponentRuns
API serverOne or more replicas in the instance's namespace.
Database migrationsBefore the server starts serving, as an initialisation step of the same deployment.
Seeding and plugin registrationAlso initialisation steps, so a fresh instance is usable on first start.
SchedulerInside the API process, with one elected leader.
PluginsIn-process, discovered from the packages installed in the server image.

See Deploying an Instance for the deployment model.