Account Model & Chart of Accounts (System-of-Record)
| Owner | Classification | Version | Effective | Next review | Status |
|---|---|---|---|---|---|
| Platform Engineering | Internal | 0.1 | 2026-09-17 | 2026-12-17 | Draft |
Purpose. The single, canonical statement of where account identity lives in the platform, how the per-module account tables relate, and why they legitimately differ. This exists because the "journal vs recon account sets don't match" question recurs; the answer is here, once. For how a close task resolves to an account and its periodsummary, see Connected Close — GL Stitching.
The decision — reconciliation.account is the account System-of-Record
Account identity (accountnumber + segment1..10) is owned by reconciliation.account. Every other module's account table is a consumer or projection of it, not a competing master.
- Ideally this canonical chart of accounts would sit at the platform layer (
finbase), alongsidefinbase.segmentconfiguration(which already owns the segment structure — aliases, unique-key flags). It does not; the account instances live in recon. - The classic ERP owner of the chart of accounts would be the GL (journal). We deliberately chose recon because recon is where the dimensional account (number × segment) is modelled and where balances reconcile.
- This is a conscious trade-off, not drift. Do not re-litigate "should accounts be in finbase / journal" — the decision is recon; this doc records it.
The account tables across modules
| Table | Role | Key it carries | Segments | Link to SoR |
|---|---|---|---|---|
reconciliation.account | Canonical SoR — the dimensional chart of accounts | accountnumber + segment1..10 + accountcategory (CASH/AR/AP/…) | Yes (1..10) | — (is the master) |
journal.accountmaster | Postable GL accounts (the ledger's working set) | accountnumber + name + category | No | Loose strings, unlinked — wave-2 |
cash.bankaccount_glmaster | Bank ↔ GL linkage for cash | bank account ↔ GL account | No | FK to reconciliation.account |
finbase.segmentconfiguration | Segment structure (aliases, useforuniquekey) | segment definitions | — | Platform-level; defines the segment model recon instantiates |
Why the sets legitimately differ (the recurring question)
Measured on the reference tenant:
journal.accountmaster: 286 accounts.reconciliation.account: 314 distinct numbers (431 rows — a number may have severalsegment1variants).- Every journal account exists in recon (journal-not-in-recon = 0).
- Recon holds 28 numbers journal does not — coherent balance-sheet/P&L categories (other assets, other liabilities, accrued, tax, prepaid, AR, AP…).
So journal.accountmaster ⊆ reconciliation.account. This is expected:
- Recon is the fuller SoR superset; journal's master is the subset the ledger has actually needed, populated from a different seed and not yet reconciled to the SoR (the "loose strings, wave-2" status).
- It is not corruption (the extra accounts are valid) and not the target design (journal should reference recon by FK). It is debt with a known end-state.
Target end-state: journal links to reconciliation.account by FK (as cash already does); the postable set becomes a governed projection of the SoR rather than a loose parallel list.
The account key — number + segment
An account's identity is accountnumber + segment1, never the number alone. The same number may have several live reconciliation.account rows differing only by segment1 (e.g. 100001-6000 vs 100001-7000) — distinct accounts, not duplicates. Resolution rules (control-variant selection, the segment-empty fallback, where the segment comes from at onboarding) live in Connected Close — GL Stitching.
Modularity — how this ships
Modules are sold à la carte, but the platform ships as one connected backend:
- All schemas and backend ship together, regardless of what a customer licensed.
reconciliation.account(+ its services) is therefore always present, even for a customer who only bought, say, CloseHub. There is no deployment where the account SoR is absent. - Modularity is enforced at the surface, not the schema: gate the UI (nav/routes) and the API (license scope) for unlicensed modules. Hiding nav alone is insufficient — the backend endpoints are reachable otherwise.
- Connected features degrade, they do not error. A CloseHub-only tenant has the recon tables but no recon data/licence, so cross-module surfaces (the recon variance tie, journal automations) must no-op / hide while the account key still resolves. Graceful degradation is the real work; the tables are free.
Because the SoR always ships, binding and resolving against reconciliation.account is safe in every deployment — the coupling is intentional and supported.
Wiring status
| Module | Status |
|---|---|
| Cash | Linked — glmaster resolves to reconciliation.account by FK. |
| Journal | Unlinked (loose strings) — wave-2. Postable set is a parallel list, not yet reconciled to the SoR. |
| CloseHub | Resolves tasks to reconciliation.account at read/dispatch time (see GL Stitching); binds by glaccountcode (+ segment1). |
| Recon chart | ~50-account canonical recon chart pending (issue #1142). |
Related
- Connected Close — GL Stitching — how a close task resolves to the right account +
periodsummary, the account key, and control-variant resolution. - FIG Data Setup — the SoR declaration in context of demo/data alignment and the FIG contract.
Revision history
| Version | Date | Author | Change |
|---|---|---|---|
| 0.1 | 2026-09-17 | Platform Engineering | Initial — consolidates the account-SoR decision (recon), per-module tables, the journal⊆recon divergence + target end-state, the account key, and the modular-shipping stance. Supersedes the scattered one-liners in FIG Data Setup and GL Stitching. |