Decisions and roadmap
ADR 0003: Convex-first EXO control plane
- Status: accepted
- Date: 2026-09-14
- Historical work reference: IV-173 (retired)
- Supersedes: ADR 0001
Decision
EXO is the application platform and control plane. It owns projects, organizations and access, environments, provider provisioning, deploy/release/rollback state, runtime-dependency metadata, policy and security controls, audit evidence, orchestration, health, and bounded usage and cost aggregates.
Convex is the default persistence, transaction, function, and reactive-state layer for every state EXO owns. An exception requires a concrete workload constraint, a named authority, reconciliation and rollback rules, and an exit path. An inherited Payload or PostgreSQL implementation is not a constraint.
Construct owns Page and website editing, Puck, publishing, Page authorization, and authenticated Surfaces such as Interspace/ION. Construct persists those records against its own Convex-native model. Payload is not moved into Construct by default; a future external-CMS adapter requires a demonstrated integration need and remains optional rather than authoritative.
Independent Apps own their domain records. EXO provisions and observes their resources and accepts only bounded operational observations. It does not centralize their prompts, content, user data, scientific datasets, financial ledgers, or other domain records.
Legacy freeze
Payload, PostgreSQL, and Puck in this repository are migration sources and rollback material only.
No new EXO capability may add a Payload collection, Payload/Puck dependency, or Puck implementation
file. pnpm check:legacy-backend-freeze enforces the checked-in baseline. Removing items from that
baseline is allowed; extending it requires changing this ADR and explicit architecture review.
Bug fixes needed to export, reconcile, secure, or retire the legacy path are allowed when they do not increase its product scope. The normal approval gates still apply to data writes, provider changes, Release Candidate, Production, domains, billing, and resource deletion.
Authority rules
The collection-by-collection disposition is maintained in the EXO legacy authority and migration map. A record has exactly one authority during every cutover phase:
- External providers remain authoritative for live deployment, billing, source, and health facts.
- EXO owns portfolio and release coordination; Entire owns source and execution provenance.
- Clerk authenticates identities; EXO Convex owns resource grants and authorization state.
- EXO Convex owns control-plane intent, orchestration state, bounded observations, and audit evidence.
- Construct Convex owns Pages, content, revisions, Puck documents, publishing, and Page/Surface access.
- Independent Apps own domain data and expose only versioned contracts and bounded observations to EXO.
SQL, analytical index, and object-storage exceptions
SQL is not retained merely because a legacy schema exists. A SQL exception must identify a workload Convex cannot reasonably satisfy, such as a required external protocol or specialized query shape, and must document synchronization and failure behavior. No current EXO control-plane collection has such an approved exception.
Large binary objects do not belong in Convex documents. Blob bytes may stay in Convex file storage or an external object store when size, transformation, retention, egress, or interoperability requirements justify it. Convex remains authoritative for ownership, checksum, metadata, lifecycle, and the opaque object reference.
Specialized analytical or search indexes may remain external when their workload requires them. They are derived and rebuildable, never the sole authority. EXO stores only bounded aggregate state and freshness/reconciliation evidence.
Cutover shape
The migration is staged and reversible:
- freeze the legacy feature surface and inventory every record family;
- widen Convex schemas, validators, indexes, auth checks, receipts, and bounded audit logs;
- export deterministic, secret-free, versioned source bundles with counts and hashes;
- dry-run transforms and reconcile identifiers, relationships, constraints, and totals;
- import through idempotent receipts into isolated Staging after the normal data-write approval;
- shadow-compare reads without making two systems authoritative;
- cut Staging reads and writes to Convex, then prove auth, isolation, index, idempotency, audit, retention, rollback, and recovery parity;
- separately approve any Production migration and retain the frozen source for the rollback window;
- remove EXO Payload, PostgreSQL, and Puck code and dependencies; then retire provider resources only through their explicit approval gates.
Rollback restores the last single authority and replays only receipt-backed operations. Ad hoc dual writes are prohibited.