Production adoption
Ownership, approved composition, durability, contract evolution, migration, and release gates for a Fabric application.
Production adoption is a sequence of proofs. Installing packages is only the first step.
Ownership stays explicit
| Concern | Owner |
|---|---|
| Governed action, event, policy, state-machine, adapter, and projection contracts | Fabric Platform |
| Durable invocation, recovery, idempotency, approval, and event ledger | Platform Host |
| Authorized replay, snapshots, freshness, and read evidence | ProjectionHost |
| Business vocabulary, domain transactions, module composition, and providers | The application |
| Experience documents, signed promotion, scoped render plans, and Host routing | Fabric experience-tier packages configured by the application |
| SaaS shell, authentication UI, organizations, billing, navigation, and deployment | The Supastarter-derived application shell |
| Family tokens and visual primitives | @fabricorg/ui |
| Product-domain components and brand mapping | The application |
| Durable cross-action orchestration | Temporal |
Platform does not ship a business capability catalog, application shell, authentication system, database operations model, provider credentials, or a replacement design system.
Build one immutable composition
- Author each
FabricModuleand export its manifest. - Compile each published module independently. Put that compiler digest and package version on the module registered at runtime.
- Generate and review usage contracts.
- Bind shared capability roles and intents to application-owned component packs.
- Resolve an Assembly v2 lockfile. Its digest covers exact capabilities, generated contract documents, component-pack artifacts, and adoption bindings. Federated packs also lock their remote entry, subresource integrity, and exposed modules.
- Validate and promote experience releases against that lockfile and explicit view and intent grants. Enumerate every selectable document variant and use fragment grants when a subtree needs narrower access.
- Start Platform Host with the approved lockfile. Host compares the actual registered modules with the lockfile before accepting submissions.
- Promote exact routes and effective fragment grants with
@fabricorg/sdui-composer. The server runtime verifies the signed release and issues a scoped render plan. - Put
@fabricorg/experience-gatewaybehind the authenticated application boundary. Never expose either Host to browser code.
The
examples/governed-portfolio
implements this sequence for two materially different applications.
Add the integration files to an existing Supastarter-derived application:
fabric-gen init experience portfolio --directory apps/saas/modules/portfolioThis creates only Fabric integration files. It does not create or replace the shell, authentication, organizations, billing, routes, or navigation.
Client checks are not authorization
A browser is controlled by its user. It can skip a local digest check, modify JavaScript, or call the gateway without rendering the document. Client checks remain useful because they catch stale caches, CDN corruption, incompatible packs, and bad deployments.
Security comes from the server path:
- The server runtime admits a signed release and stores the trusted plan state.
- The browser submits
(planId, fragmentId, eventName)or a named read binding, never an action ID or capability reference. - The gateway resolves that handle against server-held grants and derives actor and scope through
IdentityPort. - ProjectionHost authorizes every read. PlatformHost independently authorizes every mutation at its configured governing moment.
Check before deployment
Create fabric.application.json beside the resolved build artifacts:
{
"formatVersion": 1,
"assembly": "./fabric.assembly.lock.json",
"runtimeCapabilities": "./fabric.runtime.json",
"releases": ["./releases/web.json"]
}Then run:
fabric-gen check-application --config fabric.application.jsonThe check fails on lockfile tampering; missing, extra, duplicate, version- or digest-mismatched runtime modules; malformed promoted releases; release digest drift; or a release bound to another assembly.
This is a deployment gate, not runtime discovery. The runtime-capability file must come from the same application composition root that builds the explicit module registry.
Use the production storage profile
Use PostgresPlatformHostStore and the PostgreSQL ProjectionHost adapters with
PostgreSQL 16 or a compatible Lakebase client. Run ensureSchema() through a
controlled migration step.
If a handler writes application tables, provide a
PostgresPlatformHostTransactionProvider<TDb> that binds the application
database client and Host ledger to the same database transaction. Without that
provider, do not claim atomic domain writes plus event/outbox persistence.
Memory stores are for deterministic tests and explicit local development.
Trust identity only at the server seam
Use IdentityPort at the gateway to turn a presented OAuth2/OIDC credential
into verified ActorClaims. Then derive actor, tenant, space, roles, and
entitlements from authenticated server context. Do not accept them as
authoritative action or projection parameters.
External APIs, agents, Temporal activities, webhooks, support tools, and
recovery workers all submit through the same Host.
import { actorContextFromClaims } from "@fabricorg/ports";
const claims = await identity.verify(credential);
if (!claims) throw new Error("unauthenticated");
const actor = actorContextFromClaims(claims, { tenantId, spaceId });actorContextFromClaims rejects expired, not-yet-valid, malformed,
cross-tenant, and out-of-space claims before they reach Host submission or
projection authorization. Run identityPortChecks() against every identity
adapter.
Redact sensitive parameters before durable invocation creation. Store secrets in tenant-bound encrypted storage and submit opaque references.
Evolve contracts deliberately
Treat action schemas, event envelopes, view shapes, usage contracts, assembly documents, and durable invocation records as public contracts.
- Add optional fields when possible.
- A required field, removal, type narrowing, lifecycle semantic change, or changed event truth requires compatibility analysis and normally a major package release.
- Increase an event schema version when its wire shape changes.
- Keep consumers able to read every event version listed in
ViewContract.consumes. - Upcast old events at the consumer seam before applying the current reducer. Never rewrite the historical event ledger.
- Use
compatibleSnapshotVersionsandupgradeSnapshotfor compatible projection snapshots. Cold-rebuild snapshots that are not declared compatible. - Regenerate contracts and resolve a new assembly. An old assembly digest must never silently identify new artifacts.
Run compiler compatibility classification and generated conformance suites in CI. Pack changed packages and test clean ESM and CommonJS consumers before release.
Migrate Host 5 to Host 6
Host 6 requires explicit recovery fencing on custom durable stores and adds optional verified composition.
- Install a compatible
@fabricorg/assemblypeer. - Implement lease renewal, monotonic claim tokens, and fenced writes on custom stores and dispatchers.
- Run Host schema migrations before starting new workers.
- Set
versionand compilermanifestDigeston every registered module. - Pass the approved lockfile as
composition.assembly. - Resolve the initiating promoted release digest from trusted gateway or release-registry context, never from action parameters.
See the packaged
MIGRATION-6-PRODUCTION.md
for the exact interface changes.
Certify and roll out
Before cutover:
- run unit, lifecycle, recovery, conformance, family-boundary, and clean-package consumer tests;
- run PostgreSQL migration, concurrency, failover, backup, and restore tests in the target environment;
- run Temporal integration tests if workflows are present;
- verify policy deny/outage, tenant isolation, redaction, adapter failure, idempotent replay, and recovery;
- retain the previous package set, assembly, promoted releases, and database rollback procedure.
Roll back code and release selection together. Never point an old runtime at a new assembly unless the compatibility matrix explicitly certifies that pair.