PRD: Finance accounts & ledger
| Module | Finance | PRD ID | PRD-WAL-001 |
| Status | Ready to dev | FEAT | WAL |
| Epic | — | Plane | BANA-1498 |
| Date | 2026-06-04 | Version | v0.1 |
| Packages | @nx/finance | URD | WAL |
| Surface | Client · Owner/MgrBO · Ops | ||
| Owner | Phát Nguyễn | ||
TL;DR
A first-class home for a merchant's money: typed accounts (cash, bank, QR, mobile-POS) that each carry a running balance, plus the internal control accounts (Inventory, Cost of Goods Sold) the system keeps for itself. Every voucher posts balanced debit/credit ledger lines against them, each line snapshotting the balance before and after - 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 of them automatically - but none of that has anywhere to live until accounts and ledger lines exist. Without typed accounts there is no running balance to route postings to; 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 adds non-cash internal control accounts (Inventory, Cost of Goods Sold) the system keeps 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
| Metric | Target / signal |
|---|---|
| Account coverage | Every merchant has its default and internal control accounts after creation |
| Default uniqueness | Exactly one default account per type per merchant; zero duplicates |
| Balance integrity | Account running balance equals the sum of its posted ledger lines |
| Snapshot completeness | Every ledger line carries a balance-before/after snapshot in the voucher's currency |
4. Personas & Use Cases
| Persona | Goal |
|---|---|
| Owner | See where money lives across cash, bank, QR, and mobile-POS accounts and reconcile balances |
| Accountant / Manager | Read the per-account ledger and trace each movement to its source document |
| System | 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
| # | Requirement | URD ref |
|---|---|---|
| FR-1 | Hold accounts of types Cash, Bank, QR, and Mobile-POS, each owned by one merchant | URD-WAL-001 |
| FR-2 | Maintain a default account per type per merchant for routing automatic postings | URD-WAL-002 |
| FR-3 | Auto-create each merchant's default and internal control accounts (Inventory, Cost of Goods Sold) when the merchant is created | URD-WAL-003 |
| FR-4 | Track each account's running current balance as vouchers post | URD-WAL-004 |
| FR-5 | Allow account currency (default VND) | URD-WAL-005 |
| FR-6 | Restrict account visibility to merchants the user is granted; admins see all | URD-WAL-006 |
| FR-7 | Each voucher posts debit/credit ledger lines against accounts | URD-TXN-001 |
| FR-8 | A line carries the account it affects, an optional category, an amount, and a balance-before/after snapshot | URD-TXN-002 |
| FR-9 | Ledger lines share the voucher's currency | URD-TXN-003 |
| FR-10 | A line may reference its source document for traceability | URD-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
| Area | Requirement |
|---|---|
| Data integrity | An account's running balance and the ledger lines that move it are written together; balance equals the sum of posted lines |
| Default uniqueness | Exactly one default account per type per merchant, enforced at the model level |
| Tenancy & authz | Accounts are confined to the user's own merchant; non-admins see only the merchants they are granted, admins see all |
| Precision | Monetary math uses 4-decimal precision; balances stored with the same precision |
| Consistency | Account seeding and ledger posting are idempotent and transactional; a repeated merchant event never double-seeds |
| i18n | User-facing labels/types are bilingual (English and Vietnamese) |
8. UX & Flows
Key screens (in the merchant app): account list / filter / form (incl. bank type), voucher select-account-by-currency, and the ledger-line (transaction) table / filter / show page.
9. Data & Domain
| Concept | Role |
|---|---|
| Account | A money account - type (Cash/Bank/QR/Mobile-POS), owning merchant, running balance, currency, a per-type default flag, optional payment-integration link |
| Internal control account | A non-cash account (Inventory, Cost of Goods Sold) the system maintains for cost/stock postings |
| Ledger line | A debit/credit row - affected account, optional category, amount, balance-before/after snapshot, voucher currency, source-document reference |
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 - accounts reference payment integrations (linked, not auto-included).
Assumptions
- A merchant-created event reaches Finance so accounts can be seeded.
- Internal control accounts exist before any cost-of-goods posting is attempted.
11. Risks & Open Questions
| Risk / question | Mitigation / status |
|---|---|
| Account balance and ledger lines could diverge | Written transactionally; balance equals the sum of posted lines, snapshotted per line |
| Repeated merchant event could double-seed accounts | Seeding is idempotent - a repeated event never creates a second default account |
| Per-type default-flag uniqueness | Enforced at the model level after initial fixes |
| No multi-currency within a voucher | Out of scope; single currency per voucher (default VND) |
12. Release Plan & Launch Criteria
| Aspect | Plan |
|---|---|
| Phase | P1 (foundation) - see URD feature catalog |
| Rollout | All merchants; no feature flag |
| Migration | Seed migration for default finance accounts; internal control accounts seeded per merchant |
| Launch criteria | New merchant gets default + control accounts; ledger lines post balanced with balance snapshots; account balance equals the sum of its lines |
| Monitoring | Per-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
- URD: Finance - Accounts (
WAL) · Ledger Lines (TXN) - Related: Vouchers & Posting (
VCH) · Categories (CAT) - Module: Finance - URD
- Developer: @nx/finance · domain model