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/superpowers/specs/2026-07-16-hq-store-split-d...

8.8 KiB

Split SiMS into two independent projects: HQ and Store

Date: 2026-07-16 Status: Approved, pending implementation plan

Why

C:/SiMS/Store Software currently holds two products that are not one product.

HQ (apps/hq, apps/hq-web) is internal: our client book, their projects, proforma-invoice billing, call tracking, AMC contracts, AWS cost recovery, payments and reminders. It is the commercial record of the business.

Store (apps/pos, apps/store-server, apps/backoffice) is the product we sell: GST retail management deployed on client premises.

They are independent projects and should be developed, deployed and released as such:

  • Different audiences. HQ is internal-only; Store ships to ~300 clients.
  • Different databases. Two SQLite schemas with no conceptual overlap. HQ: client, module, document, interaction, amc_contract, aws_usage, payment, reminder, staff_user. Store: item, batch, bill, purchase, stock_movement, party, counter, store, tenant. Four names collide (audit_log, doc_series, setting, tax_class) but they are different definitions in different DBs — shared in appearance only.
  • Different cadences. Of 75 commits, 60 touch HQ and 2 touch Store. The repo is already HQ wearing a Store name.
  • Confidentiality. A single tree means every Store branch, contractor handout, or repo copy carries our client book and revenue data in its history.

Decisions

# Decision Choice
1 Split shape Two separate git repos
2 Shared code Fork into each repo, trimmed to what each uses
3 History HQ inherits the existing 60 commits; Store starts fresh
4 Docs Trim each side to only what that repo needs
5 Repo name C:/SiMS/hq (keep — matches docs/14, DEPLOY-HQ.md, @sims/hq, 60 commits)
6 Project tracking Out of scope — split first, build after

Rejected: a third shared repo and a private npm registry. Both add versioning overhead to solve a divergence risk the evidence says does not exist (see below).

Target layout

C:/SiMS/
├── hq/                      ← current repo, 60 commits preserved
│   ├── apps/{hq, hq-web}
│   ├── packages/{domain, auth, billing-engine, ui}   ← trimmed, names kept
│   ├── docs/                ← HQ-only, renumbered
│   ├── DEPLOY-HQ.md
│   └── README.md, STATUS.md ← STATUS.md is new
└── store/                   ← fresh git init
    ├── apps/{pos, store-server, backoffice}
    ├── packages/{domain, billing-engine, auth, ui, config, scanning, search-core}
    ├── docs/                ← the remaining 15 docs
    └── README.md, STATUS.md, BUILDING.md

Each repo gets its own package.json (sims-hq / sims-store), tsconfig, vitest.config, .gitignore, and CLAUDE.md. Neither references the other at any point — no workspace links, no relative paths across roots, no doc citing a file it does not contain.

Shared code: fork, trimmed

HQ's dependency on shared packages is shallow and fully verified — utilities and a design system, no shared schema or business logic.

HQ keeps the package names (@sims/domain, @sims/auth, @sims/billing-engine, @sims/ui) and removes files underneath. Import specifiers are unchanged, so no import statement in HQ's app source changes — not one of apps/hq's 75 files or apps/hq-web's 14. What changes is narrow and enumerable: the four index.ts barrels (drop the removed export * lines), and apps/hq-web's package.json + vite.config.ts (drop the dead @sims/printing dependency and alias).

Package HQ keeps HQ drops
domain ids, money, business-day, doc-series, gstin, documents tenancy, masters, batch, outbox
auth pin lockout, permissions, session
billing-engine compute, tax returns, gst-returns (588 lines)
ui all 5 files
printing whole package

Store's packages/ is untouched.

Closure verification (done, 2026-07-16)

Every trim is a clean cut — verified by reading the imports, not by assumption:

  • compute.ts imports ./tax and four types from @sims/domain (BillLine, BillTotals, Paise, IsoDate) — all in files HQ keeps.
  • tax.ts imports only IsoDate.
  • documents.ts imports only from money and business-day.
  • pin.ts imports only node:crypto — no @sims deps.
  • ui has no @sims deps at all (react + its own theme).
  • Nothing HQ retains imports tenancy, masters, batch, or outbox. The reverse edges (batch → business-day, masters → money) are one-way and drop cleanly.
  • @sims/printing is declared in apps/hq-web/package.json and aliased in its vite.config.ts, but imported by no source file — a dead dependency.

