Accounting Modes - armoryworks/forge GitHub Wiki
Forge is built for shops that already keep their books somewhere โ and for shops that don't. Which of those you are changes how a large part of the app behaves, so it is worth understanding before you install.
Canonical reference: docs/architecture.md (ยง Standalone vs Integrated Mode) and the accounting suite plan under docs/delivery/complete/accounting-suite/.
The โก ACCOUNTING BOUNDARY marker
Throughout the specs, a โก marks a feature that behaves differently depending on this setting. If you are reading a doc and see it, that section has two answers.
Integrated mode โ an accounting provider is connected
QuickBooks Online is the default and primary provider; Xero, FreshBooks, Sage, NetSuite, Wave and Zoho implement the same interface.
- Invoices, payments, AR, financial reports, vendor records and tax calculations are owned by the accounting system.
- Forge reads that financial data through the provider's API and caches it locally; the financial screens become read-only views.
- Quotes and sales orders still live in Forge, syncing outward to the provider's estimate and sales-order documents.
- Shipping triggers invoice creation in the accounting system.
This is the mode most shops start in: keep the accountant happy, get better operational tooling on top.
Standalone mode โ no provider connected
Forge manages invoices, payments, AR aging, customer statements, basic P&L and sales tax itself, in its own Postgres tables, with full CRUD through the UI.
Native double-entry GL (CAP-ACCT-FULLGL)
Beyond the lightweight built-in books there is a native double-entry general ledger โ posting engine, sub-ledgers, statements, period close, FX, payroll and bank reconciliation โ so a shop can keep a real book of record inside Forge rather than in QuickBooks.
Two things to know about it:
- It is off by default and gated on data, not just a toggle. The capability cannot be enabled for a book until that book's opening balances are loaded โ a posted conversion journal must exist, verified by a tie-out. This is deliberate: a ledger that starts from nothing is worse than no ledger. Disabling is ungated.
- Posting is inline and transactional. The operational command and its journal entry commit or roll back together, in one transaction. A posting failure fails the operation immediately and visibly. Nothing posts asynchronously behind your back, and posted entries are immutable โ enforced both by a
SaveChangesinterceptor and by database triggers.
A scheduled reconciliation sweeper left-joins should-have-posted documents against journal entries and alerts on orphans, which is also the mechanism for catching up a document backlog that predates enabling the GL.
Switching modes
- On connect: existing local financial data is offered for sync โ merge or archive.
- On disconnect: the last-synced accounting data becomes the local baseline.
Mode is a per-install admin setting, resolved at runtime by AccountingServiceFactory from system settings. The mutual exclusion between built-in books and an external provider is enforced declaratively through Capability Gating rather than by branching logic scattered through the codebase.