docs: HQ project identity (README, STATUS, CLAUDE) + fix cross-repo doc links

Adds the front-page README, a first STATUS.md build-state doc (the console had
none), and a CLAUDE.md with the house rules that govern this repo. De-links four
references to Store-only planning docs (04-ROADMAP, 08-MARKET-ARCHITECTURES,
09-UX-FLOWS-AND-MENUS) that now live in the Store repo, and regenerates the
lockfile to drop the removed Store workspace entries.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
feat/client-detail-redesign
Thomas Joise 5 days ago
parent 7e1c93cee0
commit 115f2e6c41

@ -0,0 +1,72 @@
# CLAUDE.md — HQ Ops Console
This repo (`C:/SiMS/hq`) is the **internal console for running our own software business**
NOT software we ship to clients. It manages our ~300 existing Classic clients: client book,
sellable modules with a dated price book, documents (quotation / proforma / invoice / credit
note) on editable letterhead templates with PDF rendering and shareable public links,
call/interaction tracking, AMC contracts, AWS cost recovery, payments + allocations,
recurring plans, and reminders emailed via Gmail with bounce handling — plus reports, a
dashboard, an append-only audit log, an APEX importer, and a scheduler.
> **The Store/POS retail product is a SEPARATE repo.** It is local-first software installed
> in shops. Do **not** add Store/POS/counter/retail features here, and do not reference them.
> This app is vendor-side cloud only (the "HQ Console" of doc 11, started early per D15).
## Layout
| Part | Where | Notes |
|---|---|---|
| Backend | `apps/hq/src` | Express over `better-sqlite3`, DB at `data/hq.db` (WAL) |
| Frontend | `apps/hq-web/src` | React + Vite; pages Dashboard / Clients / ClientDetail / Documents / Modules / Reports |
| Repos | `apps/hq/src/repos-*.ts` | one file per domain; plain functions over a `DB` handle |
| Schema | `apps/hq/src/db.ts` + `apps/hq/schema.sql` | `CREATE TABLE IF NOT EXISTS` + additive `migrate()` |
| Shared packages | `packages/*` | trimmed forks — see below |
**Shared packages** (generic on purpose — keep them so): `@sims/domain` (`ids`/UUIDv7,
`money`/paise, `business-day`, `doc-series`, `gstin`, `documents`), `@sims/auth` (scrypt PIN
+ lockout), `@sims/billing-engine` (`compute`, `tax`), `@sims/ui`. HQ owns its own
document/payment types (quotation, proforma, credit note; NEFT/cheque/UPI modes) — do not
push those into the shared packages.
## Non-negotiable rules
These are the house hard rules (`docs/16-PROJECT-RULES.md`, `docs/07-DB-AND-CONFIG.md`)
distilled to what applies to HQ. A change that breaks one does not land.
| # | Rule | In this repo |
|---|---|---|
| Money is integer paise | Every amount is `Paise` (integer). Fractional-rupee floats never enter the domain; convert at the edge with `fromRupees`, format with `formatINR`. Every rounding step is explicit. | all `*_paise` columns; `@sims/domain/money` |
| One billing engine, re-verified | GST is computed **only** through `@sims/billing-engine` `computeBill` — save and preview run the same path so they cannot drift. The server recomputes to the paisa; a mismatch is rejected. | `repos-documents.ts` |
| Config over code, dated | Anything that varies — prices, tax rates/slabs, settings, doc-series prefixes, SAC codes, templates, message text — is a **DB row resolved by business date**, never a constant in code. A price or rate change is a new dated row, not a release. | `module_price_book`, `tax_class` (`effective_from`/`_to`), `doc_series`, `setting`, `template`, `reminder-templates` |
| Documents immutable once issued | Issuing assigns the number; after that the document is never edited or deleted. Corrections are **credit notes** (own per-FY series, links the invoice via `ref_doc_id`, CGST Act s.34). Cancel keeps the number consumed; only issued, unpaid, unallocated docs may cancel. QT→PI→INV convert by carrying lines forward into a new draft. | `repos-documents.ts``issueDocument`, `raiseCreditNote`, `cancelDocument`, `convertDocument` |
| Portable-repo pattern | All data access is plain exported functions taking the `DB` handle first arg — no ORM, no repo classes, no ambient singletons. Multi-write operations wrap in `db.transaction(...)`. Keep SQL portable (SQLite today, **Postgres is the locked production engine** — D15); avoid engine-specific SQL. | every `repos-*.ts` |
| 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 (177 tests) |
## Running it
```
npm install # workspace root, once
# backend (serves API on :5182, and the built web UI + public /share links)
cd apps/hq && npm start # build-server.mjs → dist/server.cjs; first boot prints a one-time owner password
# frontend dev (Vite on :5183, proxies /api and /share to :5182)
cd apps/hq-web && npm run dev
```
- Owner login on first boot: `admin@tecnostac.com` + the one-time password printed in the
server log (change it immediately). The "Gmail disconnected" banner is expected until Gmail is connected.
- 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, 177 tests pass. Exercise real flows end
to end before claiming done.
## Docs (kept in `docs/`)
`14-SPEC-HQ-CONSOLE.md` (the HQ spec — read first), `11-ADMIN-SUPPORT-CONSOLE.md` (the console
this grows into), `16-PROJECT-RULES.md` (hard rules), `07-DB-AND-CONFIG.md` (config-over-code +
DB strategy), `06-DECISIONS.md` (every decision has a D-number — add one when you decide
something), `DEPLOY-HQ.md` (go-live runbook). Follow **The Tables Rule**: anything that can be a
table IS a table, in docs and UI.

