Superseded by 0134: the global
invariants stand; the per-model opt-ins are replaced by classification, retention and a delete
policy.
Context
0014 fixes who owns data and which ORM is used, but not what every row looks like. Without a rule, each model chooses its own id type, deletion behaviour and audit trail, and a later change is a migration across every table. The owner split the question: a few invariants apply to every model, and the rest are opt-ins declared per model.Decision
- Global invariants, no opt-out:
- Primary keys are UUIDv7; externally they carry a type prefix.
- Every tenant-owned model has
tenant_idwith row-level security (0045).
- Per-model opt-ins, declared on the model and read by the framework:
- Delete policy:
archive(default),softorhard. - Audit: changes publish audit events (0047).
- Timestamps: created and updated times.
- Versioning: a row version for optimistic concurrency or history. Exact semantics TODO.
- Searchable: the model is indexed through
@stackra/search(0049). - PII field encryption: named fields are encrypted at the application layer. Key management TODO.
- Delete policy:
- A model with no declared delete policy is
archive. Choosinghardis a visible, reviewable line in the model. - Raw SQL stays an escape hatch in migrations, as in 0014 decision 6; it does not remove an invariant.
Consequences
- Models are short to write and uniform to read.
- Defaults lean toward keeping data;
harddelete is the exception that needs a reason (relevant to erase requests under the GDPR practice). - The meaning of
archiveversussoftmust be defined precisely before implementation (TODO).
Enforcement
Planned — a build-time check on model definitions (UUIDv7 key,tenant_id and RLS on tenant-owned models, declared opt-ins valid) plus the per-service schema-drift test planned in 0014. Nothing is implemented yet.