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.
sims-hq/docs/14-SPEC-HQ-CONSOLE.md

165 lines
12 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 14 — SPEC: HQ Console (internal ops app) — started early
Founder requirement (2026-07-09): an **internal tool for running our own software business**
~300 existing clients, 6 sellable modules, quotations/proforma/invoices "in minutes",
recurring bills with auto/manual email reminders, per-module payment + AMC tracking,
per-client AWS usage & cost, and the full client memory (installation, training, visits,
calls, meetings, sales outcomes) that today lives partly in an Oracle APEX app and partly
in people's heads.
**Decision (D15, [06-DECISIONS.md](06-DECISIONS.md)):** this is the
[doc-11 HQ Console](11-ADMIN-SUPPORT-CONSOLE.md) **started early** — built in this
monorepo as a new cloud app, aimed first at the *current Classic client base*, replacing
the APEX app entirely. Roughly 70% of the requirement (tenant directory, subscription
state, renewals pipeline, dunning, our own GST invoices, support notes) was already
specified in doc 11; this spec adds the missing 30% (quotations/proforma from letterhead
templates, AMC, AWS cost attribution, interaction/visit logs) and re-sequences delivery.
Approved via brainstorm 2026-07-09. Alternatives rejected: separate codebase (rebuilds
GST engine/UI/patterns and builds doc-11 twice); off-the-shelf CRM (no module-level
tracking against our catalog, no AWS attribution, no path to the fleet console).
## 1. Shape
| Aspect | Call |
|---|---|
| App | `apps/hq` — Node server + web app + JSON API, same pattern as `apps/store-server` |
| Hosting | Small AWS instance (Mumbai), HTTPS; store product stays local per D14 — this is vendor-side cloud, which doc 11 already prescribes |
| DB | SQLite (WAL) behind portable repositories (`repos.ts` pattern); nightly + on-change backup to S3; restore drill scheduled. **This database is the nucleus of the future cloud tier** — at HQ-4 the tenant registry grows *from* it (same rows, same UUIDs), never beside it; there is never a second client list to reconcile. Consider swapping the engine to Postgres at AWS deploy time (cheap behind the repos; removes even the engine migration later) |
| Reuse | `@sims/billing-engine` **compute engine** (our invoices are GST documents — computed to the paisa), `@sims/domain` money/FY/UUIDv7 helpers + doc series (**generalized in HQ-1**: scope becomes an opaque key, separator/width configurable, 16-char GST rule kept — today it is per-counter), `@sims/ui` (design system), `@sims/auth` patterns (scrypt, lockout). HQ defines its **own document/payment types** — quotation/proforma/credit-note and B2B payment modes (NEFT/cheque) don't exist in the retail document model; shared packages stay generic (D15) |
| Auth | Email + password (scrypt), optional TOTP for owner; roles: **Owner** (everything incl. pricing/finance), **Staff** (operations; finance edits owner-gated). Small team — same people do sales, accounts, support |
| Audit | Every action logged — same discipline as the store product |
| Email | **Gmail API on the company mailbox** (OAuth app published to **Production** status; the grant belongs to the company mailbox account, refresh token stored encrypted): mails send as us, appear in Gmail Sent, replies land in the normal inbox; every send logged against its document. **Token death is a first-class failure**: on `invalid_grant` auto-sends halt, pending items flip to the manual queue, a persistent dashboard banner + a non-Gmail fallback alert reach the owner, and one-click **Reconnect Gmail** re-authorizes |
| PDFs | HTML/CSS templates matching the existing APEX/letterhead designs, rendered server-side (headless Chromium); stored on disk + S3 |
## 2. Data model (core tables)
- **client** — the registry, imported from APEX: name, GSTIN, address, multiple contacts,
status (lead / active / dormant / lost), notes. *Identity rule for the doc-11 future:
`client.id` (UUIDv7) becomes/links `tenant_id` when the cloud tenant registry stands
up (HQ-4) — same records and ids, promoted once, never re-entered; lead/dormant/lost
states stay HQ-only.*
- **module** + **module_price_book** — the 6 sellable modules, editions, dated prices
(a price change is a row, not a release — D5 philosophy; named apart from D5's product
`price_book` deliberately). `module` declares its **allowed subscription kinds** and
whether a client may hold **multiple concurrent subscriptions** of it (a per-module
flag — some modules allow several, others exactly one). At HQ-4, SiMS Next plans join
this catalog carrying their D5 `plan_code`, so licensing stays single-sourced.
- **client_module** — the heart. Per client × module: lifecycle status
(*quoted → ordered → installing → installed → trained → live → renewed / expired /
cancelled*), key dates (installation started/completed, payment received, training
given), subscription kind (one-time / monthly / yearly / usage-based — must be one the
module allows), current plan, next renewal date. Where the module permits
multi-subscription, several active rows per client × module may exist; Client 360°
rolls them up into one module line.
- **document** — quotation / proforma / invoice / receipt / **credit note** (the
GST-compliant correction path: a credit note with its own per-FY series and negative
lines links to the invoice it amends — issued invoices are never edited or deleted,
CGST Act s.34). Per-FY number series per type (e.g. `QT/26-27-0001`), line items
priced from module_price_book (editable), GST via billing-engine, stored PDF, status
trace (*draft → sent → accepted → invoiced → paid / part-paid / lost / **cancelled***
— a cancelled invoice keeps its number consumed in the series). One-click conversion
QT → PI → INV carries lines forward.
- **payment** — mode + reference, with a **payment_allocation** child (payment ×
invoice, optionally per line): default allocation oldest-invoice-first, pro-rata
across its lines, overridable at entry — this is what makes the per-module
paid/not-paid view deterministic. A **TDS-deducted** field treats amount + TDS as full
settlement (the 194J reality of Indian B2B); unallocated payments sit as **advances**
applied to future invoices.
- **recurring_plan** — scope (client or client_module), cadence, amount or usage formula,
next_run, policy: **auto-send** or **queue-for-manual-send**.
- **amc_contract** — client, coverage, period, amount, renewal date. AMC renewals are
**invoiced as documents**; paid status is *derived* from linked payments (a manual
flag exists only for imported legacy contracts) — one source of truth, no drift.
- **interaction** — typed from a user-extensible lookup (seeded: call / site visit /
training / courtesy meeting / committee meeting / demo / complaint):
date, who, notes, outcome (positive / neutral / negative), follow_up_date → feeds the
daily follow-ups queue. *The "memories into the system" table.*
- **aws_usage** — per client per month: data stored/transferred, cost ₹ (see §5).
- **email_log** — every outbound mail: recipient, subject, linked document, Gmail
message-id, status. Full traceability.
- **audit** — everything.
## 3. Flows
**Quotation in minutes:** New Quotation → type-ahead client → tick modules/plans →
prices prefill from module_price_book (editable) → GST auto-computed → live PDF preview
on letterhead → Send (Gmail) or Download. Same flow for proforma & invoice; conversions are
one click. Recording a payment marks the invoice (part-)paid; optional receipt.
**Reminders & recurring:** a daily scheduler scans `recurring_plan.next_run`, overdue
invoices, renewals due in N days, AMC expiring, follow-ups due. On next_run it
**generates the invoice** (lines from the plan's amount or usage formula, GST via
billing-engine, letterhead PDF) and then auto-emails or queues it per the plan's policy;
next_run advances only once the invoice exists. Each rule configurable: auto-send the
templated email, or queue on the dashboard for one-click manual send — both modes exist
per the founder requirement. **Scheduler semantics:** an idempotency key per
(rule, due-period) makes every send at-most-once across crashes and catch-up after
downtime; a failed send never advances the schedule — the item lands in the manual queue
with its error visible; a bounce-detection pass polls the mailbox for delivery-status
notifications and flags stale client contacts on the dashboard ("sent" ≠ "delivered").
Dashboard home = today's money: overdue, due this week, renewals this month, follow-ups
today, recent payments.
**Client 360°:** one page per client — modules with status timeline, all documents with
payment state, AMC, renewals, every interaction, AWS usage trend. The whole relationship
in one scroll.
## 4. APEX migration (replace fully)
One-time importer reading the APEX app's Oracle tables (node-oracledb thin, same as D12
tooling) → staging → verification report (counts + eyeballed samples) → import clients,
module assignments, statuses, open dues, and historical bills as history-only documents
(no PDFs regenerated). **Trial run, verify, then final cutover; APEX goes read-only.**
No double entry at any point.
**GST series continuity at a mid-FY cutover:** each per-FY document series is **seeded
from the last APEX-issued number** of the current FY (or switches to a distinct new
prefix — confirm with the CA, same session as Open item 4). Imported documents carry a
`source=apex` flag, keep their original numbers, and are exempt from the new-series
constraint while still collision-checked.
## 5. AWS usage & cost per client — automated
Nightly job pulls AWS Cost Explorer (cost-allocation tags per client) plus storage/
bandwidth metrics for shared resources, allocating shared cost proportional to usage.
Stored monthly per client; Client 360° shows usage trend and **cost vs. what they pay
us** (margin per cloud client). **First implementation step is a feasibility check:**
how cleanly are current cloud resources separable per client? Where tagging is
impossible, that portion falls back to proportional allocation — never manual entry as
the primary mechanism. HQ-3 also ships the **cross-client AWS cost chart**: clients
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))
| Phase | Ships |
|---|---|
| **HQ-1** | App skeleton + auth + audit; client registry (APEX import + verification); module catalog + module_price_book; client_module tracking; **quotation/proforma/invoice generation + letterhead PDF + Gmail send + payment recording (allocation + TDS + advances) + document traceability**; credit notes + cancelled status; per-FY series seeded from APEX at cutover; Gmail token-death handling |
| **HQ-2** | Recurring plans (invoice generation on next_run); reminder engine (auto + manual queue, idempotent, bounce-aware); AMC contracts; dashboard (money view + follow-ups); interaction/visit/call/training log |
| **HQ-3** | AWS usage & cost automation + margin view + cross-client cost chart (rank/share); reports (dues aging, module-wise revenue, client profitability); Client 360° polish |
| **HQ-4** | Convergence with doc-11 fleet features when SiMS Next ships: migration tracker, fleet dashboards, support queue — on the same client registry, no rebuild |
All founder-listed capabilities land somewhere in HQ-1…4; phase numbers order delivery,
nothing is dropped. HQ-1's headline is the founder's stated top pain: documents in minutes.
## 7. Non-goals (v1)
Dealer portal; impersonation; client-facing portal; WhatsApp sending (email first — the
message templates live in one place so WhatsApp can be added as a channel later);
double-entry accounting (payments feed reports, books stay in the existing accounting
tool); mobile app (the web app must simply work well on a phone browser).
## 8. Open items
1. **AWS tagging feasibility check** (gates HQ-3 automation depth).
2. **Template capture**: export the current APEX/letterhead quotation + invoice layouts
so the HTML templates match them.
3. **Gmail OAuth setup**: Google Cloud project **published to Production**, consent
granted by the company mailbox account (owner action; the grant — and any revocation
— follows that account).
4. **CA session**: SAC codes per module, place-of-supply for out-of-state clients
(IGST — the engine already handles CGST/SGST vs IGST), credit-note fields, and the
mid-FY series-continuity call (seed from APEX vs new prefix).
5. **APEX schema walk-through** with whoever maintains it, before writing the importer.