You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
76 lines
6.2 KiB
Markdown
76 lines
6.2 KiB
Markdown
# 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 / Pipeline / Clients / ClientDetail / Modules / Reports / NewDocument / DocumentView / Employees (owner-only) / DocumentTemplate (owner-only) |
|
|
| 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_schedule` (reminder cadence + follow-up text, resolved by `resolveSchedule`), `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 (270 tests) |
|
|
|
|
## Running it
|
|
|
|
```
|
|
npm install # workspace root, once
|
|
# backend (serves API on :5182, and the built web UI + public /share links)
|
|
# RUN FROM THE REPO ROOT — the DB path resolves to ./data/hq.db from CWD, so
|
|
# `cd apps/hq && npm start` would boot a fresh empty DB in apps/hq/data instead.
|
|
npm run build --workspace @sims/hq
|
|
node apps/hq/dist/server.cjs # first boot on an empty data/ 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, 270 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.
|