Featured Project
AccuLedger
Pro
A modern double-entry accounting engine built from first principles on the VILT stack. AccuLedger Pro enforces GAAP-compliant ledger mechanics while delivering the kind of intuitive interface that non-accountants can actually use.
System Modules
Module Register
Chart of Accounts
COMPLETEHierarchical CoA with account types (Asset, Liability, Equity, Income, Expense), sub-account grouping, and opening balance import.
Journal Entry Engine
COMPLETEDouble-entry posting with Dr/Cr balance enforcement, reference numbering, period locking, and full audit trail on every line.
Trial Balance
COMPLETEPeriod-selectable trial balance with opening/movement/closing columns, account-level drill-down, and PDF/CSV export.
Profit & Loss
COMPLETEGAAP-formatted income statement with gross profit, EBITDA, and net profit lines. Comparative prior-period column included.
Balance Sheet
COMPLETEClassified balance sheet (current/non-current) with automatic retained earnings roll-forward and net asset reconciliation.
Bank Reconciliation
IN PROGRESSStatement import via CSV/OFX, auto-matching on amount and date, unreconciled item ageing, and reconciliation lock-off.
Accounts Receivable
IN PROGRESSCustomer invoicing, credit notes, receipt allocation, ageing schedule, and statement generation. VAT / sales-tax aware.
Multi-Currency
PLANNEDTransaction-level currency capture with live FX rates, realised/unrealised gain-loss posting, and base-currency reporting.
Data Architecture
Schema Design
Every table exists to enforce an accounting invariant. The schema is the contract between the application and GAAP.
| TABLE | KEY COLUMNS |
|---|---|
accounts
|
id, code, name, type, parent_id, currency, is_active
|
journal_entries
|
id, reference, date, description, currency, period_id, posted_by
|
journal_lines
|
id, entry_id, account_id, type(dr/cr), amount, memo
|
periods
|
id, name, start_date, end_date, is_locked
|
currencies
|
id, code, name, symbol, rate, is_base
|
bank_statements
|
id, account_id, date, amount, description, matched_line_id
|
protected static function booted(): void { static::creating(function (JournalEntry $entry) { $dr = $entry->lines->where('type','debit')->sum('amount'); $cr = $entry->lines->where('type','credit')->sum('amount'); if ($dr !== $cr) { throw new UnbalancedEntryException( 'Dr/Cr must be equal — GAAP invariance violated.' ); } }); }
Engineering Decisions
Architecture Ledger
Every technical choice has a reason (debit) and a consequence (credit).
Eloquent ORM over raw SQL
Relationships between entries, lines, and accounts are naturally expressed as Eloquent associations. The ORM enforces consistency without sacrificing query clarity.
Inertia.js over a separate SPA
Financial forms need server-side validation authoritative over the client. Inertia keeps validation on the Laravel layer while delivering a seamless navigation experience.
Money PHP for all arithmetic
Floating-point arithmetic is unsuitable for financial calculation. Money PHP enforces integer-based minor-unit storage and prevents rounding errors that would break the Dr = Cr invariance.
Period locking at the model layer
Closed accounting periods must be immutable. A locked period is enforced via a Laravel global scope that prevents any new journal lines being posted into it.
Development Roadmap
Build Plan
GL Core
- ✓ Chart of Accounts
- ✓ Journal Engine
- ✓ Trial Balance
- ✓ P&L
- ✓ Balance Sheet
Cash & AR
- ▸ Bank Reconciliation
- ▸ Accounts Receivable
- ▸ Customer Portal
AP & Multi-CCY
- ○ Accounts Payable
- ○ Multi-Currency
- ○ FX Revaluation
Reporting Suite
- ○ Management Pack
- ○ Budget vs Actual
- ○ Cash Flow Statement