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 SaveChanges interceptor 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.