Complied — Requirements (Source of Truth)
Status: locked decisions · Date: 2026-08-20 · Last amended: 2026-09-02 (D21)
This file is the source of truth for product decisions (D1–D21), vocabulary, capability-parity principle, tenancy, and the agency/program abstraction. Where this document and any other file disagree on intent, this document wins.
It is not the source of truth for what shipped. Architecture of the running app:
docs/domain/. Honest walk-through status and the ranked next-fix list:docs/LIFECYCLE_ASSESSMENT.md§8. Rebuild change log:docs/history/CHANGE-LOG.md.⚠️ Section numbering is load-bearing and deliberately irregular. Over 100 comments in
src/,domain/,supabase/migrations/andsupabase/functions/cite this file asREQUIREMENTS §n.m. §5's subsections are numbered4.xand §6's are numbered5.x— a historical drift that the citations now depend on, so it is kept on purpose. Renumbering them to "tidy up" would silently break ~59 citations. Add new subsections at the end of a section; never renumber an existing one.The HPD rulebook domain content (
docs/RULEBOOK.md,docs/HPD_SYSTEM_MODEL.md,domain/src/programs/nyc-lead-paint/) is hard-won domain truth, ported forward faithfully. The code twin lives indomain/, notsrc/lib/hpd/(that path isarchive/).
1. What Complied is
Complied is a multi-tenant, white-label lead-paint compliance platform. Complied (the company) is the platform operator; each customer organization — SecureEnv, Abated, and future ones — is a tenant running its own white-labeled instance: branding, clients, buildings, projects, staff. For a tenant, the product watches agency data for compliance events, surfaces what needs doing, runs the work (schedule and field-capture it — XRF, dust wipe, paint chip, abatement), produces the paperwork, and proves it with a defensible, auditable record.
2. Decisions locked
These are settled. Do not relitigate them without an explicit change to this file.
| # | Decision | Choice |
|---|---|---|
| D1 | Database | Fresh schema in a new Supabase project. One clean, consolidated migration set designed around tenancy from line one. The 215 existing migrations are archived, not carried forward. |
| D2 | Frontend | Keep React + Vite + TypeScript + shadcn-ui. Rebuild the UI against the new schema. Salvage genuinely good logic (HPD rulebook, XRF engine, report renderer); rewrite the pages. |
| D3 | Tenant isolation | Shared tables + tenant_id + Postgres RLS. Every tenant-owned row carries tenant_id; isolation is enforced in the database, not the client. |
| D4 | Cross-tenant work | Per-project collaborator invitation. The owning tenant explicitly invites another tenant onto one specific project with a scoped role. Projects are the only cross-tenant surface. |
| D5 | Identity | One user belongs to exactly one tenant. Clients (building owners / managing agents) log into a separate white-label portal as a distinct account type. Complied platform operators sit above all tenants. |
| D6 | Abstraction axis | Agency and compliance program, within NYC. The core is neutral across NYC agencies (HPD, DOB, DOHMH, FDNY, ECB/OATH, DOF, DEP). v1 ships exactly one program: NYC Lead Paint, owned by HPD with DOHMH participating. Region/jurisdiction is a second, outer axis reserved for later. See §8. |
| D7 | Customer hierarchy | Tenant → Client → Building → Unit → Project. |
| D8 | Service & phase definition | Defined in code, not in the database. No admin workflow studio in v1. |
| D9 | Billing | None in v1. Every tenant is unlimited. No plans, no entitlements, no Stripe. |
| D10 | Buildings | Citywide public reference registry + a tenant-scoped tracking layer. One row per real building, shared; tenant relationships recorded separately. |
| D11 | The firms concept | Removed entirely. There are no firms inside a tenant. firms, firm_settings, firm_licenses, firm_documents and every firm_id column are deleted. |
| D12 | Git history | Reset. The repo starts fresh; the old history remains on the GitHub remote for reference. |
| D13 | Capability parity | Nothing the system does today may be lost. The rebuild changes architecture, vocabulary, and structure — never capability. Every existing behavior is inventoried and carried forward or consciously retired with written sign-off. See §4. |
| D14 | Vocabulary | tenant = the white-label organization, always. The resident is an occupant. |
| D15 | Backend | Supabase-only for the MVP. No separate API service in v1. Browser → PostgREST/RPC stays, with RLS as the enforcement layer. A NestJS service is the known next step, triggered by the first external (non-internal) tenant onboarding — see §10.1. The seams that make that migration cheap are mandatory in v1, not optional. |
| D16 | White-label routing | Subdomain per tenant in v1 — e.g. secureenv.complied.com, abated.complied.com. Custom domains deferred. |
| D17 | Production data cutover | Re-derive all public/reference data from agency feeds at cutover (buildings, units, public_events, PLUTO, etc.). Migrate tenant-authored data only (clients, projects, documents, invoices, XRF history, profiles). Live production migration is gated on explicit owner approval when ready. |
| D18 | Inspector tenancy | One inspector, one tenant. An inspector profile belongs to exactly one tenant and never works across two. D5 stands; no multi-tenant JWT model. |
| D19 | Agency feeds (v1) | Keep all active agency syncs — they are the compliance-intelligence layer (§9.2). Retire confirmed-dead code only (sync-doh-data, sync-fdny-data, W7 backfills). One orchestrator; feeds write only to public_events (no legacy per-agency mirror tables). |
| D20 | Edge function pruning | Confirmed RETIRE functions are deleted from live Supabase, not left deployed. |
| D21 | Phase as capability | Forbidden. Nothing in the app may read projects.phase to decide what a user can do. Phase is a manually-set ops label. Any future check gates an action on data facts, never on the phase value. (Rung 6, owner ruling 2026-08-31; see docs/domain/GATING.md.) |
3. Glossary and vocabulary
The word tenant is overloaded in this domain and it will cause bugs if left ambiguous.
| Term | Meaning in this system |
|---|---|
| Tenant | A white-label customer organization of Complied (SecureEnv, Abated). The unit of data isolation. |
| Occupant | A person living in a residential unit. This is what NYC law calls a "tenant." |
| Client | A customer of a tenant — a property management company or building owner. |
| Platform operator | A Complied employee with cross-tenant access. |
| Building | A physical structure, keyed by BIN, in the citywide registry. |
| Unit | An apartment within a building. |
| Project | A unit of billable compliance work, attached to a unit or directly to a building. |
| Violation | A reactive compliance event: an agency has cited the property. |
| Obligation | A proactive compliance event: a recurring legal duty with a running clock, independent of any citation. |
| Event | Anything landing in public_events from an agency feed — the raw material both violations and obligations are derived from. |
RESOLVED 2026-08-20 (D14).
tenantis reserved exclusively for the white-label organization; the resident is an occupant. The third project origin isoccupant_request;access_status = 'tenant_refused'becomes'occupant_refused'. Any legacy identifier usingtenantto mean resident is renamed — a vocabulary rename, never a behavior change.
4. Capability parity — the governing constraint (D13)
This rebuild is a refactor, not a reduction. The owner's position, stated explicitly:
"I'm not here to break the workflow logic. Whatever it achieves today, I want to achieve the same thing — just in a much more refactored and better manner. Renaming the vocabulary, better architecture, removing redundant stuff. But what it essentially achieves today, I still want to be able to achieve."
4.1 What may change freely
Table names and shapes · column names and types · file and module layout · component structure · vocabulary and labels · the number of tables · how data is stored, indexed, and joined · which layer a rule lives in.
4.2 What may not change without written sign-off
Any observable behavior: a compliance rule's outcome (deadlines, applicability, required documents, signer roles, notarization, order-code behavior); a data feed running today, on the same cadence, producing the same coverage; a document or report the system can generate today; a calculation (pricing, deadlines, XRF pass/fail, exemption status, RPO determination); a workflow a user can complete today, end to end.
4.3 How parity is enforced
- The Capability Inventory is written before anything is deleted — a behavior list (every scheduled job, feed, generated document, calculation, completable workflow), not a table list.
- Every entry is dispositioned:
CARRY,RETIRE(reason + owner sign-off), orUNKNOWN(investigate — never a default). Nothing is dropped on anUNKNOWN. - The inventory is the acceptance checklist. A phase is done when its
CARRYentries work against real data — not when the code compiles. - Rules get fidelity tests. Ported compliance logic must reproduce the old implementation's output case-for-case before the old code is deleted.
4.4 The specific risk to watch
The highest-risk area is the least visible: public-data ingestion — crons writing to tables no page reads directly, failing silently. A table that looks unused is not evidence that it is. No table is dropped until every edge function, cron, trigger, view, and RPC touching it has been traced.
5. Tenancy and access control
4.1 The isolation rule
Every table holding tenant-owned data carries a non-nullable tenant_id uuid references tenants(id). RLS on every such table restricts rows to the caller's tenant, resolved from a
JWT claim.
Three data classes, three policy shapes:
| Class | Examples | Policy |
|---|---|---|
| Public reference | buildings, units, public_events, PLUTO lots, agency lookup tables, HPD order maps | Readable by all authenticated users. Written only by service-role sync jobs. USING (true) is acceptable here and nowhere else. |
| Tenant-owned | clients, projects, inspections, documents, invoices, profiles | tenant_id = current_tenant_id(), plus the project-collaboration exception below. |
| Platform | tenants, platform_operators, impersonation_audit, sync run logs | Platform operators only. |
Hard rules: no tenant-owned table ever gets USING (true); every SECURITY DEFINER function
ships a paired REVOKE EXECUTE ... FROM anon, authenticated in the same migration, granting
only the roles that need it; client-portal users see only rows belonging to their own client,
within their tenant; tenant isolation is proven by an automated cross-tenant leakage test
suite, not by inspection — a v1 deliverable.
4.2 Roles
Scoped to a tenant unless stated otherwise:
| Role | Scope | Capability |
|---|---|---|
platform_operator | Global | Cross-tenant read, tenant provisioning, audited impersonation |
tenant_admin | Tenant | Everything within the tenant, including user and branding management |
project_manager | Tenant | Create and run projects, assign work, approve documents |
inspector | Tenant | Field execution on assigned projects; XRF, samples, photos, notes |
back_office | Tenant | Documents, filing packages, invoicing |
client_user | Client | Read-only portal access to their own buildings, projects, and documents |
Impersonation by a platform operator is time-bounded, reason-required, and written to an append-only audit log that the impersonated tenant can read.
4.3 Cross-tenant collaboration (D4)
The only cross-tenant surface is the project. A project has exactly one owner tenant, which
may create a project_collaborators row inviting another tenant with a scoped role (e.g.
field_execution, lab_coordination, abatement); the collaborator sees only that
project, and within it only the surfaces its scope covers. Financials are never shared —
proposals, rate cards, invoices, and vendor payments stay visible to the owner tenant alone,
regardless of scope. Every collaborator action is attributed to (user_id, acting_tenant_id)
in the audit log. RLS reads: a row is visible if tenant_id = current_tenant_id() OR it
belongs to a project on which the caller's tenant holds an active collaboration grant covering
that surface.
6. Domain model
Table-by-table shape is documented authoritatively in docs/domain/SCHEMA.md; what follows is
the decisions the schema must encode, not a restatement of it.
5.1 Buildings and units (D10)
buildings is a citywide public registry keyed by BIN, seeded/refreshed from PLUTO and
agency feeds, owned by no tenant. units are likewise shared; tenant-specific facts about a
unit are tenant-scoped rows referencing it, never columns on the shared row. tenant_buildings
is the tenant-scoped tracking layer — which buildings a tenant watches/services, which client
they belong to, its own annotations. Two tenants servicing the same building share one building
row and hold two tenant_buildings rows; neither sees the other's.
5.2 public_events — the canonical event table
Every agency feed lands in public_events, the only table the application reads compliance
events from; per-agency tables (dob_violations, hpd_complaints, etc.) were partial legacy
artifacts and do not survive. Normalized status status_norm ∈ {OPEN, CLOSED, DISMISSED}.
Every event must resolve to a building_id — one that can't is quarantined in
unlinked_events with a reason, surfaced on an ops dashboard; silent nulls are a defect.
Ingestion is idempotent, and every sync run is logged with counts, duration, and outcome.
5.3 Obligations
An obligation is a recurring legal duty with a deadline, generated on a schedule against a
building or unit, independent of any citation: annual lead-paint notice, periodic (LL31) unit
inspection, turnover-triggered work, investigation/testing duties, RPO checks, exemption
monitoring visits. The obligation engine takes building/unit facts plus the jurisdiction
rulebook and emits dated obligations with an applicability rationale; where a fact is unknown,
it emits "possibly applicable, verify" rather than silently dropping — applicability.ts
does this correctly today and that behavior is preserved.
6.3 Moved — retained as a citation anchor
Superseded — chain-of-custody / field-gate content that once lived at this number is now under
Projects and v1 scope: see §7.3 (Phases) and §9.3 (Field work). Kept because source comments
cite REQUIREMENTS §6.3; do not delete this heading without repointing them.
7. Projects
projects columns and constraints are documented in docs/domain/SCHEMA.md; the decisions
below are what that schema must hold.
7.1 Origins
A project is created one of three ways; the origin is recorded and immutable. A manually-created project must still declare one of the three.
| Origin | Trigger | Source |
|---|---|---|
violation | An agency cited the property | a public_events row |
obligation | A recurring duty came due | an obligations row |
occupant_request | An occupant asked for an inspection | manual intake |
7.2 Scope
A project attaches to a unit, or — when work isn't apartment-specific (common-area XRF,
building-wide filings) — directly to a building. Exactly one of unit_id /
building_id-only is set; building_id is always populated.
7.3 Phases (D8, amended D21)
The six phase names are kept, hardcoded, identical for every tenant — intake → scheduling → field → docs_qa → billing → closed — plus recoverable side-states (blocked / on-hold /
cancelled), orthogonal to phase (setProjectSideState does not move phase).
D21 supersedes the original gate-engine plan. Rung 6 deleted domain/src/phases/gates.ts
and advance-project-status; setProjectPhase writes the column from the client, nothing
auto-advances, and nothing may branch on phase to enable or disable work. The workspace is
Decide → Work → File → Money, always reachable. Within-phase progress is a sub-state,
not a phase, and billing is decoupled from filing — commercial close does not wait on
agency acceptance. The original per-boundary completeness list (signed proposal, scheduled
visit, captured field data, documents, paid invoice) is a useful ops checklist, not
enforced; candidate action-level warnings are in docs/history/DESIGN-C.md, unshipped.
7.4 Services (D8)
Service types — xrf, dust_wipe, paint_chip, abatement, and combinations — are defined
in TypeScript, not database rows; a service definition declares required documents,
licenses, and field capture contract. Staff don't declare services on a project — they're
derived from linked HPD orders and project_order_decisions (servicesForTracks); there's
no project_services table.
The Admin Workflow Studio is removed from v1, along with workflow_catalogs and every
other workflow_* table.
8. The abstraction axis: agency and program (D6)
The thing that varies in this domain is not primarily the city. It is which agency issues the rule, and which body of rules you are working under. Complied's abstraction is built on that axis first. Region is a second, outer axis we leave room for but do not build in v1.
8.1 The three levels
// 1. Jurisdiction — the legal geography. v1 ships exactly one.
interface Jurisdiction { id: 'nyc'; name: string; agencies: Agency[]; }
// 2. Agency — issues citations, publishes data, receives filings. NYC has many;
// we already ingest from most of them.
interface Agency {
id: 'hpd' | 'dob' | 'dohmh' | 'fdny' | 'ecb_oath' | 'dof' | 'dep' | 'dot' | 'dsny';
name: string;
feeds: FeedDefinition[]; // ingestion
citations: CitationRegistry; // codes and what they mean
filingChannels: FilingChannel[]; // how work files back, if at all
}
// 3. Compliance program — THE unit of abstraction: a body of rules with its own
// citations, deadlines, obligations, documents, services. Usually one agency;
// sometimes several participate.
interface ComplianceProgram {
id: 'nyc-lead-paint';
jurisdiction: 'nyc';
primaryAgency: 'hpd';
participatingAgencies: ['hpd', 'dohmh'];
orderRegistry: OrderRegistry; // citation code -> required behavior
obligationRules: ObligationRule[]; // recurring duties and their clocks
applicability: ApplicabilityEngine; // does this rule apply to this building?
deadlines: DeadlineCalculator;
documents: DocumentRequirementSet; // forms, signers, notarization
services: ServiceDefinition[]; // xrf, dust_wipe, paint_chip, abatement
}
v1 ships exactly one program: nyc-lead-paint — the existing HPD rulebook, ported
faithfully (order codes, deadlines, documents, signer roles, notarization, friction surfaces,
RPO logic, LL31 status, exemption monitoring), plus the DOHMH side of lead (inspections,
poisoning-case response), already touched via doh_inspections/doh_violation.
8.2 Why this split matters — ingestion is agency-wide, workflow is program-scoped
This is already how the system behaves; the rebuild makes it explicit. The product ingests from agencies it has no program for — DOB, ECB/OATH, FDNY, DOF, 311, ACRIS — none of it lead-paint work. Not scope creep: it's the compliance intelligence layer, showing a building's whole risk picture, not just the slice sold against. The two layers are governed differently:
| Layer | Scope | Rule |
|---|---|---|
| Ingestion | Per agency | Every agency feed lands in public_events regardless of whether a program consumes it. Adding a feed never requires a program. |
| Intelligence | Cross-agency | Surfacing, mapping, alerting, and risk scoring read public_events across all agencies. Program-agnostic. |
| Workflow | Per program | Projects, obligations, services, documents, and filings are always scoped to one compliance program. A project belongs to nyc-lead-paint. |
8.3 Growth paths, and what each costs
| Want to add | You write | You must not touch |
|---|---|---|
| A new agency's data feed (e.g. DEP water) | A FeedDefinition + ingestion adapter | Anything else |
| A new program under an existing agency (e.g. DOB façade / LL11) | A ComplianceProgram module | Projects, phases, documents engine, schema |
| A new program spanning agencies | Same, listing multiple participatingAgencies | Same |
| A new city (LA, Chicago) | A Jurisdiction + its agencies + its programs | Same |
8.4 Binding rules
- One rulebook per program, single source.
orderRegistryis canonical; adapters and validation derive from it, never re-hardcoding an order's behavior elsewhere. - The core never names an agency. No
if (agency === 'hpd')outside a program module; NYC-specific vocabulary (BIN, BBL, HPD order numbers) lives in agency-scoped columns or JSON, never in core columns. - Programs are code, not configuration (D8) — a typed TypeScript module, versioned and tested.
- Fidelity gate. The ported
nyc-lead-paintrulebook must reproduce the old implementation's output case-for-case before the old code is deleted. - Every project records its program.
projects.program_idis non-nullable, even though v1 has only one value.
9. v1 scope
All four module groups are in scope for v1 as intent. Status below is a snapshot; the
living record is docs/LIFECYCLE_ASSESSMENT.md and
docs/domain/CUTOVER.md.
9.1 Core — buildings, units, projects, workspace
Citywide registry with PLUTO/BIN resolution · tenant building tracking · client management · the three project origins · Decide/Work/File/Money detail · scheduling per inspection · audit trail on phase-label changes. Shipped, with holes (units create UI, post-create event linking on obligation/occupant-request origins) — detail in CUTOVER.md.
9.2 Compliance intelligence
Agency feed ingestion into public_events with guaranteed linkage · violation surfacing ·
citywide map · tracked-building alerts/digest email · saved views · ingestion ops dashboard.
Layer 1/2 ingest, /map, /violations shipped; obligation engine, cron, ops dashboard, and
alert rules are not — detail in CUTOVER.md.
9.3 Field work
Inspection scheduling/access tracking · XRF (instruments, calibration, component groups, room
requirements, readings, CSV import, findings, report gen/versioning) · dust wipe/paint
chip/abatement sampling · lab partners and chain of custody · floor plans and room presets ·
online-only field capture (OPEN-6 resolved 2026-08-21: no IndexedDB queue-and-sync — every
inspection-wizard read/write requires connectivity). /field + XRF CSV → report shipped;
non-XRF reports, CoC, lab-result entry, and admin are not wired in UI.
9.4 Documents, portal, and money
Document templates/validation · affidavit/proposal generation · paperwork bundles, signature
and notary tracking · HPD filing package assembly · invoicing, rate cards, line items, vendor
payments · white-label client portal (per-tenant/per-client branding) · outbound email with
delivery state, suppression, unsubscribe. Generators, portal, branding, and email pipeline
shipped; filing package has no merged PDF, empty rate cards yield $0, and email stops at
queued_unsent without RESEND_API_KEY.
9.5 Explicitly out of scope for v1
Subscriptions/plans/entitlements/Stripe (D9) · the admin workflow studio (D8) · any
jurisdiction other than NYC (D6) · the firms layer (D11) · a native mobile app (field work is
responsive web) · Airtable migration tooling · every legacy per-agency violation table · a
phase-gate engine keyed on projects.phase (D21).
10. Non-functional requirements
| Area | Requirement |
|---|---|
| Security | RLS on every table. Tenant isolation proven by an automated cross-tenant leakage suite. No service-role key ever reaches the browser. Edge functions that read client PII or financials gate on resource ownership, not merely on a valid JWT. |
| Auditability | Append-only audit log for state transitions, document generation, impersonation, and cross-tenant collaborator actions. Compliance work must be defensible years later. |
| White-label | Per-tenant branding — logo, palette, sender identity, document letterhead, portal domain — resolved at request time. No Complied branding leaks into a tenant surface. |
| Data integrity | Foreign keys enforced. No orphan tables. No nullable tenant_id on tenant-owned data. No nullable building_id on events. |
| Testing | Vitest for domain logic — rulebook, deadlines, applicability, pricing. Playwright for the critical paths. A feature is not done until it has been exercised end-to-end against real data. An empty table means untested, not finished. |
| Migrations | One consolidated, reviewable baseline. Every subsequent migration forward-only and reversible in intent. No migration ships without its RLS policies. |
| Performance | Citywide map and event lists must stay responsive over millions of rows — server-side pagination, indexed filters, no client-side full-table loads. |
10.1 Backend architecture and the migration seam (D15)
v1 has no API service. The browser talks to Postgres through PostgREST and RPC, RLS as the enforcement layer — a deliberate MVP trade, since both launch tenants (SecureEnv, Abated) are internally owned and shipping a testable product matters more right now than architectural purity.
That trade expires. The Lovable-era app had 824 .from() calls across 106 tables
scattered through the UI — the pattern that makes a backend migration expensive, and the thing
not being repeated. These seams are mandatory in v1:
- No
.from()or.rpc()outsidesrc/data/andsrc/auth/. One typed repository module per table, intention-revealing functions (listOpenViolationsForBuilding), never raw query builders; components call repositories, never Supabase.src/auth/identity lookups are the documented exception. Enforced by an ESLint rule, not convention. - Domain logic is pure TypeScript in
domain/(@complied/domain) — rules, deadlines, applicability, pricing, XRF determination; no I/O, no Supabase import, runnable in Node. Moves to a server unchanged when the backend arrives. Notsrc/domain/. - Database functions are reserved for two jobs: atomic operations (invoice number
allocation) and non-client-forgeable ones (tenant resolution, permission checks). No
business logic in PL/pgSQL — the old system's 140
SECURITY DEFINERfunctions are a warning, not a template. - Every write path is a named function. No component builds an update payload inline.
- Auth is accessed through one module. A single
src/auth/wrapper over Supabase Auth; nothing else importssupabase.auth. 878 RLS references toauth.uid()make this the deepest Supabase hook and the one most worth isolating.
Hold those five and the NestJS migration becomes "reimplement src/data/, move domain/,
point the client at a new base URL." Break them and it's a rewrite of hundreds of call sites.
Migration trigger (not scheduled by date — whichever comes first): the first external tenant onboards (cross-tenant correctness stops being internal, RLS-only is no longer acceptable as the sole point of failure); cross-tenant collaboration (D4) ships past two tenants (the grant-scoped RLS is the hardest in the system, doesn't scale safely by hand); or ingestion reliability becomes a recurring incident (cron-plus-edge-function has no retry, dead-letter, or run observability — a job queue is the fix, and it needs a server). Until one fires, Supabase-only stands and is not to be relitigated.
11. Execution plan
Complete. Phases 0–8 and Phase 9's file-promotion step finished 2026-08-22; hosting went live
2026-08-26. Full phase-by-phase history: docs/history/CHANGE-LOG.md.
Remaining work is the CUTOVER gap list — see docs/domain/CUTOVER.md — not a rebuild phase.
12. Open questions
None open. All resolved 2026-08-20 through 2026-09-02 — see D16–D21 in §2, including OPEN-6 (offline field capture: online-only for v1) and D21 (phase is not a capability, 2026-08-31 Rung 6 owner ruling).
13. Change log
Rebuild phases are complete and hosting is live; this section is no longer active-decision
content. Full phase-by-phase history: docs/history/CHANGE-LOG.md.
| Where | What it is |
|---|---|
| This file §2–§8, §10 | Locked decisions and architecture intent |
docs/domain/ | What the running system is |
docs/LIFECYCLE_ASSESSMENT.md | Can we run a real project? |
docs/domain/CUTOVER.md | Production / CARRY gaps |