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/06-DECISIONS.md

16 KiB

06 — Open Decisions (founder calls)

Each has a recommendation; none is blocking to start Phase 0, all must be locked to exit it.

D1 — Product name & positioning vs "SiMS Classic"

New name, or "SiMS" with a generation marker? Recommendation: keep the SiMS brand (it carries your existing base's trust), market the rebuild as SiMS Next or SiMS 2 — the migration pitch is easier when it's "your SiMS, reborn" rather than a stranger.

D2 — POS shell REVISED (2026-07-09): web app first

Founder call: the product is a web app. POS and back office are browser apps served by the store-server on LAN (later the same apps served from cloud). Zero installs at counters — the Oracle Forms deployment model, modernized. Consequences:

  • Hardware routes through the store-server: web POS → HTTP → store-server → ESC/POS over TCP 9100 (printers + drawer). Scanners are keyboard-wedge (browser-native). Weighing scales: Web Serial API (Chrome/Edge) or a store-server serial bridge — spike item.
  • Electron shell is kept as an optional kiosk wrapper (~100 lines, already built) for counters that need true offline billing or locked-down kiosk mode; same web bundle inside.
  • Browser key conflicts (F11 fullscreen, F12 devtools): keymaps are DB config — the web preset leans on Numpad+ for cash-close and Chrome kiosk mode at counters.
  • Offline story for browser POS (PWA + IndexedDB bill queue) is a Phase-2 hardening item; v1 counters depend on the store-server over LAN, exactly like Classic depends on the Oracle server today.

D3 — Sync: buy (PowerSync / ElectricSQL) vs build (custom outbox)

Recommendation: spike both in Phase 0; prefer buying the transport if it handles per-tenant partial sync cleanly. The domain rules (immutable documents, per-counter series, derived stock) are ours regardless.

D4 — GSP vendor for e-Invoice / e-Way

ClearTax vs Masters India vs others. Decide on: API reliability, per-document pricing at your volume, sandbox quality. Recommendation: shortlist two, integrate behind our own interface so switching is a config change.

D5 — Pricing tiers RESOLVED (direction)

Founder call (2026-07-08): prices aren't fixed yet and must be addable/changeable in the DB so they reflect in the app without a release. Design adopted: plan, plan_feature, and price_book tables (see 07-DB-AND-CONFIG.md §2) — new plans and ₹ amounts are rows, the license token is a signed snapshot of them. Actual ₹ amounts get decided whenever you're ready; nothing blocks on it.

D6 — Accounting depth at launch

Full books (P&L/BS) in-app from Phase 2, or ledgers + Tally export first? Recommendation: ledgers + Tally export in Phase 2, full statements later. Most shops' CAs live in Tally; export buys goodwill for a fraction of the effort. Classic parity data should confirm how many customers actually used full accounting.

D7 — Store Hub (LAN sync box) as requirement or option

Multi-counter stores need counters to see shared stock/bills when internet is down. Recommendation: ship Store Hub as an optional role of the main billing PC (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, 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; full Android POS only if we later go down-market deliberately. D2 (Electron) stands.

D9 — Purchase Inbox channels at launch

Email-in + manual upload first; WhatsApp-forward intake later (needs WhatsApp Business API setup). Recommendation: email + upload in Phase 3, WhatsApp intake fast-follow.

D10 — Cloud region & provider

Any major provider with a Mumbai region works. Deciding inputs: managed-Postgres quality, egress pricing, your team's familiarity. Recommendation: pick boring; revisit never.

D13 — Support ticketing: build vs integrate (raised by 11-ADMIN-SUPPORT-CONSOLE.md)

The diagnostic bundle, error-code playbooks, and Store 360° are ours; the ticket queue itself is commodity. Recommendation: integrate a boring helpdesk in Phase 2; build only if the integration fights the error-code workflow.

D14 — Cloud staging RESOLVED: local-only first, cloud layered on later

Founder call (2026-07-09): v1 runs fully local (counters + in-store Oracle 12c per D12), then the cloud tier is added and switched on per store. Accepted consequences: owner app, 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 (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 principle is a stable frontend with changes flowing from backend/DB, handled by the team — adopted as the config-driven design in 07-DB-AND-CONFIG.md. Still needed to calibrate the roadmap: builder headcount and skill mix for the new stack.

D12 — Local DB engine RESOLVED (for now): Oracle 12c stays at the store tier

Founder call (2026-07-09): the in-store DB remains Oracle 12c — it is already deployed shared infrastructure with multiple other systems running on it, so for the existing base the license and operations cost is sunk. Analysis and the adapted design are in 07-DB-AND-CONFIG.md §3.

Consequences accepted with this call:

  • D3 resolves to "build": off-the-shelf sync engines (PowerSync/ElectricSQL) speak Postgres/SQLite only — sync is a custom outbox, with outbox tables living in Oracle and a store-side sync agent draining them to the cloud.
  • Counters still carry a local SQLite buffer (offline bill queue + item-search cache) so a counter survives store-server or LAN death — the "counter never stops" goal is independent of the store engine.
  • Backend connects via node-oracledb thin mode (no Oracle client install needed; supports 12.1+).
  • New code stays engine-portable: repository/DAL layer, portable SQL by default, Oracle-only features only with a written justification — "for now" must stay cheap to revisit.

Revisit triggers (any one reopens this decision): onboarding NEW customers who don't already have Oracle in-store (license cost is no longer sunk); the other systems sharing the DB migrate off 12c or upgrade (19c/23ai); a security/compliance audit flags the unpatched engine; or sync friction in Phase 01 proves materially costlier than an engine port. Risk register entries in 07 §3 remain on record.

D15 — Internal HQ ops console: build now RESOLVED (2026-07-09; split to its own repo 2026-07-16)

Founder call (2026-07-09): an internal tool for running our own ~300-client business — quotations/proforma/invoices in minutes, recurring billing with auto/manual email reminders, per-module payment + AMC tracking, per-client AWS usage & cost, and the full client interaction memory (installation, training, visits, calls, meetings, sales outcomes) in a system instead of heads. Decision: start the doc-11 HQ Console early, as apps/hq (built in the shared monorepo at the time; split into its own repo C:/SiMS/hq on 2026-07-16) — spec in 14-SPEC-HQ-CONSOLE.md. Cloud-hosted vendor-side (D14 untouched — the store product stays local); SQLite behind portable repositories with S3 backup; Gmail API sending from the company mailbox; automated AWS cost attribution; full replacement of the internal Oracle APEX app — one-time verified migration, then APEX goes read-only, no double entry. Reuses @sims/billing-engine (our invoices are GST documents), @sims/domain (paise money, FY, doc series), @sims/ui, and the @sims/auth patterns.

Alternatives rejected: fully separate codebase (rebuilds the 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).

Consequences accepted:

  • This shipped as two deployables with different release rhythms. On 2026-07-16 they were split into two independent repos (C:/SiMS/hq and C:/SiMS/store) — separate histories, deploy scripts, and versioning; the shared packages were forked into each.
  • Doc-11's phase mapping splits: the ops slice ships early (HQ-1…3 in 14-SPEC-HQ-CONSOLE.md §6); the fleet half is unchanged and waits for the cloud tier per D14.
  • One repo, two runtime-independent applications (founder re-confirmed 2026-07-10 after weighing a full split): separate servers, DBs, builds and deploys; only source packages are shared. Guardrails: a bundle-isolation check in the test suite (store bundle contains no HQ code and vice versa), per-app version tags, and the rule that HQ's DB is the cloud tier's nucleus — the tenant registry is born from HQ's client table (same UUIDs, promoted once), never built beside it. Postgres locked as the production engine (founder, 2026-07-10) — swap runs as its own task after HQ-2, before the real-data import, so live data never migrates engines; SQLite stays the dev/test engine behind the same repositories. Physical repo split stays a cheap, reversible option if practice ever demands it.

D16 — Quote-to-close funnel slice (2026-07-17)

Founder-approved design in superpowers/specs/2026-07-17-quote-to-close-funnel-design.md; decisions locked with it:

  • Employee foundation rides staff_user. The Employee entity is backed by the existing staff_user table — renaming it would churn session.staff_id, interaction.staff_id and audit entity names for zero gain; "Employee" lives in the repo/API/UI vocabulary only. Roles widened to owner | manager | staff via a guarded, transactional table rebuild (SQLite cannot ALTER a CHECK); the enum is validated in the repo. Session hardening rode along: verifySession requires active=1, and deactivation / password reset purge sessions in the same transaction.
  • Chase-list over kanban (option B). The pipeline is one cross-client ranked list — most-overdue on top, colour bands, an explicit next action per row, All | Mine | Overdue | Lost filters — not a kanban board.
  • Derived pipeline stages, zero new pipeline storage. Stage (Enquiry / New Project / Quoted-Waiting / Won / Lost) is never stored — computed from client.status + the client's latest live quotation; age anchors on the first sent document event. The only new column anywhere in the slice is client.owner_id (a bare lead has no creator to derive an owner from — A4).
  • Escalating owner+client reminders on the dated reminder_schedule table. New sendable quote_followup rule kind: the queued reminder row is the owning employee's nudge (owner derived doc_id → document.created_by), and its send is the client email with a public share link. Cadence and message text are dated config rows (rule 3) resolved by resolveSchedule — defaults 3/7/14 (quote) and 7/15/30 (invoice) ship as seeded rows plus code-constant fallbacks, so a cadence change is a new dated row, never a release. Catch-up fires only the highest crossed milestone; accept / lose / convert / cancel dismisses open nudges per-row (audited) in the same transaction; previews resolve shares read-only — minting happens only in the send path (60-day expiry, live links reused).
  • Convert recompute + duplicate-invoice guard (F3/F4). PROFORMA → INVOICE rebuilds the carried lines through computeBill on the invoice's own doc_date (a tax invoice uses the rate that is law on its issue date), and convertDocument rejects any source with a live (non-cancelled) forward child — one sale, one invoice number.
  • Proforma supersede matrix. Corrections stay firewalled by document type: a draft PI is simply re-drafted; an issued, unallocated PI may cancel (number stays consumed) and be recreated as a ref_doc_id-linked supersede; an issued INVOICE is never recreated — cancel-if-unpaid or credit note only.
  • Assumptions A1A7 (defaulted, flagged in the spec): A1 module roster balances support and revenue; A2 employees are a plain table (no org chart); A3 document owner = created_by for v1 (no document.owner_id until a handoff feature is real); A4 client.owner_id is the one genuinely new owner column; A5 notify-all text is owner-typed ad-hoc, not dated config; A6 roster visible to all staff, notify-all owner/manager only; A7 invoice-overdue anchors on doc_date (no due-date column exists).

Recorded deviation from the funnel spec's blanket pagination rule (§5 / rule 8): GET /employees returns the full set with total and no page/pageSize — console users are a small bounded set (single-digit headcount), the count is displayed, and nothing is silently truncated, which is the intent of rule 8. If the team ever grows past a screenful, paginate it like every other list.

Delivery state (2026-07-17, final): all ten phases landed. Phases 16 (employee foundation + management surface, owner plumbing, dated schedule, pipeline chase-list, escalating quote follow-up) plus the F3/F4 convert hardening, then 710 in the same day's second pass: one-click POST /documents/:id/convert-and-send (guards → one txn convert+issue → post-commit email), proforma POST /documents/:id/supersede, invoice dN milestone escalation (d7/d15/d30 from the dated schedule, F7 highest-only catch-up), and the module → client roster (GET /modules/:id/clients + CSV export + owner/manager Notify-all with per-recipient audit). Suite at 293 tests / 57 files.

D17 — HQ console visual redesign: warm ops-console (2026-07-17)

Founder-approved spec in superpowers/specs/2026-07-17-hq-console-redesign-design.md (delivered same day; adversarial multi-agent review + fixes recorded there). Decisions locked with it:

  • Direction: "Direction A v2 discipline wearing the H-04 warm palette." Synthesised from the two most recent design artifacts (the chosen Claude-Design "Direction A v2" system and the H-04 Client 360 mockup): warm paper neutrals (#FAFAF7/#E7E5DE/ #1A1A17), flat border-defined surfaces, shadows only on overlays.
  • Teal is the default accent; primary buttons are ink, not accent. Accent colour is reserved for state (active nav, chips, links, focus). The 6 previous accents stay switchable; dark mode is warm-tinted with explicit per-accent dark values.
  • Mono/sans split. JetBrains Mono for machine data (codes, doc numbers, GSTINs, ids); Inter with tabular numerals for money. Uppercase micro-labels never below 11px (WCAG).
  • Ctrl-K command palette over more nav. Client search + pages + actions in one keyboard-first overlay (generic CommandPalette in @sims/ui; AND-term matcher).
  • Client 360 = record header + KPI row + relationship-pulse ribbon + deep-linkable tabs — the ribbon plots documents / payments / interactions / AMC on one 12-month axis from data the page already loads (no chart lib, no new endpoints).
  • UI-only slice. No backend/schema changes; @sims/ui stays generic (no router or icon deps — lucide-react lives in apps/hq-web only). Known deferred: server-side "outstanding ₹" figure for the Client 360 KPI row (client-side paise math is banned).