@ -1,49 +1,74 @@
# SiMS Next — Store Management Suite (Rebuild)
# SiMS HQ — Internal Ops Console
A ground-up rebuild of SiMS Store Software: GST-compliant retail management for India —
inventory, POS billing, purchases, and accounting — for everything from a single-counter
kirana shop to multi-outlet supermarket chains.
The console for running our own software business. It manages our **~300 Classic clients**
end to end — and it replaces the internal Oracle APEX app. This repo is **internal only**;
it is **not** shipped to clients.
**Why the rebuild:** the current product runs on Oracle Forms & Reports (hard to maintain,
buggy, no path to cloud/multi-store), and the market is moving. Same customers, much better
product.
One place for the client book, what each client has bought, the money they owe, and every
document and conversation we've had with them.
**North star:** the fastest, easiest counter workflow in the market. The customer in line
never waits because of the software, and purchase entry is never a burden.
## What it does
- **Client book** — the registry of ~300 clients: contacts, GSTIN, status, notes.
- **Modules + price book** — the sellable software modules with a **dated price book** (a
price change is a new row, not a code release) and per-client subscriptions.
- **Documents** — quotations (QT), proforma invoices (PI), invoices (INV) and credit notes
(CN), built on **editable letterhead templates**, rendered to **PDF** (headless Chromium),
with **shareable public links** (one token-guarded, rate-limited, revocable read route).
- **Interactions** — call / visit / meeting tracking against each client.
- **AMC contracts** and **AWS cost recovery** — per-client cost attribution pulled monthly.
- **Payments + allocations**, **recurring plans**, and **reminders** sent via **Gmail** on
the company mailbox, with **bounce handling** and a manual queue when the token dies.
- **Reports**, a **Dashboard**, an **append-only audit log** (every mutation), an **APEX
importer** for the initial 300-client load, and a **scheduler** (runs on boot + every 6h:
reminders, bounce polling, AWS cost pull).
## Build state (start here)
This is now a working codebase, not just a plan. Current state, run instructions, and the
live-vs-wireframe breakdown live in **[STATUS.md](STATUS.md)** and **[BUILDING.md](BUILDING.md)**.
Working codebase, not a plan. `npm install` + typecheck are clean and **177 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)**.
## Architecture
In brief: a web-app POS + back office served by a Node store-server over a portable data
layer (SQLite dev slice; Oracle 12c adapter pending the Classic DDL). Live and verified
end-to-end: billing (keyboard-first, offline-capable, B2B/IGST), purchases with batch/
expiry, returns/credit notes, and GST returns (GSTR-1/3B). A full adversarial security
review + P0P2 remediation is complete — see [docs/18-RED-TEAM-REVIEW.md](docs/18-RED-TEAM-REVIEW.md).
- **Backend — `apps/hq/src`**: an Express JSON API over **better-sqlite3**, behind portable
repositories (`repos-*.ts`, one per domain: clients, modules, documents, payments, amc,
aws, interactions, recurring, reminders, shares, reports, dashboard, email). SQLite is the
dev/test engine; Postgres is the locked production engine (see DEPLOY-HQ.md). DB at
**`data/hq.db`**; server on **:5182** (also serves the built web UI and the public
`/share/:token` route).
- **Frontend — `apps/hq-web`**: React + Vite. Pages: Dashboard, Clients, ClientDetail,
Documents, Modules, Reports.
- **Shared packages** (trimmed forks): `@sims/domain` (ids, money, business-day, doc-series,
gstin, documents), `@sims/auth` (pin/scrypt), `@sims/billing-engine` (compute, tax — our
invoices are GST documents, computed to the paisa), `@sims/ui` (design system).
## Planning documents
## Planning docs
| Doc | What it covers |
|-----|----------------|
| [docs/00-VISION.md](docs/00-VISION.md) | Product vision, segments/editions, business model, success metrics |
| [docs/01-SCOPE.md](docs/01-SCOPE.md) | Full module & feature catalog with priorities and edition mapping |
| [docs/02-ARCHITECTURE.md](docs/02-ARCHITECTURE.md) | Offline vs online vs hybrid analysis, sync design, tech stack, multi-tenancy |
| [docs/03-FRONTEND.md](docs/03-FRONTEND.md) | App surfaces, counter UX principles, screen inventory, design system |
| [docs/04-ROADMAP.md](docs/04-ROADMAP.md) | Phased build plan with exit criteria, pilot & migration strategy |
| [docs/05-CHECKLIST.md](docs/05-CHECKLIST.md) | Master build checklist, grouped by area |
| [docs/06-DECISIONS.md](docs/06-DECISIONS.md) | Open decisions that need a founder call, with recommendations |
| [docs/07-DB-AND-CONFIG.md](docs/07-DB-AND-CONFIG.md) | Everything-in-DB design (messages, plans, settings), local DB engine analysis (D12) |
| [docs/08-MARKET-ARCHITECTURES.md](docs/08-MARKET-ARCHITECTURES.md) | How Tally/Marg/GoFrugal/Vyapar & global players architect; Android POS conclusion |
| [docs/09-UX-FLOWS-AND-MENUS.md](docs/09-UX-FLOWS-AND-MENUS.md) | Screen-level UX blueprint: POS flows, back-office menu tree, Purchase Inbox, owner app |
| [docs/10-ISSUES-REGISTER.md](docs/10-ISSUES-REGISTER.md) | Consolidated failure-mode register across 6 lenses, with Top-10 risk ranking |
| [docs/11-ADMIN-SUPPORT-CONSOLE.md](docs/11-ADMIN-SUPPORT-CONSOLE.md) | Settings hierarchy, tenant Admin review, and the vendor-side HQ/support console |
| docs/13-SPEC-*.md | Keystroke-level specs: billing polish + purchase entry (P1/P2 backlog) |
| [docs/14-SPEC-HQ-CONSOLE.md](docs/14-SPEC-HQ-CONSOLE.md) | HQ ops console for the Classic client base (D15, apps/hq) |
| [docs/15-EDITIONS.md](docs/15-EDITIONS.md) | Lite/Standard/Pro/Enterprise: privileges, limits, costs — all configurable DB rows |
| [docs/16-PROJECT-RULES.md](docs/16-PROJECT-RULES.md) | The 26 hard rules (Tables Rule, money rules, config-over-code, counter rules) |
| [docs/17-SCALE-AND-INTEGRATIONS.md](docs/17-SCALE-AND-INTEGRATIONS.md) | The 7 committed scale gaps + full integrations catalog with status |
| [docs/18-RED-TEAM-REVIEW.md](docs/18-RED-TEAM-REVIEW.md) | Adversarial security review + remediation record (all findings closed) |
| [DEPLOY-HQ.md](DEPLOY-HQ.md) | Go-live runbook for the HQ ops console (apps/hq) |
Start with STATUS.md for what's built; then 00-VISION, 02-ARCHITECTURE, 04-ROADMAP for the plan.
| [docs/14-SPEC-HQ-CONSOLE.md](docs/14-SPEC-HQ-CONSOLE.md) | The console spec: shape, data model, features, delivery sequence (D15) |
| [docs/11-ADMIN-SUPPORT-CONSOLE.md](docs/11-ADMIN-SUPPORT-CONSOLE.md) | The vendor-side HQ / support console this app implements |
| [docs/07-DB-AND-CONFIG.md](docs/07-DB-AND-CONFIG.md) | Everything-in-DB design (messages, plans, settings) and the local DB engine analysis |
| [docs/06-DECISIONS.md](docs/06-DECISIONS.md) | Founder decisions, including D15 (build HQ early) and the Postgres call |
| [docs/16-PROJECT-RULES.md](docs/16-PROJECT-RULES.md) | The hard rules a PR must satisfy to merge |
| [docs/DEPLOY-HQ.md](docs/DEPLOY-HQ.md) | Go-live runbook for the console |
## Run
```bash
npm install # from the repo root (workspaces: packages/*, apps/*)
# Backend — HQ server (builds the server bundle, then runs it on :5182)
cd apps/hq && npm start
# First boot creates data/hq.db and prints a one-time owner password — capture it.
# Log in as admin@tecnostac.com with that password, then change it.
# Frontend — hq-web dev server (Vite on :5183, proxies /api and /share to :5182)
cd apps/hq-web && npm run dev
```
Nothing in `apps/hq/.env` is required to boot; each var unlocks a capability (Gmail sending,
AWS cost pull, security peppers) — see `apps/hq/.env.example` and DEPLOY-HQ.md. Repo-wide
checks from the root: `npm run typecheck` and `npm test`.

