← Atlas Journey · Docs

Frozen document. Dates and status refer to its original source. Private resources and unreviewed images are unavailable.


status: accepted


Use tRPC between React and the SDUI BFF

On September 30, 2026, the owner selected tRPC between the React frontend and Atlas's server-driven UI BFF. Use tRPC over same-origin HTTPS on Fastify for the SPA's experience queries and mutations. This amends the browser REST choice in ADR 0008, the browser clause in ADR 0012, and the Experience Layer contract. The private gRPC decision remains accepted for suitable backend adapters.

The alternative is retaining REST/OpenAPI for every SPA experience call. tRPC gives the TypeScript React client inferred procedure input/output types and catches incompatible client/server changes during the build. It also couples those builds to a shared contract and uses its own RPC/error envelopes. Type inference is not runtime validation or authorization. Existing REST routes remain compatibility endpoints during incremental migration; raw OpenAPI is not the source of the tRPC client contract.

Content, schemas and workflow ownership

Retain ADR 0004. Contentful authors fields, layout, copy, supported conditions and declarative validation in pinned en-US/es-US releases. Camunda supplies the authorized workflow/task state and logical screen reference. The BFF joins that state with the release and permitted owner data. React renders the resulting SDUI model.

Retain ADR 0011. TypeBox describes reviewed procedure envelopes, response projections and the supported definition vocabulary. A compatible tRPC parser adapter must validate these schemas at runtime without coercion, defaults, unknown-field removal or mutation of retry payloads. Fastify's route validator does not automatically validate nested tRPC procedure input. Validate both procedure input and authorized output explicitly. CMS-authored field constraints remain with the constrained release evaluator, not duplicated in TypeBox or hard-coded React forms. Never compile arbitrary CMS scripts or schemas.

Export the router's type through a browser-safe contract entry point and use type-only imports in the SPA. No database, session, OIDC, Camunda or secret-bearing backend module may enter the browser bundle. Pin compatible tRPC server/client packages and verify Fastify, TypeBox and TypeScript compatibility before enabling a slice.

Session and command safeguards

Retain ADR 0009. Resolve the opaque cookie and current business context server-side for every request. Do not accept a client-supplied subject, employer, role or context as authority. Queries return only authorized projections and use Cache-Control: no-store. Mutations require POST, the exact allowed Origin and the current session-bound CSRF token before any effect. Authentication, field non-disclosure and owner authorization remain required before record-specific results are returned.

Start with individual requests, batching disabled and no automatic mutation retries. Bound HTTP input, procedure arrays/strings and response sizes. Keep business revision checks, immutable release identity, idempotency keys, durable acceptance, operation polling and uncertain-effect reconciliation from ADR 0005. A tRPC mutation can accept durable work; it must not wait for Camunda completion or treat an RPC retry as a new business command.

Use a reviewed error formatter with stable Atlas error codes and safe field errors. Map authentication, not-found, validation, conflict and dependency errors explicitly into tRPC codes. Do not serialize raw exceptions, database errors, stack traces or private records. The SPA must handle tRPC's error envelope deliberately; its HTTP status alone does not preserve the previous REST response contract.

OIDC redirects, session bootstrap/logout, health probes and authorized binary upload/download stay dedicated HTTPS endpoints. These protocol and streaming exceptions do not replace tRPC for SDUI experience calls. REST remains appropriate for system APIs, external consumers and compatibility paths; OpenAPI continues to describe those REST paths. Browser gRPC-Web is not selected.

Migration and evidence

Adopt tRPC for new SPA-to-SDUI BFF experience work. Migrate existing behavior as tracer bullets, beginning with pinned draft list/read/create/save. Both transports invoke the same owner functions. Keep legacy routes until existing consumers and tests are accounted for, and make each frontend migration explicit. No REST proxy or second rules/workflow implementation is introduced behind tRPC.

Use TDD at the existing public BFF/HTTPS seam. Cover cookie authentication, cross-context denial, mutation Origin/CSRF, GET mutation rejection, batching rejection, structural validation, response redaction, pinned bilingual rules and stale revisions. Qualify the same browser journey against real Keycloak, PostgreSQL, Camunda and pinned Contentful content at convergence. Changing the transport alone does not certify a journey. See the tRPC boundary design for rollout and current standing.

Primary references checked September 30, 2026: tRPC Fastify adapter, input/output validators including TypeBox, HTTP client link, and error formatting.