Architecture decisions
The backend records every significant design choice as a numbered Architecture Decision Record (ADR). This page is a map, not a replacement: it groups the records by theme and gives a one-line decision for each so you can find the right one fast. The records themselves are the source of truth and live in the backend repo under NexisOmni/docs/adr/ (files 0001-*.md through 0023-*.md).
How to read an ADR
Section titled “How to read an ADR”Each file follows the same shape: a status line (Accepted, Proposed, or superseded-by), the date and decider, the context that forced a choice, the decision itself, and the alternatives rejected. A Status of “superseded by ADR-00xx” means part of that record has been overtaken - always follow the pointer forward to the current decision.
Platform and tenancy
Section titled “Platform and tenancy”The database-per-tenant foundation, how tenants are placed and scaled, and how schema changes reach every tenant database.
| ADR | Title | Decides |
|---|---|---|
| 0001 | Adaptive multi-vertical API model | One API drives supermarket, bakery, cafe, and boutique terminals via a per-outlet BusinessType plus capability flags. |
| 0012 | Pragmatic layering | Business services live in Infrastructure as concrete classes with a near-empty Application ring; EF Core is the unit of work (no MediatR, no per-service interfaces). |
| 0013 | Per-tenant module entitlements | Whole modules are enabled or disabled per tenant from a central Tenant.Plan plus overrides, enforced by authorization policy, no tenant-DB migration needed. |
| 0020 | Tenant connection-pool bounds and manual-context audit | A shared context provider stamps bounded connection pools on every tenant context and defines which admin paths are audited. |
| 0021 | Tenant migration fan-out runner | An admin-plane runner applies pending migrations to every tenant database in-process; once a first production tenant exists, InitialCreate is frozen and changes become additive forward-only. |
| 0022 | Tenancy scaling strategy | Per-tenant isolation tiers (dedicated vs shared schema-per-tenant), a connections-based capacity ceiling, multi-server placement, and a safe graduation path between tiers. |
Auth and security
Section titled “Auth and security”The two authentication planes, how tokens are signed and secrets protected, and the permission and account-lifecycle model.
| ADR | Title | Decides |
|---|---|---|
| 0014 | Auth and secret hardening | RS256 JWT signing keys with rotation, and tenant connection strings encrypted at rest in the central database. |
| 0016 | Enterprise security model | Verb-based permissions resolved per request (never baked into the token), per-user branch scoping, an audit trail, lockout, and 2FA. |
| 0017 | Bounded role tiers and role management | Three seeded roles - Owner (the only holder of the global.admin override), a bounded Manager, and Cashier - plus tenant-managed roles. |
| 0018 | Transactional email and email-2FA | A swappable email transport (Resend) with a no-op fallback, enforced email confirmation on the tenant plane, enumeration-safe password reset, and email as an opt-in second factor. |
Sales and operations
Section titled “Sales and operations”The cash-drawer backbone, the offline-first sales layer, returns after settlement, and the read-only reporting layer.
| ADR | Title | Decides |
|---|---|---|
| 0002 | Operations and cash | Register, CashSession, and a typed CashMovement ledger - the accountable open-float-count-reconcile cash lifecycle, universal across all verticals. |
| 0003 | Sales and offline sync | The Order / OrderLine / Payment aggregate with frozen price and stacked-levy tax snapshots, per-branch receipt numbers, and idempotent offline POS replay. |
| 0008 | Returns and refunds | Single-shot post-settlement returns that refund pro-rata of the snapshotted sale and reverse money, stock, loyalty, and promotion effects, with a race-safe over-return guard. |
| 0007 | Reporting and analytics | Read-only, computed-on-read reports over snapshotted figures, with a per-request IANA timezone parameter and Manager-gated financial reads. |
Catalog and inventory
Section titled “Catalog and inventory”How stock is costed, depleted, and moved between branches.
| ADR | Title | Decides |
|---|---|---|
| 0010 | FIFO inventory costing and COGS | Exact FIFO depletion via a per-consumption ledger that captures COGS on sale and reverses precisely on void or return. |
| 0011 | Inter-branch stock transfers | A Draft-Dispatched-Received transfer lifecycle that moves the exact FIFO cost layers with the goods, preserving the on-hand invariant at both branches. |
Purchasing and suppliers
Section titled “Purchasing and suppliers”The inbound supply side that feeds inventory and costing.
| ADR | Title | Decides |
|---|---|---|
| 0009 | Purchasing and goods receipt | Supplier - Purchase Order - Goods Receipt, where a PO is intent and only a receipt moves stock, recording actual lot cost as the valuation basis. |
Marketing and credit
Section titled “Marketing and credit”Discounts and loyalty at the register, and the credit and installment model with its ceiling.
| ADR | Title | Decides |
|---|---|---|
| 0004 | Credit (the Singer model) | First-class Customer and CreditAccount with hire-purchase and layaway, flat financing interest, an installment schedule, and layaway stock reservation. |
| 0005 | Marketing - discounts, promotions, loyalty | Manual discounts plus a rule-based promotion/coupon/BOGO engine and loyalty points and tiers, with a configurable, default discount-before-tax treatment. |
| 0023 | Owner-governed credit ceiling | Moves the per-tenant credit ceiling to its own Owner-only CreditSettings, enforced at both grant time and lending time. |
Cross-cutting and contract
Section titled “Cross-cutting and contract”The wire contract both frontends generate from, and email decisions that span planes.
| ADR | Title | Decides |
|---|---|---|
| 0006 | Post-roadmap feature roadmap (Phases 7-10) | Sequences reporting, returns, purchasing, and stock transfers, fixing scope and dependencies for each. |
| 0015 | Frontend API contract | Money and decimals are quoted JSON strings on the wire, the OpenAPI document declares the two bearer planes and the Tenant-ID header per operation, and sync acks carry the server receipt number and totals. |
| 0018 | Transactional email and email-2FA | The platform email transport and the account-email lifecycle (also listed under Auth and security). |
| 0019 | Tenant customer email | A backlogged plan for owner-configurable, business-branded customer email (transactional and marketing) - recorded but not yet built. |
Status at a glance
Section titled “Status at a glance”Most records are Accepted and implemented. A few carry pointers you should follow:
- ADR-0016’s original single-role model is superseded by ADR-0017 (Owner / Manager / Cashier), and its authenticator-only 2FA by ADR-0018 (email confirmation and email-2FA).
- ADR-0014’s “email deferred” item is superseded by ADR-0018.
- ADR-0019 (tenant customer email) is Proposed and backlogged - a settled design, not built.
Where the records live
Section titled “Where the records live”The canonical files are in the backend repo at NexisOmni/docs/adr/, one Markdown file per record, named by number and slug (for example NexisOmni/docs/adr/0014-auth-and-secret-hardening.md). For the broader backend orientation see the developer guide at NexisOmni/docs/developer-guide.md, and for how the contract binds the web and POS clients see the API contract.