Loading...
Loading...
Implement a complete double-entry accounting system inside any SaaS app. Users enter transactions naturally (sales, expenses, inventory) while the system auto-posts journal entries under the hood. Produces both user-friendly reports and technical financial statements (Trial Balance, Balance Sheet, Income Statement, Cash Flow). Enforces 10000% accuracy with balanced entries and seamless void/reversal mechanics. Use when building any financial, ERP, POS, or inventory system that needs proper accounting.
npx skill4agent add peterbamuhigire/skills-web-dev saas-accounting-system┌─────────────────────────────────────────────────┐
│ USER LAYER (Friendly) │
│ Sales, Purchases, Payments, Inventory, Expenses│
│ → User sees: "Sale #1042 to Customer X: $500" │
└──────────────────────┬──────────────────────────┘
│ auto-posts
┌──────────────────────▼──────────────────────────┐
│ ACCOUNTING ENGINE (Hidden) │
│ Journal Entries, Ledger Postings, Trial Balance│
│ → Engine posts: DR Accounts Receivable $500 │
│ CR Sales Revenue $500 │
└──────────────────────┬──────────────────────────┘
│ aggregates
┌──────────────────────▼──────────────────────────┐
│ REPORTING LAYER (Dual) │
│ User Reports: Sales Summary, Aging, P&L Simple │
│ Accountant Reports: Trial Balance, BS, IS, CF │
└─────────────────────────────────────────────────┘SUM(debits) = SUM(credits) — ALWAYS| Type | Code Range | Normal Balance | Examples |
|---|---|---|---|
| Asset | 1000-1999 | Debit | Cash, Bank, AR, Inventory, Equipment |
| Liability | 2000-2999 | Credit | AP, Loans, Tax Payable, Unearned Revenue |
| Equity | 3000-3999 | Credit | Owner's Equity, Retained Earnings |
| Revenue | 4000-4999 | Credit | Sales, Service Income, Interest Income |
| COGS | 5000-5999 | Debit | Cost of Goods Sold, Direct Materials |
| Expense | 6000-6999 | Debit | Rent, Salaries, Utilities, Marketing |
franchise_idreferences/chart-of-accounts.md| User Action | Debit Account | Credit Account |
|---|---|---|
| Record Sale (Invoice) | Accounts Receivable | Sales Revenue |
| Record Sale + Tax | AR + Tax Receivable | Sales Revenue + Tax Payable |
| Receive Payment (Cash) | Cash/Bank | Accounts Receivable |
| Record Purchase | Inventory/Expense | Accounts Payable |
| Pay Supplier | Accounts Payable | Cash/Bank |
| Record Expense | Expense Account | Cash/Bank or AP |
| Inventory Sale (COGS) | Cost of Goods Sold | Inventory |
| Stock Adjustment (+) | Inventory | Inventory Adjustment (Income) |
| Stock Adjustment (-) | Inventory Adjustment (Expense) | Inventory |
| Salary Payment | Salary Expense | Cash/Bank |
| Loan Received | Cash/Bank | Loan Payable |
| Loan Repayment | Loan Payable + Interest Exp | Cash/Bank |
| Depreciation | Depreciation Expense | Accumulated Depreciation |
| Customer Refund | Sales Returns | Cash/Bank or AR |
references/journal-posting-rules.md1. User clicks "Void" on a transaction (e.g., Sale Invoice #1042)
2. System marks the original transaction as VOIDED (status change)
3. System auto-creates a REVERSING journal entry:
- Same accounts, opposite directions
- Reference: "REVERSAL of JE-{original_id}"
- Same date OR current date (configurable)
4. Original entry + reversal entry net to ZERO
5. All sub-ledger balances update automaticallyOriginal (Sale Invoice #1042):
DR Accounts Receivable 500.00
CR Sales Revenue 500.00
Reversal (Void of #1042):
DR Sales Revenue 500.00
CR Accounts Receivable 500.00
Net effect: ZEROreferences/void-reversal-patterns.md-- Chart of Accounts
accounts (id, franchise_id, code, name, type, parent_id,
is_active, normal_balance, created_at)
-- Journal Entries (Header)
journal_entries (id, franchise_id, entry_date, reference_type,
reference_id, narration, is_reversal, reversed_entry_id,
posted_by, status, created_at)
-- Journal Entry Lines (Detail)
journal_entry_lines (id, journal_entry_id, account_id,
debit_amount, credit_amount, narration,
franchise_id, created_at)
-- Fiscal Periods
fiscal_periods (id, franchise_id, period_name, start_date,
end_date, status, closed_by, closed_at)
-- Account Balances (Materialized for performance)
account_balances (id, franchise_id, account_id, period_id,
opening_balance, debit_total, credit_total,
closing_balance, updated_at)journal_entry_lines.debit_amountcredit_amountfranchise_idstatusreferences/schema-design.md| Report | What User Sees | Data Source |
|---|---|---|
| Sales Summary | Total sales by period, customer, product | Sales transactions |
| Outstanding Invoices | Who owes what, how old | AR sub-ledger |
| Expense Report | Spending by category | Expense transactions |
| Profit & Loss (Simple) | Revenue minus expenses | Income/expense accounts |
| Cash Position | Money in bank/cash | Cash/bank accounts |
| Inventory Value | Stock on hand with cost | Inventory sub-ledger |
| Report | What It Shows | Source |
|---|---|---|
| Trial Balance | All account balances (DR/CR columns) | General Ledger |
| Balance Sheet | Assets = Liabilities + Equity | GL (type 1-3) |
| Income Statement | Revenue - COGS - Expenses = Net Income | GL (type 4-6) |
| Cash Flow Statement | Operating + Investing + Financing | Cash account entries |
| General Ledger Detail | Every entry per account | Journal entries |
| Journal Register | All journal entries chronologically | Journal entries |
| Aged Receivables | AR aging (30/60/90/120 days) | AR sub-ledger |
| Aged Payables | AP aging | AP sub-ledger |
| Audit Trail | Who posted what, when | Journal entries + audit log |
references/financial-statements.mdaccountsjournal_entriesjournal_entry_linesfiscal_periodspostJournalEntry()| Area | Skill | How It Applies |
|---|---|---|
| Database schema | | DECIMAL(15,2), indexes, FK constraints |
| API endpoints | | Consistent error responses for failed postings |
| Multi-tenancy | | franchise_id on all tables |
| UI reports | | DataTables for ledger, charts for P&L |
| Mobile reports | | Report screens with tables |
| PDF export | | Financial statement PDFs |
| Security | | Protect financial data, audit trail |
| Auth | | Permission: who can post/void/view reports |
| Inventory link | | COGS posting on stock movements |
| Testing | | Test every posting rule, every reversal |
| Implementation | | Execute accounting phases with TDD |
| Audit | | Verify accounting system completeness |
| Don't | Do Instead |
|---|---|
| Let users enter journal entries directly | Auto-post from business transactions |
| Use FLOAT for money | Use DECIMAL(15,2) always |
| Delete journal entries | Create reversing entries (void) |
| Skip balance validation | Enforce DR=CR in stored procedure |
| Store calculated balances only | Store individual entries, calculate on demand |
| Mix accounting with business logic | Separate accounting engine as its own service layer |
| Hard-code account codes | Use configurable COA with tenant-specific accounts |
| Skip audit trail | Log every posting with user, timestamp, IP |
| Allow posting to closed periods | Enforce period status check before posting |
| Show debits/credits to end users | Show friendly labels (Income, Payment, etc.) |
SELECT SUM(debit) - SUM(credit) FROM journal_entry_linesreferences/chart-of-accounts.mdreferences/journal-posting-rules.mdreferences/void-reversal-patterns.mdreferences/financial-statements.mdreferences/schema-design.md