Appearance
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 │
└─────────────────────────────────────────────────────┘| Layer | Responsibility |
|---|---|
| Routes | The HTTP surface. Paths, methods, request and response models are generated from the platform schema, so the OpenAPI document and the server never disagree. |
| Authentication | Establishes 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. |
| Authorization | Each endpoint declares the scopes it requires. The caller's role must grant at least one of them before the controller runs. |
| Validation | Request bodies and query parameters are validated against the generated models. Invalid input never reaches business logic. |
| Controllers | Translate HTTP into service calls and back. They contain no business rules. |
| Services | The business layer: folder configuration resolution, revision rules, schedule and slot rules, permission resolution, vault references, event creation. Each operation runs in one database transaction. |
| Repositories | Typed data access with a shared query engine that implements filtering, sorting, pagination and soft-delete rules uniformly for every collection. |
| ORM | Model classes generated from the schema over PostgreSQL. Questionnaire definitions, answers, configuration and workflow graphs are stored as JSONB. |
Request lifecycle
- 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.
- 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.
- Account checks. Session tokens are checked against account status and pending obligations such as an unfinished multi-factor challenge or a forced password change.
- 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.
- 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.
- 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.
- 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.
- 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
| Component | Runs |
|---|---|
| API server | One or more replicas in the instance's namespace. |
| Database migrations | Before the server starts serving, as an initialisation step of the same deployment. |
| Seeding and plugin registration | Also initialisation steps, so a fresh instance is usable on first start. |
| Scheduler | Inside the API process, with one elected leader. |
| Plugins | In-process, discovered from the packages installed in the server image. |
See Deploying an Instance for the deployment model.