@ -0,0 +1,219 @@
# SiMS HQ — Build Status
_Internal ops console for running our software business. Not shipped to clients._
_Last reviewed: 2026-07-16 · Version 0.1.0_
HQ is the back-office console we use to run ~300 Classic client relationships:
the client book, our software module catalogue and dated price book, quotations /
proforma / invoices / credit notes with editable letterhead templates and PDF
output, shareable public document links, call & interaction tracking, AMC
contracts, AWS cost recovery, payments & allocations, recurring billing, and
Gmail reminders with bounce handling — plus reports, a money dashboard, an
append-only audit trail, an APEX cutover importer, and a background scheduler.
## Verification state
| Check | Result |
| --- | --- |
| `npm install` | clean |
| `npm run typecheck` (root + workspaces) | clean, no errors |
| `npm test` (`vitest run`) | **177 tests pass across 46 files** |
The 177 figure was re-counted from source (`it(`/`test(` blocks) and matches the
suite. Test files: 43 under `apps/hq/test/`, plus one each in
`packages/{domain,auth,billing-engine}/test/`.
## Architecture
- **Backend**`apps/hq/src`, Express over `better-sqlite3`. Every table sits
behind plain-function "portable repositories" (the D12 pattern: functions take
the DB handle, no ORM). SQLite-only SQL (`ON CONFLICT`, `INSERT OR IGNORE`) is
flagged in comments for a later Postgres port. DB file: `data/hq.db` (WAL mode);
`HQ_DATA_DIR` overrides the location, `:memory:` is used by tests.
- **Frontend**`apps/hq-web`, React 19 + Vite 6, `react-router-dom` v7 hash
router. Talks to the server over `/api` with a bearer token kept in
`localStorage`. In production the server serves the built SPA from
`apps/hq-web/dist`; in dev Vite runs separately.
- **Shared packages** (trimmed forks under `packages/`): `@sims/domain`
(ids, money, business-day, doc-series, GSTIN, documents), `@sims/auth` (scrypt
password hashing), `@sims/billing-engine` (GST compute + tax resolution),
`@sims/ui` (React component kit + theme).
- **Build/run**:
- Root: `npm install`, `npm run typecheck`, `npm test`.
- Server: `apps/hq``npm run build` (esbuild → `dist/server.cjs`),
`npm start` (build + run). Listens on `HQ_PORT` (default **5182**); the
scheduler starts with the server.
- Web: `apps/hq-web``npm run dev` / `npm run build`.
- CLI: `npm run import` (APEX importer), `scripts/gmail-connect.ts` (one-time
Gmail OAuth).
- Env: `HQ_PORT`, `HQ_DATA_DIR`, `HQ_SECRET_KEY` (64 hex / 32 bytes, for token
encryption), `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET`,
`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY`.
## Database schema (`apps/hq/src/db.ts`)
The schema creates 25 tables on open; `migrate()` additively backfills two columns
(`module.quote_content`, `email_log.bounced`) on older DBs.
| Table | Purpose |
| --- | --- |
| `staff_user` | Console logins — owner / staff, scrypt salt+hash, active flag |
| `session` | Bearer session tokens with expiry |
| `client` | Client registry — code, name, GSTIN, state, contacts (JSON), status, source |
| `module` | Software module catalogue — SAC, allowed billing kinds, multi-sub flag, quote-content lines |
| `module_price_book` | Dated prices per module/edition/kind (latest effective row wins) |
| `client_module` | A module assigned to a client — lifecycle status, install/complete/train dates, next renewal |
| `tax_class` | GST rate classes (dated); `GST18` seeded at 18% |
| `doc_series` | Per (doc_type, FY) running number + prefix |
| `document` | QT / PROFORMA / INVOICE / RECEIPT / CREDIT_NOTE — totals, status, ref chain, JSON payload |
| `document_event` | Per-document timeline (created / issued / sent / converted / cancelled / credit_note …) |
| `document_share` | Opaque public share tokens — expiry, revoked flag |
| `payment` | Money received — mode, reference, amount, TDS |
| `payment_allocation` | How a payment is applied across invoices |
| `email_account` | The single Gmail sending identity — encrypted refresh token, active/dead status |
| `email_log` | Append-only send trace — sent/failed, gmail message id, error, bounced flag |
| `setting` | Key/value store — `company.*` identity, `template.*` letterhead text, reminder + AWS config |
| `audit_log` | Append-only before/after JSON for every mutation |
| `stg_client` | APEX import staging for clients (per-row problem list) |
| `stg_invoice` | APEX import staging for invoices (per-row problem list) |
| `recurring_plan` | Recurring billing — cadence, amount-or-price-book, next run, auto/manual policy |
| `amc_contract` | AMC contracts — coverage, period, amount, reminder days, linked invoice |
| `interaction_type` | Interaction type lookup (call, site visit, training, …) |
| `interaction` | Client interaction log — outcome, notes, follow-up date |
| `reminder` | Reminder rows — rule kind, subject, due period, status; `UNIQUE(rule_kind, subject_id, due_period)` idempotency key |
| `aws_usage` | Per-client per-month AWS storage/transfer/cost; `UNIQUE(client_id, month)` upsert key |
## Backend capabilities
Everything below is implemented and exercised by tests via the Express router
(`apps/hq/src/api.ts`) or the scheduler.
- **Auth & roles** — email + password login (scrypt via `@sims/auth`), 14-day
bearer sessions, `requireAuth` / `requireOwner` middleware. First boot seeds an
owner and prints a one-time password to stdout. There is no self-service staff
management API yet — additional staff are created in code/seed only.
- **Clients** — create / list / search (name·code·GSTIN) / get / patch, GSTIN
checksum validation, auto-generated client codes, contacts as JSON, lead →
active → dormant → lost status.
- **Modules & price book** — owner-managed catalogue, dated price book
(`priceOn` = latest effective row ≤ date), allowed billing kinds
(one_time / monthly / yearly / usage), multi-subscription rule, per-module
"what's included" quote-content lines.
- **Client modules** — assign modules to clients, full delivery lifecycle
(quoted → ordered → installing → installed → trained → live → expired /
cancelled), install/complete/train dates, next-renewal date, single-active
guard for non-multi-sub modules.
- **Documents** — draft compose (`prepareDraft` is a pure compute half shared by
save **and** the live preview, so they can't drift), issue (assigns the series
number), legal status marks (sent / accepted / lost), the QT → PI → INV
conversion chain via `ref_doc_id`, cancel (number stays consumed; blocked once
payments are allocated), full/partial credit notes recomputed at the original
invoice date, and a permissive preview endpoint. Issued documents are never
edited — corrections are credit notes.
- **GST / billing**`@sims/billing-engine` `computeBill` with intra-state
CGST/SGST vs inter-state IGST split by place of supply, round-to-rupee, SAC
labelling. Place-of-supply is fail-loud: a missing `company.state_code` throws
rather than silently defaulting.
- **PDF rendering** — puppeteer HTML → A4 PDF (lazy singleton browser),
self-contained inline-CSS letterhead (`templates.ts`: `documentHtml`,
`receiptHtml`, `documentHtmlSample`). Letterhead identity/text, doc titles,
logo (data-URI) and accent colour all read live from settings; the accent is
validated before interpolation.
- **Public share links** — owner mints a 256-bit opaque token (default +30d
expiry, or never), lists and revokes. One unauthenticated route
`GET /share/:token` mounted outside `/api`, per-IP rate-limited (30/60s),
renders the one document inline as PDF; unknown/expired/revoked tokens return a
data-free "link unavailable" page. Tokens are never logged or audited.
- **Email (Gmail)**`gmail-connect` loopback OAuth (send + readonly scopes)
stores an AES-256-GCM-encrypted refresh token. Sends go over the Gmail REST API
(no SDK): access-token exchange, raw MIME build with PDF attachment, send.
`invalid_grant` flips the account to `dead` and raises the dashboard banner.
Document emails and templated reminder emails share the send path; every
attempt is logged.
- **Bounce handling** — polls the mailbox for mailer-daemon / postmaster DSNs
since the last poll, matches failed recipients against `email_log`, flips them
`bounced`, and raises an `email_bounced` reminder — idempotently.
- **Payments & allocations** — record payments (bank / upi / cheque / cash /
other) with TDS, allocate oldest-invoice-first or explicitly (never exceeding
outstanding or settling power), TDS pooled with cash as settling power,
advance-on-account computed on read, settlement status auto-flip
(part_paid / paid), credit-note-aware outstanding, RECEIPT generation, and a
pro-rata per-module billed-vs-settled view.
- **Recurring billing** — monthly/yearly plans priced by amount or price book,
auto/manual policy. Generation in the daily scan is transactional (claim +
issue invoice + advance `next_run`, all-or-nothing) and at-most-once per period;
auto plans send strictly after commit.
- **AMC contracts** — create / patch / deactivate, paid state derived from the
linked invoice's settlement (or a `legacy_paid` manual flag for imports), and
one-click renewal-invoice generation against the seeded AMC module.
- **Interactions** — seven seeded interaction types, logging with outcome and an
optional follow-up date that feeds the daily scan.
- **Reminders & scheduler** — a deterministic daily scan (clock injected) detects
`invoice_overdue`, `renewal_due`, `amc_expiring`, and `follow_up`, plus recurring
generation; every reminder goes through `INSERT OR IGNORE` on its idempotency
key, so catch-up after downtime is safe. Manual queue with send / dismiss /
preview; templated emails in `reminder-templates.ts`. The scheduler ticks on
boot and every 6h (`unref`'d), also running the bounce poll and the monthly AWS
cost pull.
- **AWS cost recovery** — per-client per-month usage & cost, entered manually by
the owner or pulled from Cost Explorer. The pull is SigV4-signed with
`node:crypto` (no SDK), grouped by the `client` cost-allocation tag, assumes
INR, upserts one row per (client, month), and is gated to once per calendar
month. Cross-client cost ranking and per-client cost aggregation are exposed.
- **Reports** — dues aging (030 / 3160 / 6190 / 90+ buckets), module revenue
(billed vs settled), client profitability (billed / settled / AWS cost /
margin), and the AWS cost ranking.
- **Dashboard view** — "today's money": overdue invoices, recurring due this
week, renewals this month, follow-ups today, recent payments, the live reminder
queue, and headline totals.
- **Settings / letterhead** — owner-editable company profile (GSTIN & state-code
validated) and template text (terms, declaration, jurisdiction, footer,
signatory label, per-type titles), logo upload (base64 PNG/JPEG/GIF/WebP/SVG,
≤200 KB), and a live sample preview through the one real renderer.
- **Audit trail** — every mutation writes a before/after row; ids are
monotonically-bumped UUIDv7 so same-millisecond writes stay strictly ordered.
- **APEX importer** — stage `clients.csv` + `invoices.csv` (each row carries its
own problem list), a verification report, and a commit that refuses to run
while any staged row has problems; commit marks rows `source='apex'` and seeds
the INVOICE series past the legacy numbers. CLI:
`npm run import -- --dir <folder> [--commit]` (dry-run without `--commit`).
## Frontend screens (`apps/hq-web`)
Shell (`Layout.tsx`): left nav, top bar with theme switcher + logout, and a
Gmail-disconnected banner. Nav is Dashboard / Clients / Modules / Reports / New
Document, plus **Document Template** for owners. Routes (`main.tsx`):
| Route | Screen | What it does |
| --- | --- | --- |
| `/login` | `Login` | Email + password sign-in |
| `/` | `Dashboard` | Money headline cards, the reminder queue with send / preview / dismiss, and overdue / due-this-week / renewals / follow-ups / recent-payments tables |
| `/clients` | `Clients` | Search, list, inline new-client create; row → client 360° |
| `/clients/:id` | `ClientDetail` | Client 360°: header + status, module assignment & lifecycle, documents, payments & dues (record payment, advance), recurring plans (owner), AMC contracts (owner), interaction log with follow-ups, and 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/: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 |
The composer, quote-content, and template previews all use one `LivePreview`
component that renders the server's real `documentHtml` in a sandboxed
double-buffered iframe — the on-screen paper is the same HTML puppeteer
rasterizes for the PDF.
## Known gaps / not yet wired
- **Gmail is not connected in production yet** — until `gmail-connect` is run,
document sends and auto-reminders queue to the manual dashboard queue and the
disconnected banner shows.
- **AWS cost pull is env-gated** — the scheduled and manual pulls run only when
`AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` are configured; otherwise usage
is owner-entered by hand.
- **No staff-management UI/API**`createStaff` exists but is only reachable via
seed/code; there is no in-app way to add or deactivate console users.
- **APEX import is CLI-only** — no web UI for staging/commit.
- **Reminders live on the Dashboard** — there is no standalone reminders page,
and there is no separate documents-list page (documents are reached from the
client ledger and the dashboard).
- **A few tax/identity defaults are provisional** — the seeded company state code
(`32`, Kerala) and several SAC codes carry "founder / CA to confirm" notes.

@ -51,7 +51,7 @@ Multi-counter stores need counters to see shared stock/bills when internet is do
(a checkbox, not a separate device) from Phase 2.
## D8 — Android POS terminals (Sunmi-style) in scope? ✅ RESOLVED
Settled by the market-architecture brainstorm ([08-MARKET-ARCHITECTURES.md](08-MARKET-ARCHITECTURES.md)):
Settled by the market-architecture brainstorm (08-MARKET-ARCHITECTURES.md, in the Store repo):
every player winning high-throughput counters is desktop + local-first; Android wins
micro-merchants and mobility. **Decision:** v1 = Windows desktop POS; Phase 34 = Android
*companion* app (line-busting, stock-take, approvals) sharing the billing-engine package;
@ -76,7 +76,7 @@ then the cloud tier is added and switched on per store. Accepted consequences: o
Purchase Inbox, WhatsApp, central backup, silent auto-update, and HQ fleet features all
wait for the cloud workstream. Guardrail (non-negotiable): client UUIDs + dormant outbox
rows are written from the first local build, so cloud enablement is switch-on, not
migration. See the staging note atop [04-ROADMAP.md](04-ROADMAP.md).
migration. See the staging note atop 04-ROADMAP.md (in the Store repo).
## D11 — Existing team & hiring plan (partially answered)
Founder input (2026-07-08): a support team exists for Classic and continues; the product

@ -2,7 +2,7 @@
Founder review question (2026-07-09): *"how are the support sections, and are there admin
pages/settings — default settings, multi-tenant settings, etc.?"* Verdict: the tenant-side
Admin module is specified in [09-UX-FLOWS-AND-MENUS.md](09-UX-FLOWS-AND-MENUS.md) (§2 menu
Admin module is specified in 09-UX-FLOWS-AND-MENUS.md (in the Store repo) (§2 menu
tree → Admin; §5.7 error-code support handshake; print-profile remote fixes in §5.4). What
was **missing** is the vendor side — the console *our* team and dealers use to run the
whole fleet. This doc fills that gap and consolidates the settings model.

@ -138,7 +138,7 @@ the primary mechanism. HQ-3 also ships the **cross-client AWS cost chart**: clie
ranked by monthly cost and share of total, each client's rank surfaced on their
Client 360° — the founder's "where do they sit in the AWS cost chart" view.
## 6. Phasing (mirrored in [04-ROADMAP.md](04-ROADMAP.md))
## 6. Phasing (mirrored in 04-ROADMAP.md, in the Store repo)
| Phase | Ships |
|---|---|

2924
package-lock.json generated

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save