From 13d2b5fabb3b8a7938e1d98365b461996d9d6794 Mon Sep 17 00:00:00 2001 From: Thomas Joise Date: Fri, 17 Jul 2026 20:51:26 +0530 Subject: [PATCH] docs(d21): stamp DELIVERED, D-record, real-data verification, test count 363 Co-Authored-By: Claude Fable 5 --- CLAUDE.md | 4 ++-- docs/06-DECISIONS.md | 15 +++++++++----- .../2026-07-17-module-field-schema-design.md | 20 ++++++++++++++----- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 0ba54dc..436c992 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -43,7 +43,7 @@ distilled to what applies to HQ. A change that breaks one does not land. | Append-only audit | Every mutation calls `writeAudit(db, userId, action, entity, id, before, after)` in the **same transaction** as the change. The audit log is append-only — never update or delete rows. Previews and the public share route write nothing. | `audit.ts` | | Client id is the future tenant id | `client.id` is a client-generated UUIDv7 that becomes `tenant_id` when the cloud tier stands up — same rows, promoted once. Never re-key clients. | `repos-clients.ts` | | No silent caps | Every list that can grow paginates or warns; never silently truncate. | reports, directory queries | -| Strict TS, green before landing | Strict TypeScript everywhere; `npm run typecheck` and `npm test` both clean before anything lands. Money math is locked by tests — a rounding change without a test change does not land. | `tsc`, vitest (346 tests) | +| Strict TS, green before landing | Strict TypeScript everywhere; `npm run typecheck` and `npm test` both clean before anything lands. Money math is locked by tests — a rounding change without a test change does not land. | `tsc`, vitest (363 tests) | ## Running it @@ -66,7 +66,7 @@ cd apps/hq-web && npm run dev - Postgres integration tests: `HQ_PG_TEST_URL=postgres://hq:hq_dev@localhost:5432/hq_test npm test` (wipes that database each run — never point it at real data). - Health check: `GET /api/health` → `{ ok: true }`. -- Verified state: `npm install` + typecheck clean, 346 tests pass. Exercise real flows end +- Verified state: `npm install` + typecheck clean, 363 tests pass. Exercise real flows end to end before claiming done. ## Docs (kept in `docs/`) diff --git a/docs/06-DECISIONS.md b/docs/06-DECISIONS.md index 2fc4be4..6f2fd1b 100644 --- a/docs/06-DECISIONS.md +++ b/docs/06-DECISIONS.md @@ -332,9 +332,14 @@ Two real-data facts to carry forward: the export has NO state/GSTIN column (all CGST/SGST at the company state) and one client's OS field holds a plaintext Linux root password (move it into an encrypted field + rotate at cutover). -## D21 — Module-defined field schema (config on the module) — DESIGNED, queued after D20 import +## D21 — Module-defined field schema (config on the module) ✅ DELIVERED (2026-07-17) Spec `superpowers/specs/2026-07-17-module-field-schema-design.md`. Each module declares its -own operational fields (`module.field_spec` JSON); per-client values organised by that -schema; a generalised encrypted secret map replaces the single portal password. Founder -mandate: the app, modules and client↔module mapping stay flexible — a new module or a -changed field needs no code and no migration. Implementation follows the real-data cutover. +own operational fields (`module.field_spec` JSON: FieldDef key/label/type/options/required); +per-client values live on `client_module` as `field_values` (non-secret, type-validated +against the owning module's spec) + `secrets_enc` (one AES-GCM blob over a {key:plaintext} +map, N secrets, reveal audited). Owner defines a module's fields on the Modules page; the +Client 360 service card renders the form automatically; a new module or field needs NO code +and NO migration — the founder's flexibility mandate, delivered. Built **additively** over +D20 (login trio keeps its columns; retiring them into field_spec is a later cleanup after the +direction is confirmed). Verified on the real re-import: RTGS 13 fields / SMS 6 / MobileApp +1, 53/53 RTGS + 102/105 SMS links carrying structured values. Suite 363 green. diff --git a/docs/superpowers/specs/2026-07-17-module-field-schema-design.md b/docs/superpowers/specs/2026-07-17-module-field-schema-design.md index fec8e9f..d0dbe69 100644 --- a/docs/superpowers/specs/2026-07-17-module-field-schema-design.md +++ b/docs/superpowers/specs/2026-07-17-module-field-schema-design.md @@ -1,10 +1,20 @@ # HQ Console — Module-Defined Field Schema (D21) -> **STATUS: DESIGNED 2026-07-17, implementation queued AFTER the D20 trial import** -> (founder timing call). Approach: *config on the module* (the simplest of the three -> weighed). North star (founder): the app, the modules, and the **client↔module mapping** -> must stay flexible — a new module or a changed field must never need a code change or a -> DB migration. +> **STATUS: DELIVERED 2026-07-17** (built additively over D20; suite 363 green). Approach: +> *config on the module* (the simplest of the three weighed). North star (founder): the app, +> the modules, and the **client↔module mapping** must stay flexible — a new module or a +> changed field must never need a code change or a DB migration. +> +> **Verified on real data** (re-import into local Postgres): RTGS declares 13 fields, SMS 6, +> MobileApp 1; 53/53 RTGS links and 102/105 SMS links carry structured field values (IP, IP +> code, partner bank, IFSC, QR, SMS balance, reseller, alert types…) instead of a free-form +> blob. Owner defines a module's fields on the Modules page; every client on that module +> shows the form automatically; secret fields encrypt with an audited reveal. +> +> **Built additively** (deliberate, for the confirm-after-build gate): D20's login trio +> (provider/username/portal-password) stays in its own columns/card; D21 adds the +> module-specific fields on top. Retiring the D20 columns into field_spec is a later cleanup +> once the direction is confirmed. ## 1. The problem