Skip to content

PRD: Finance accounts & ledger

ModuleFinance (CORE-12)PRD IDPRD-WAL-001
StatusIn-progressOwnerFinance squad
Date2026-06-04Versionv0.1
Packages@nx/finance · @nx/ledgerURDWAL · TXN

TL;DR

Gives a merchant a first-class home for its money: typed accounts (cash, bank, QR, mobile-POS) that carry a running balance, plus the internal control accounts (Inventory, Cost of Goods Sold) the system maintains for itself. Every voucher posts balanced debit/credit ledger lines against those accounts, each line carrying a balance-before/after snapshot - so an owner can trace where money lives and how each posting moved it.

1. Context & Problem

The Finance module (URD §1) tracks money across accounts, records every movement as a balanced double-entry voucher, and posts most movements automatically. None of that has a place to live until the accounts and ledger lines exist. Without typed accounts there is no running balance to route automatic postings to, and without ledger lines there is no per-account, balanced audit of how each voucher moved money.

This work lays the foundation: the accounts (WAL) that hold money and carry a running balance, and the ledger lines (TXN) every voucher posts against them. It also introduces non-cash internal control accounts (Inventory, Cost of Goods Sold) the system maintains for itself, so cost-of-goods and stock-adjustment postings have somewhere to land.

2. Goals & Non-Goals

Goals

  • Hold typed accounts (Cash, Bank, QR, Mobile-POS), each owned by one merchant, each with a running balance.
  • Maintain exactly one default account per type per merchant for routing automatic postings.
  • Seed each merchant's default accounts and the internal Inventory / Cost-of-Goods-Sold control accounts when the merchant is created.
  • Post debit/credit ledger lines against accounts, each carrying its account, amount, and a balance-before/after snapshot, in the voucher's currency.
  • Link accounts to payment integrations (referenced, not auto-included).

Non-Goals

  • Payment-gateway processing - owned by the Payment module; finance only links to integrations.
  • The full voucher lifecycle and auto-posting rules (VCH) and category taxonomy (CAT) - tracked by their own features.
  • Budget tracking, profit & loss, and cash-flow forecasting.
  • Multi-currency conversion within a single voucher (single currency per voucher, default VND).

3. Success Metrics

MetricTarget / signal
Account coverageEvery merchant has its default and internal control accounts after creation
Default uniquenessExactly one default account per type per merchant; zero duplicates
Balance integrityAccount running balance equals the sum of its posted ledger lines
Snapshot completenessEvery ledger line carries a balance-before/after snapshot in the voucher's currency

4. Personas & Use Cases

PersonaGoal
OwnerSee where money lives across cash, bank, QR, and mobile-POS accounts and reconcile balances
Accountant / ManagerRead the per-account ledger and trace each movement to its source document
System (worker)Auto-seed accounts on new merchant and post balanced ledger lines for every voucher

Core scenarios: a merchant is created → default and internal control accounts are seeded → vouchers post debit/credit ledger lines against those accounts → each account's running balance updates and each line records a balance-before/after snapshot.

5. User Stories

  • As an owner, I want typed accounts for cash, bank, QR, and mobile-POS, so I can see where my money lives and its running balance.
  • As an owner, I want one default account per type, so automatic postings route to a predictable account.
  • As the system, I want a new merchant's default and internal control accounts seeded automatically, so cost-of-goods and stock postings have somewhere to land from day one.
  • As an accountant, I want each voucher to post balanced ledger lines against accounts with a balance snapshot, so I can audit how every movement changed an account.
  • As an owner, I want an account to reference its payment integration, so a QR / mobile-POS account ties back to its gateway without auto-pulling integration data.

6. Functional Requirements