Why forking is safe

The divergence risk for forked code is GST computation. It does not apply: tax rates are dated DB rows, not code. tax_class rows carry effective_from/effective_to and resolve by the bill's business date, with the Sept-2025 GST 2.0 slab change cited in tax.ts as the precedent. HQ reads its own tax_class table; Store reads its own. A rate change is a row insert per DB, never a code edit.

What remains in compute.ts is stable arithmetic — CGST/SGST/IGST split, rounding. It has no reason to change often, and the two products are entitled to diverge: HQ invoices software modules, Store bills retail goods.

History

The current repo becomes C:/SiMS/hq: all 60 HQ commits preserved, then one commit removing Store paths. No filter-repo surgery.

C:/SiMS/store gets git init and one clean initial commit. It loses only 2 commits (one titled wip) and gains a guarantee: zero HQ bytes in its history, permanently. This is the confidentiality boundary, and it is only real if the Store history starts empty.

Docs

Trimmed per repo — each doc cut to what that side actually needs.

HQ (renumbered 0004):

New From Treatment
00-HQ-CONSOLE-SPEC.md 14-SPEC-HQ-CONSOLE.md As-is
01-ADMIN-SUPPORT-CONSOLE.md 11-ADMIN-SUPPORT-CONSOLE.md As-is
02-PROJECT-RULES.md 16-PROJECT-RULES.md Trimmed: keep money, config-over-code, document rules; drop counter/POS rules
03-DECISIONS.md 06-DECISIONS.md Extract D15 + HQ-only calls
04-DB-AND-CONFIG.md 07-DB-AND-CONFIG.md Trimmed: D12 portable-repo pattern, dated tax-class config

Plus DEPLOY-HQ.md as-is, a rewritten README.md, and a new STATUS.md.

Store: the remaining 15 docs, with D15/HQ references pruned from 06-DECISIONS.md and the HQ rows removed from README.md's doc table.

HQ has no STATUS.md

The largest app in the repo (75 files, at go-live per DEPLOY-HQ.md) has no build-state doc. STATUS.md covers only the Store product. HQ's current state had to be reconstructed from source and git log. Write one during the split, covering the built surface: clients, modules and price book, documents (QT/PI/INV/CN) with templates/PDF/share links, interactions, AMC, AWS usage, payments, recurring plans, reminders with Gmail send and bounce handling, reports, dashboard, audit, APEX import, scheduler.

Verification

The split is done when, for each repo independently:

  1. node_modules removed and npm install run fresh
  2. npm run typecheck passes
  3. npm test passes
  4. No path resolves outside its own root

Typecheck is the real proof of the fork closure — a missed dependency fails immediately and loudly.

Additionally, confirm the confidentiality boundary holds rather than assuming it: searching C:/SiMS/store/.git for client, AMC, and AWS-cost terms must return nothing.

Out of scope

  • Project tracking. Listed as a core HQ concept but not built — no project table, no repo module, no UI. It is a feature to design and build, not code to move. Deferred so the split stays mechanical: pure move-and-verify, with no new feature to confuse a failure with.
  • Conversion reporting. client.status (lead/active/dormant/lost) exists but has no lead-to-won reporting on it. Wanted alongside the existing conversation log (interaction), but after the split.
  • Oracle 12c adapter (Store, pending Classic DDL) and the 46 wireframe back-office screens (Store) are unaffected by this work.

Risks

Risk Mitigation
A trimmed file is needed by something unread Typecheck on a fresh install in each repo catches it immediately
Store history retains HQ data Fresh git init, verified by searching .git
Docs cite files that no longer exist in their repo Grep each repo's docs for cross-references to removed paths
HQ's dead @sims/printing alias breaks its Vite build when dropped Remove from both package.json and vite.config.ts together; build verifies