A self-hosted, browser-based ISO 9001:2015 Quality Management System (QMS). A managed controlled vault (PostgreSQL + MinIO WORM) owns the master copy of every controlled document and record; the on-disk filesystem is a read-only mirror regenerated from Released versions only — so document drift becomes an enforced invariant rather than a discipline problem.
-
Specification: complete and internally reconciled — see
docs/(start atdocs/00-overview.md;docs/decisions-register.mdis authoritative). -
Implementation plan:
docs/18-mvp-implementation-plan.md(approved). -
Code: the MVP is complete — all 11 vertical slices (S0–S11) shipped to protected
main(each via a PR with green CI), all six acceptance proofs in, the mirror epic + both information-architecture backends complete, and the doc-18 §12 exit checklist closed.- S0 — walking skeleton ✅ — Compose stack,
/healthz+/readyz, reversible Alembic baseline, OpenAPI→client pipeline. - S1 — authentication ✅ — Keycloak OIDC/PKCE, JWT-vs-JWKS validation,
app_user+ JIT provisioning,/me. - S2 — authorization ✅ — deny-wins PDP/PEP, the closed permission catalog + 8 seeded roles, two-tier grant guard.
- S3 — vault ✅ — document create + the check-out → presigned CAS upload → immutable check-in cycle (MinIO WORM, Redis lock).
- S4 — lifecycle ✅ — the document FSM (Draft→…→Effective) + the atomic single-Effective cutover (SERIALIZABLE + INV-1), 6 named lifecycle actions, R25 singleton index, future-dated Beat sweep.
- S5 — approval + SoD ✅ — the task/decision approval workflow (
POST /tasks/{id}/decisionwritessignature_event+task_outcome+audit in one txn; tasks-canonical), append-onlysignature_eventemission on approve/release/obsolete, and the deny-wins separation-of-duties gate (SoD-1 no self-approval, SoD-2 no self-release, SoD-3 auditor independence). - S6 — audit ✅ — the append-only, monthly-partitioned, hash-chained
audit_eventtrail behind DB role separation (a non-ownereasysynq_approle with INSERT/SELECT-only onaudit_event+signature_event, so append-only is structurally enforced — AC#6a); the in-transaction audit writer; the decoupled chain-linker (a dedicatedeasysynq_linkerrole, advisory-locked, bounded-lag alarm) with a frozencanonical_serialize+ golden vector;verify-chain(detects a mutated row as the first broken link — AC#6b); the off-hostworm_bucketcheckpoint anchor with an honest tamper-evidence soft-gate (R13); and the read-only/audit-eventsAPI. - S7 — mirror ✅ — the read-only, Effective-only filesystem mirror, regenerated from the vault via an atomic symlink-repoint swap, mounted RO (AC#2). S7b watermarked-PDF rendering (Gotenberg + a deterministic reportlab/pypdf §11.3 band, cached non-WORM rendition); S7c the Ed25519 verify-token + QR + the public
GET /verify(CURRENT/SUPERSEDED/UNKNOWN); S7d the per-request export/print stamp. - S8 — first-run setup ✅ — the 423 setup-latch + the five blocking gates, each shipped as its own slice: S8a the bootstrap-of-trust spine (mint-secret → first System Administrator) + org profile + finalize (G-A/G-E); S8b the WORM-verify probe (G-B); S8b2 the backup→restore-into-scratch drill + durable backup (G-C / AC#5); S8c auth-config + a non-bootstrap login proof (G-D) + the client router; S8d the Users & Roles admin (roster / invite / enable-disable + role/override management).
- S9 — clause IA +
clause_mapping✅ — the read-only ISO 9001:2015 clause spine (an 83-clause seeded catalog, the 20 ★ mandatory documented-information items) + the M:N document↔clause mapping (GET /clauses, flat…/clause-mappingssub-resources) + the lifecycle submit gate (a document needs ≥1 clause mapping before review). - S9b — clause-aligned mirror tree ✅ — the §10.3
PLAN/DO/CHECK/ACT → {NN}-{clause}/tree: each Effective doc lives once under its numerically-lowest mapped clause and is reached from every other mapped clause via a relative symlink (clause 7 splits PLAN/DO); an unmapped (pre-S9 upgrade) doc lands in_unmapped/. - S9c — process IA backend ✅ — the Clause 4.4 process graph (
process/process_edge/process_link+org_role/supplierFK targets) withGET /processes(/{id})(/map)+SEED→ACTIVEauthoring (POST/PATCH /processes,…/edges) + the M:N…/process-linkssub-resource, all audited (process.create/assign_ownerseeded-but-ungranted → grant via override until the role UI). - S9d — by-process mirror index ✅ — the §10.3 secondary
current/by-process/{name}/tree of relative symlinks into the clause-tree doc folders (always-on; bytes never duplicated). Completes the mirror epic. - S10 — search + the Compliance Checklist ✅ — the org-wide checklist (
GET /reports/compliance-checklist: the 20 ★ mandatory clauses with COVERED/PARTIAL/GAP coverage), Postgres-FTSGET /search(+/suggest) behind an engine-agnosticIndexerseam (Effective-only, filter-not-403), andclause_refs+ bracketedfilter[field][op]onGET /documents(the audit-read API proven write-verb-free, co-proving AC#6). - S11 — the MVP exit slice ✅ —
easysynq restore(WORM-aware restore-to-verified-target: fresh scratch DB + fresh non-WORM bucket, the locked vault read-never-written, integrity triad → checkpoint-not-ahead tamper guard → restored-chain re-verify → a documented operator cutover) +easysynq upgrade(pre-backup → migrate → health-gate); backup archive v2 (AES-256-GCM envelope + Keycloak realm export + config snapshot, the G-C drill kept plaintext-internal so AC#5 isn't regressed); Caddy strict static CSP + TLS 1.2 floor + air-gap internal-issuer wiring; a server-side NFR P95 smoke; and the operatordocs/runbooks/. The MVP is done.
See
CLAUDE.mdfor the per-slice detail and the v1/v1.x deferrals.Run it:
just up s, then open http://localhost (dev logindemo/Demo-Password-1). - S0 — walking skeleton ✅ — Compose stack,
-
v1 phase: the ISO 9001:2015 ★ spine is feature-complete ✅ — every ★ family shipped end-to-end on
main(each via a PR with green CI), and the React/TS web track is feature-complete for them:- Records & evidence (
docs/06) — capture → retention/disposition + management → evidence packs (with revocable external share links) → Mode-B structured-form capture. - Ingestion engine (
docs/09, UJ-2) — the read-only on-ramp that imports an existing QMS file tree into the controlled vault (scan/inventory → extract/classify → dedup/propose → review → commit). - Audits / Findings / CAPA, Document Change Requests (read/write/diff/annotate/CREATE-implement), Mirror drift D1–D5, Acknowledgements, Quality Objectives (lifecycle/revision + KPI trend chart), and Management Review (backend + UI + outputs→action-systems + filed-minutes pack).
- Improvement Initiatives (clause 10.3, R46) — the own-table workflow object end-to-end, including the opt-in signed, engine-routed Top-Management authorization.
- Leadership release routing (S-leadership-1) — an opt-in, document-backed Top-Management RELEASE authorization for the clause-5/6/9 leadership artifacts (POL §5.2 / OBJ §6.2 / MR §9.3), gated by an org config flag (default off).
See
CLAUDE.mdCurrent-status anddocs/slice-history.mdfor the per-slice detail and the v1/v1.x deferrals. Migration head0054. - Records & evidence (
packages/contracts/ OpenAPI-first source of truth (openapi.yaml → generated server models + TS client)
apps/api/ FastAPI / Python 3.12 (the vault, lifecycle, PDP/PEP, audit)
apps/web/ React/TS + Mantine + Tailwind SPA
migrations/ Alembic (single tree)
infra/compose/ Docker Compose stack (S/M profiles ship; L is spec-only) + Caddy / Keycloak / MinIO config
scripts/ install.sh, easysynq (admin CLI), gen-contracts.sh
docs/ the specification + the implementation plan
Requires Docker Compose v2, uv, Node 22, and just.
just setup # install deps, pre-commit, generate the contract
just up s # bring up the stack (S profile)
# the API is reachable behind Caddy; /healthz and /readyz report statusThe four locked foundational decisions (D1–D4) and the Decisions Register (R1–R46 — see
docs/decisions-register.md) govern everything; seedocs/00-overview.md. Data never leaves the org boundary; there is no phone-home.