#RequirementURD ref
FR-1Hold accounts of types Cash, Bank, QR, and Mobile-POS, each owned by one merchantURD-WAL-001
FR-2Maintain a default account per type per merchant for routing automatic postingsURD-WAL-002
FR-3Auto-create each merchant's default and internal control accounts (Inventory, Cost of Goods Sold) when the merchant is createdURD-WAL-003
FR-4Track each account's running current balance as vouchers postURD-WAL-004
FR-5Allow account currency (default VND)URD-WAL-005
FR-6Restrict account visibility to merchants the user is granted; admins see allURD-WAL-006
FR-7Each voucher posts debit/credit ledger lines against accountsURD-TXN-001
FR-8A line carries the account it affects, an optional category, an amount, and a balance-before/after snapshotURD-TXN-002
FR-9Ledger lines share the voucher's currencyURD-TXN-003
FR-10A line may reference its source document for traceabilityURD-TXN-004

Full requirement text and acceptance criteria live in the Finance URD. This PRD references them rather than restating them.

7. Non-Functional Requirements

AreaRequirement
Data integrityAn account's running balance and the ledger lines that move it are written together; balance equals the sum of posted lines
Default uniquenessExactly one default account per type per merchant, enforced at the model level
Tenancy & authzAccounts are merchant-scoped (x-merchant-id); non-admins see only granted merchants, admins see all
PrecisionMonetary math uses float(value, 4); balances stored with the same precision
ConsistencyAccount seeding and ledger posting are idempotent and transactional; a repeated merchant event never double-seeds
i18nUser-facing labels/types are bilingual ({ en, vi })

8. UX & Flows

Key screens (in apps/client): account list / filter / form (incl. bank type), voucher select-account-by-currency, and the ledger table / filter / show page with a PDF view.

9. Data & Domain

EntityRole
Account (finance-account)A money account - type (Cash/Bank/QR/Mobile-POS), owning merchant, running balance, currency, isDefault per type, optional payment-integration relation
Internal control accountA non-cash account (Inventory, Cost of Goods Sold) the system maintains for cost/stock postings
LedgerLineA debit/credit row - affected account, optional category, amount, balance-before/after snapshot, voucher currency, source-document reference
Ledger config / jobPer-merchant ledger settings and the draft ledger job (with websocket progress)

Conceptual only - full schema and invariants in the finance domain model.

10. Dependencies & Assumptions

Depends on

  • Commerce (Merchant) - a new merchant's accounts are reconciled automatically on creation.
  • Vouchers & posting (URD-VCH) - vouchers are what post ledger lines against accounts.
  • Payment (@nx/payment) - accounts reference payment integrations (linked, not auto-included).

Assumptions

  • A merchant-created event is delivered to the finance worker so accounts can be seeded.
  • Internal control accounts exist before any cost-of-goods posting is attempted.

11. Risks & Open Questions

Risk / questionMitigation / status
Account balance and ledger lines could divergeWritten transactionally; balance equals the sum of posted lines, snapshotted per line
Repeated merchant event could double-seed accountsSeeding is idempotent - a repeated event never creates a second default account
isDefault per-type uniquenessEnforced at the model level after initial template/model fixes
No multi-currency within a voucherOut of scope; single currency per voucher (default VND)

12. Release Plan & Launch Criteria

AspectPlan
PhaseP1 (foundation) - see URD feature catalog
RolloutAll merchants; no feature flag
MigrationSeed migration for default finance accounts; internal control accounts seeded per merchant
Launch criteriaNew merchant gets default + control accounts; ledger lines post balanced with balance snapshots; account balance equals the sum of its lines
MonitoringPer-merchant account count, default-uniqueness checks, balance-vs-ledger-sum consistency

13. FAQ

What account types exist? Cash, Bank, QR, and Mobile-POS - plus non-cash internal control accounts (Inventory, Cost of Goods Sold) the system maintains for itself.

What is an internal control account? A non-cash bookkeeping account - not the merchant's money - that gives cost-of-goods and stock-adjustment postings a place to land.

How does a default account get chosen? Exactly one account per type per merchant is flagged default; automatic postings route to it.

What does a ledger line record? The affected account, an optional category, an amount, the voucher's currency, a balance-before/after snapshot, and an optional source-document reference.

Does linking an account to a payment integration pull integration data in? No - the relation is a reference; integrations are not auto-included in the account.

References

Proprietary and Confidential. Unauthorized copying, distribution, or use of this software is strictly prohibited.