Skip to content
ImplementedFor engineers, validation reviewers, auditors asking "why is it built this way"

Architecture decisions (ADRs)

Last updated Oct 21, 2026

An architecture decision record is a short, dated statement of a significant decision, why it was taken and what it costs. The records are append-only: a decision is revised by a new record that supersedes the old one, never by editing it. They are written in the repository (server/docs/adr), they are the design the code follows, and the pages of this library say what the code actually does. Where a record and the code differ, the code is right and the record is a finding.

The schema was re-authored before launch as one migration per table, so the records still name the files of the earlier history; server/docs/adr/MIGRATION-MAP.md says where each one's effect lives now (The database).

The records

ADRDecisionStatus in the recordWhere it shows
ADR 0001 Architecture foundations (2026-05-24)Layered clean architecture; modular by capability in two scopes (platform and study); PostgreSQL with SQL-only migrations; strict TypeScript, zod at the boundary; Express; pino logs; two processes (API and worker). Decision 10 (a database for each tenant) is superseded by ADR 0002AcceptedArchitecture
ADR 0002 Pooled multi-tenancy (2026-09-03)One database for many organizations, isolated by row-level security on org_id; the connection setting is the only source of tenant identity; an unbound connection sees nothing; the runtime role is never the ownerAcceptedData and tenancy
ADR 0003 Role revisions and guardrails (2026-09-30)A role changes only by appending a revision with a reason; hard guardrails nobody can override and soft warnings an administrator accepts with a recorded reasonAcceptedManage organization roles
ADR 0004 Persons and organization memberships (2026-09-30)A person is one global login; a membership gives that person a place in an organization; the same person can belong to several, and an organization always keeps an administrator who can actAcceptedInvite and manage members
ADR 0005 Study and site memberships, and the separation rule (2026-09-30)A membership holds the role and is the only grant for its scope; one role per person per study; the separation rules (an Organization Admin holds no study role, members are never site staff) are database constraintsAcceptedStaff a study team, Who can and cannot
ADR 0006 The site delegation log (2026-10-01)Site staff access follows a log of dated entries, each signed by the principal investigator; the database refuses a wrong signerAcceptedStaff a site
ADR 0007 Scoped access exceptions (2026-10-01)One permission added to or removed from one grant, with a reason, an expiry of at most 90 days and a second approver for elevated or critical permissionsAcceptedReview organization access and audit
ADR 0008 One central authorization decision (2026-10-01)An access profile is resolved for each request, cached by an organization-wide access revision; one pure function decides; every route declares its accessAcceptedWho can and cannot
ADR 0009 One scope for every list (2026-10-01)A person's scope (which sites) is computed in one place and applied in one SQL implementation; a count is a list; absent means unconfined, empty means nothingAcceptedArchitecture
ADR 0010 Ending a membership ends what rests on it (2026-10-01)Removing a person ends their team memberships, grants and sessions in the same transaction; it is finalAcceptedInvite and manage members
ADR 0011 Row-level security on identity and audit tables (2026-10-01)Every identity and audit table is isolated by the tenant setting; pre-sign-in reads go through narrow security-definer functions; a write that matches no visible row is an errorAcceptedThe database
ADR 0012 Study versions, draft revisions, snapshots, UAT cycles (2026-10-01)A study's design is versioned as one unit; submitting freezes it into a hashed snapshot; UAT cycles are numbered per version; three sign-offs bind to the passed cycle's snapshot; the read-only rules are in the databaseAcceptedEnvironments and versioning, Review and release a study
ADR 0013 Study operational state, the workspace carried by the session, and the configuration cache (2026-10-01)One state machine for a study (Setup to Archived) with write intents; the two-person lock bound to e-signatures; the workspace comes from the session's access profile; the runtime reads the version's snapshotAcceptedChange the state of a study, Environments and versioning
ADR 0014 Study level and the three areas (2026-10-02)A study is worked at the study level and in Build, UAT and Live; where every module goes; UAT issues and resultsAcceptedFinding your way around
ADR 0015 Clinical data: items, events, contacts and the logs (2026-10-02)Values are an append-only chain, one row for each value ever entered; checks and derived values run on the server; events and contacts have their own records; the AE and SAE logs are read modelsAcceptedEnter visit data, Record an adverse event
ADR 0016 Consent, change impact, safety trail, signatures, exports and check severity (2026-10-04)Re-consent is a row and the latest counts; a change has a computed impact and a breaking change is refused; follow-up, review and reconciliation are append-only; visit and casebook signatures; the severity of each checkAcceptedAmend a live study, Review and reconcile a serious adverse event
ADR 0017 Per-chain audit with anchoring, summary tables, streaming exports, partitioning and a load test (2026-10-04)The audit ledger is chained per chain key, partitioned by month and anchored daily in write-once storage; dashboards read summary tables; exports stream with formula-injection protection; a load-test harnessAcceptedArchitecture, Testing and quality
ADR 0018 Onboarding (2026-10-05)Provisioning with an invitation; a durable mail outbox with delivery status; the roles wizard and its AI assistant; the team invitation wizard; atomic study creationAccepted (2026-10-21); builtSet up your organization
ADR 0019 A session without a workspace (2026-10-06)A session may carry no workspace; every route declares its kind (none, named, required); a workspace is entered, with a version, by a new sessionAccepted (2026-10-21); builtFinding your way around
ADR 0020 Blinding and the investigational product (2026-10-12)A design for products, arms, blinding levels, an unblinded permission and emergency unblindingProposed; not builtNot built yet

The status column is what each record says. ADR 0018 and 0019 were Proposed when the work began and were moved to Accepted by the product owner on 21 October 2026; ADR 0020 stays Proposed until blinding is built.

How to read a record

Each follows one template: Context (what was wrong or missing), Decision (numbered, so other pages can cite "ADR 0017, decision 9"), Consequences (what gets better and what it costs) and Alternatives considered. The long records (0012 to 0019) end with amendments dated when a decision was refined during building; the amendment, not the first text, is the latest word. "Needs the product owner" sections list the choices the owner made, so the owner's decision is on the record next to the recommendation.

Decisions worth knowing before you qualify the system

  • The audit ledger is outside the application's reach (ADR 0011, 0017): the runtime database role can read and append and nothing else, the chain is verified on a schedule and anchored daily, and production refuses to start unless that holds.
  • The design is sealed, not edited (ADR 0012): what was tested is what was signed is what runs.
  • A saved value is never overwritten (ADR 0015): every value is a row in a chain, and a signature on a record is withdrawn visibly by an authorized change.
  • Tenant isolation is a database control, not an application filter (ADR 0002, 0011).

Architecture · Data and tenancy · The database · Environments and versioning · Testing and quality