|
|
# 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.
|
|
|
Two founder additions (2026-07-10): **quote content** — an optional per-module block of
|
|
|
"what's included" lines that flows into quotations under that module's line (editable
|
|
|
per document; modules without content print nothing extra) — and **packs**: named
|
|
|
purchasable variants offered as a pick-list, e.g. the SMS module sold as *SMS 50,000*
|
|
|
or *SMS 1,00,000* packs. A pack is a `module_price_book` row whose `edition` is the
|
|
|
pack name; the composer shows the module's packs with prices and the chosen pack name
|
|
|
prints on the document line.
|
|
|
- **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.
|
|
|
|
|
|
**HQ-1.5 (immediate follow-up to HQ-1):** per-module quote-content blocks and pack
|
|
|
pick-lists (SMS 50k / 1L style) in the composer and on the PDF (spec §2 module bullet).
|
|
|
|
|
|
## 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.
|