diff --git a/CLAUDE.md b/CLAUDE.md index 2d4a989..3509cc6 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 (344 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 (345 tests) | ## Running it @@ -63,7 +63,7 @@ cd apps/hq-web && npm run dev - Env: `HQ_DATA_DIR` (DB location), `SIMS_PIN_PEPPER` (set once, never change), `HQ_SECRET_KEY` (before Gmail), `GOOGLE_*` (Gmail), `AWS_*` (Cost Explorer), `HQ_PORT` (default 5182). - Health check: `GET /api/health` → `{ ok: true }`. -- Verified state: `npm install` + typecheck clean, 344 tests pass. Exercise real flows end +- Verified state: `npm install` + typecheck clean, 345 tests pass. Exercise real flows end to end before claiming done. ## Docs (kept in `docs/`) diff --git a/README.md b/README.md index 5511030..4db6bcf 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ document and conversation we've had with them. ## Build state (start here) -Working codebase, not a plan. `npm install` + typecheck are clean and **344 tests pass**. +Working codebase, not a plan. `npm install` + typecheck are clean and **345 tests pass**. Current state and run-vs-pending detail live in **[STATUS.md](STATUS.md)**; the go-live runbook (server, HTTPS, backups, Gmail/AWS/import wiring, the Postgres switch) is in **[docs/DEPLOY-HQ.md](docs/DEPLOY-HQ.md)**. diff --git a/STATUS.md b/STATUS.md index a78336a..3dcf798 100644 --- a/STATUS.md +++ b/STATUS.md @@ -13,7 +13,11 @@ append-only audit trail, an APEX cutover importer, and a background scheduler. The 2026-07-17 quote-to-close slice (D16) added employee management with owner / manager / staff roles, account-owner routing on clients, a cross-client pipeline chase-list with derived stages, and escalating quote follow-up -reminders driven by the dated `reminder_schedule` table. +reminders driven by the dated `reminder_schedule` table. The same-day D18 +go-live cluster added invoice due dates, the Documents and Reminders pages, +self-service profiles, My Day, client support-access data, the APEX import web +UI, the editable module roster with one-click Convert & send, and the +section-per-module quotation PDF — then closed all 8 findings from its review. ## Verification state @@ -21,10 +25,14 @@ reminders driven by the dated `reminder_schedule` table. | --- | --- | | `npm install` | clean | | `npm run typecheck` (root + workspaces) | clean, no errors | -| `npm test` (`vitest run`) | **344 tests pass across 66 files** | +| `npm test` (`vitest run`) | **345 tests pass across 66 files** | -The 344 figure is the live `vitest run` count measured 2026-07-17, after the -quote-to-close funnel slice and its review fixes. Test files live under +The 345 figure is the live `vitest run` count measured 2026-07-17, after the +D18 go-live cluster **and its post-delivery review pass** (8 reviewer findings +— convert-and-send click bubbling, importer support-field mapping, Pipeline +convert parity, client-book filters, typed contact roles, due-date anchors on +dashboard/aging, and two atomicity gaps — all confirmed and fixed the same +day). Test files live under `apps/hq/test/` (49 files, including `employees`, `employees-routes`, `client-owner`, `pipeline`, `quote-followup`, and `reminder-schedule`), `apps/hq-web/test/`, and `packages/{domain,auth,billing-engine,ui}/test/`. @@ -58,12 +66,14 @@ quote-to-close funnel slice and its review fixes. Test files live under ## Database schema (`apps/hq/src/db.ts`) -The schema creates 26 tables on open; `migrate()` additively backfills three -columns (`module.quote_content`, `email_log.bounced`, `client.owner_id`) on -older DBs and widens two CHECK constraints via a guarded, transactional -table rebuild (`rebuildTable`: `staff_user.role` gains `manager`, -`reminder.rule_kind` gains `quote_followup`) — a no-op on fresh DBs and on -re-runs. +The schema creates 26 tables on open; `migrate()` additively backfills the +post-launch columns on older DBs (`module.quote_content`, `email_log.bounced`, +`document.due_date`, `staff_user.phone`/`title`, `client.owner_id` plus the +D18 support fields `anydesk`/`os`/`district`/`sector`/`db_password_enc`, and +the same four support fields on `stg_client` so the APEX cutover carries them) +and widens two CHECK constraints via a guarded, transactional table rebuild +(`rebuildTable`: `staff_user.role` gains `manager`, `reminder.rule_kind` gains +`quote_followup`) — a no-op on fresh DBs and on re-runs. | Table | Purpose | | --- | --- | @@ -237,24 +247,30 @@ Everything below is implemented and exercised by tests via the Express router ## Frontend screens (`apps/hq-web`) Shell (`Layout.tsx`): grouped sidebar (WORK / CATALOG / INSIGHT / ADMIN) with -lucide icons and a reminder-queue count badge, top bar with Ctrl+K command -palette, Gmail status pill, theme/accent switcher and user chip, plus the -Gmail-disconnected banner. Owner-only items (Employees, Document Template) -appear in ADMIN; the warm ops-console restyle is the 2026-07-17 redesign spec. Routes (`main.tsx`): +lucide icons and a reminder-queue count badge — collapsible to an icon rail via +the footer ‹/› toggle (remembered in `localStorage`) — top bar with Ctrl+K +command palette, Gmail status pill, theme/accent switcher and a user menu +(Profile / Logout), plus the Gmail-disconnected banner. Owner-only items +(Employees, APEX Import) appear in ADMIN; the warm ops-console restyle is the +2026-07-17 redesign spec. Routes (`main.tsx`): | Route | Screen | What it does | | --- | --- | --- | | `/login` | `Login` | Split-panel sign-in — dark warm brand panel + form card (brand panel hides under 800px) | | `/` | `Dashboard` | Money headline cards, the reminder queue with send / preview / dismiss, and overdue / due-this-week / renewals / follow-ups / recent-payments tables | -| `/pipeline` | `Pipeline` | Cross-client chase-list: derived stage, amount, owner, age and colour band per row with an explicit next action; `All / Mine / Overdue / Lost` chips, owner narrowing (owner/manager), pagination | -| `/clients` | `Clients` | Search, list, inline new-client create; row → client 360° | +| `/pipeline` | `Pipeline` | Cross-client chase-list: derived stage, amount, owner, age and colour band per row with an explicit next action (incl. one-click confirmed **Convert & send**); `All / Mine / Overdue / Lost` chips, owner narrowing (owner/manager), pagination | +| `/reminders` | `Reminders` | Standalone reminder queue: status chips (Queued / Sent / Failed / Dismissed), Mine/All (managerial), send / preview / dismiss, pagination | +| `/clients` | `Clients` | Search + district/sector filters, status chips, inline new-client create; row → client 360° | | `/clients/:id` | `ClientDetail` | Client 360°: avatar record header + status, **account-owner dropdown** (owner/manager), KPI row, a 12-month **relationship-pulse ribbon** (documents / payments / interactions / AMC on one axis; hover readout, click-through), and deep-linkable **tabs** (`?tab=`): Overview · Modules (assignment & lifecycle) · Documents · Payments & plans (record payment, advance, recurring — owner) · AMC (owner) · Interactions (log + follow-ups) · AWS usage | | `/modules` | `Modules` | Module catalogue + dated price book; owner edits (create module, quote content with live sample preview, add prices), staff read-only | | `/reports` | `Reports` | Dues aging, module revenue, client profitability, and an AWS cost bar chart by month | -| `/documents/new` | `NewDocument` | Quotation-in-minutes composer: client type-ahead, line editor, server-computed GST, and a live PDF-fidelity preview (desktop split view / mobile sheet) | +| `/documents` | `Documents` | Register of every document, newest first: type chips + status filter, honest server pagination with true totals, one-click confirmed **Convert & send** on issued proformas | +| `/documents/new` | `NewDocument` | Quotation-in-minutes composer: client type-ahead, line editor, server-computed GST, due-date field on invoices (auto-filled from terms, editable), and a live PDF-fidelity preview (desktop split view / mobile sheet) | | `/documents/:id` | `DocumentView` | Document page: PDF preview, state-driven action bar (issue / send / mark / convert / cancel / credit note / record payment), share & download group (copy link / WhatsApp / native share / revoke), event timeline and email log | | `/settings/template` | `DocumentTemplate` | Owner-only letterhead editor (company + boilerplate + titles + logo) with a live sample preview | | `/employees` | `Employees` | Owner-only staff management: add / edit / re-role / reset password / deactivate / reactivate, surfacing the last-owner and self-deactivation guards | +| `/profile` | `Profile` | Self-service: edit display name/phone (email + role read-only), change own password (current password required; other sessions purged) | +| `/import` | `ImportApex` | Owner-only APEX cutover: CSV pickers → staged rows with per-row problem chips → verification summary → commit locked until zero problems | The composer, quote-content, and template previews all use one `LivePreview` component that renders the server's real `documentHtml` in a sandboxed diff --git a/docs/06-DECISIONS.md b/docs/06-DECISIONS.md index 90b3940..544579c 100644 --- a/docs/06-DECISIONS.md +++ b/docs/06-DECISIONS.md @@ -256,4 +256,10 @@ in ten phases the same day. The calls that matter going forward: owner/manager toggle Mine/Everyone (`?mine=1`). Sidebar collapses to an icon rail. - **APEX import UI:** owner-only `/import` wraps the existing stage/verify/commit — commit stays locked while any staged row carries a problem. -Suite at 344 tests / 66 files at delivery. +Delivery was followed the same day by an independent review of the full slice diff: +8 findings (4 major — convert-and-send click bubbling on the register, importer not +mapping the WS-F support fields, Pipeline still on the old plain convert, missing +client-book filter UI; 4 minor — typed contact roles absent, dashboard/aging still +anchored on doc_date, non-atomic dbPassword PATCH, audit-outside-txn on three new +write paths) — all confirmed and fixed in one pass (`fix(review)` commit). +Suite at 345 tests / 66 files after the review pass. diff --git a/docs/superpowers/specs/2026-07-17-golive-cluster-design.md b/docs/superpowers/specs/2026-07-17-golive-cluster-design.md index e95ada2..b33a096 100644 --- a/docs/superpowers/specs/2026-07-17-golive-cluster-design.md +++ b/docs/superpowers/specs/2026-07-17-golive-cluster-design.md @@ -1,9 +1,15 @@ # HQ Console — Go-Live Cluster Spec (Due Dates, Import UI, Reminders/Documents Pages, Shell & Profile, Client Support Data) -> **STATUS: DELIVERED 2026-07-17.** Successor slice to the delivered D16 funnel +> **STATUS: DELIVERED 2026-07-17; reviewed same day — all 8 review findings fixed +> (`fix(review)` commit), suite at 345 tests.** Successor slice to the delivered D16 funnel > (`2026-07-17-quote-to-close-funnel-design.md`). The Postgres switch (D15) is deliberately > NOT in this slice — it is the dedicated task queued immediately after it, before the > real-data import commit. +> +> Post-review deltas vs the text below: the clients CSV also carries optional +> `anydesk,os,district,sector` columns (§3's "mapped from the APEX CSV" promise now holds — +> A4's "same two CSVs" means same files, with four optional extra headers), and the +> district/sector book filters match partial text (LIKE) rather than exact values. ## 1. Overview & goals