Help & User Guide

A complete reference for the Ledger accounting system.

What this app does: Full double-entry accounting for project-based businesses (construction, contracting). Every transaction is balanced — debits always equal credits. Revenue and expense accounts are organised per project and closed at year-end. Historical data can be bulk-imported from bank CSVs, PDFs, GnuCash files, or scanned receipts.

Core concepts

Double-entryEvery transaction has at least one debit line and one credit line that sum to the same amount.
Normal balanceAssets & Expenses increase with Debit. Liabilities, Equity & Revenue increase with Credit.
ReferenceAuto-generated ID for each entry (e.g. JUR-20250315-001). Used for searching and linking.
ProjectTag entries to a construction project for cost-tracking. Projects can be nested (sub-projects).
DocumentGroup imported entries under a source statement, invoice, or receipt.

Trial Balance

Home dashboard — quick health check of all accounts.

The Trial Balance lists every account with its debit and credit totals for the selected period. The bottom of the page shows whether the ledger is in balance (debits = credits). An imbalance means a posting error exists somewhere.

How to use

  1. Open the app — Trial Balance is the home page.
  2. Optionally set a From and To date to view a period subset.
  3. Click any account code or name to drill into its full Ledger.
  4. If totals show Out of balance, check recent entries in the Journal.

Journal

Complete chronological log of all posted transactions.

What you see

Each row shows: date, reference, description, debit total, credit total, source badge (MANUAL or POS), and any linked document / project. 50 entries per page.

Actions

  • Expand a row — click the reference to see all line items. Account names are clickable links that jump to that account's ledger.
  • Search — type a reference, description, or account name in the search box.
  • Filter by date / source — use the filter controls at the top.
  • Edit — click the pencil icon to change date, description, or lines (entry must remain balanced).
  • Assign Document / Project — use the dropdown fields in the expanded row. You can also assign a project to each individual line item — useful when a single payment covers multiple projects (see Projects).
  • Reverse — creates a new offsetting entry (original is kept).
  • Delete — permanently removes the entry.

New Entry

Manually post a journal entry from scratch.

Step-by-step

  1. Click New Entry in the sidebar.
  2. Set the Date (defaults to today).
  3. Optionally add a Description / memo.
  4. Optionally link to a Document and/or Project.
  5. Add at least two line items:
    — Select an account
    — Enter either a Debit or Credit amount (not both)
    — Add a line memo if needed
  6. Keep adding lines until debits = credits. The balance indicator turns green when the entry is balanced.
  7. Click Post Entry.
Tip — Auto-balance: Leave the last credit line amount blank. The system will auto-fill it to make the entry balance.

Ledger (Account Drill-Down)

All transactions for a single account with running balance.

Access the ledger by clicking any account code in the Trial Balance, Journal, or Chart of Accounts.

Features

  • Running balance — each row shows the cumulative balance after that transaction.
  • Date & text filter — narrow to a period or search by reference / description.
  • Pagination — 100 transactions per page. Use « First, ← Prev, Next →, Last » in the top bar to navigate. The date range of the current page is shown alongside the page counter.
  • Breadcrumb navigation — the account heading shows its full path (e.g. Bank › Savings › Sampath Coll 3887). Click any ancestor segment to see a dropdown of its immediate child accounts and jump to one without going back to the menu.
  • Expand a row — click any row to see the full entry. Account links in the expanded detail (code and name) jump to that account's ledger and land on the exact page and transaction automatically.
  • Counter accounts inline — each row shows the counter-account names in the empty column (debit row → counter names in credit column, and vice versa). Click any counter-account name to jump directly to its ledger at the correct page and transaction.
  • Quick entry — click + New Entry at the top to open a mini form. Enter date, DR/CR side, amount, counter-account, and optional description without leaving the ledger.
  • Edit & Delete — expand a row, then use Edit to change date, description, or lines (must stay balanced), or Delete to permanently remove the entry.
  • Breakdown by account — the collapsible panel above the table shows which counter-accounts appear most. Click any card to jump to that account's ledger.

Chart of Accounts

Define the structure of your ledger.

Account types

TypeNormal BalanceExamples
ASSETDebitCash, Bank, Accounts Receivable
LIABILITYCreditAccounts Payable, Loans
EQUITYCreditOwner's Capital, Retained Earnings (3900)
REVENUECreditContract Income, Service Revenue
EXPENSEDebitMaterials, Labour, Subcontractors

Creating an account

  1. Click Chart of Accounts in the sidebar.
  2. Click + New Account.
  3. Enter a unique Code (e.g. 1010), a Name, and select the Type.
  4. Optionally set a Parent account to create a sub-account hierarchy.
  5. Click Create.

Moving accounts

To relocate an account — and its entire subtree of sub-accounts — to a different parent, click the Move button on the account row. A panel opens below the row with a searchable parent selector. Pick the new parent and click Move Here. To promote the account to top-level (no parent), clear the selector and click Move Here. The system prevents circular moves (e.g. moving a parent into one of its own descendants).

Full hierarchical names

Account names are always shown with their full path from the root of the tree, separated by . For example, a sub-account named Salaries under Operating under Expenses displays as Expenses › Operating › Salaries everywhere in the app — in dropdowns, journal entry lines, ledger rows, and project entries. This makes it unambiguous which account you are looking at without needing to know the code.

Customising the default account list

The default Chart of Accounts is defined in apps/api/prisma/accounts.ts. Edit that file to add, remove, or rename accounts for a new deployment, then run pnpm db:seed to apply changes (safe to re-run — existing accounts are upserted, not duplicated). See New Business Instance for the full deployment guide.

Import

Bulk-import transactions from bank exports, PDFs, receipts, or GnuCash files.

Import modes

CSV — Bank Export
Upload a CSV from your bank or accounting software. The importer auto-detects date, description, and amount columns. Handles most date formats and currency symbols.
PDF — Digital Statements
Upload a PDF bank statement with selectable text. Scanned image-only PDFs will not parse — use the AI Receipt mode instead.
AI Receipt — Photos & Scans
Upload a JPG or PNG of a receipt or statement. Requires AI_API_KEY to be configured. Works with Gemini, Groq, or any OpenAI-compatible endpoint.
GnuCash — Full Migration
Import a full GnuCash XML file (.gnucash). Creates all accounts and imports all transactions. Duplicate detection prevents re-importing the same file. Must be XML format — export from GnuCash if you have a compressed file.

Review step (CSV / PDF / AI)

  1. After upload the parsed rows are shown. Check dates and amounts look correct.
  2. Set a default debit account (e.g. your main expense account) for unrecognised rows.
  3. Click Apply Rules to auto-assign accounts based on your Category Rules.
  4. For each row, verify or change the debit account. Check/uncheck rows to include or exclude.
  5. Optionally attach to a Document (name, type, issuer) for record-keeping.
  6. Click Post Entries.
Historical data tip: Import year by year. After each year's entries are complete, Smart Assign entries to projects, then close the fiscal year.

Documents

Group journal entries under a source document for filing and reference.

A Document represents a real-world paper: a bank statement, a supplier invoice, a receipt. Entries imported together in one batch are automatically attached to a single Document if you choose during import. You can also create Documents manually and link entries via the Journal.

Document types

  • Statement — bank or credit card statement
  • Receipt — proof of payment
  • Invoice — supplier or customer invoice
  • Other — anything else

Click a document name to see all its entries and totals. Documents with linked entries cannot be deleted.

Projects

Track costs by construction project, stage, or cost centre — hierarchically.

Hierarchy

Projects can be nested to any depth. Example:
Phase 1 — Foundation
  └ Excavation
  └ Concrete Works
Phase 2 — Structure

The project detail page shows a Cost Breakdown that rolls up all direct and descendant entries — so "Phase 1" total includes Excavation + Concrete Works.

Creating and managing projects

  1. Click Projects in the sidebar.
  2. Click + New Project.
  3. Enter a name, optional description, optional parent, status (Active / Completed), and start/end dates.
    Dates are required for Smart Assign Stage 1 (date-range matching).
  4. Click Create.

Assigning entries to a project

There are five ways:

  1. At posting — select the project in the New Entry or Import form (assigns the whole entry).
  2. In the Journal — expand an entry and use the Project dropdown (assigns the whole entry).
  3. Per line — in the New Entry form or Journal edit view, each individual line can carry its own project. This is ideal when a single payment (e.g. a supplier invoice) covers work for two different projects. The project detail page shows the attributed amount — only the lines assigned to that project — marked with an asterisk (*) when it differs from the full entry total.
  4. From the Project page — use the "Assign Entries" search panel to find entries by keyword and add them.
  5. Smart Assign — bulk AI-assisted assignment (see below).

Editing & deleting projects

  • Click a project to open its detail page, then click Edit.
  • A project can only be deleted if it has no direct entries and no sub-projects. Remove or re-assign those first.

Category Rules

Keyword-based rules to automatically categorise entries during import and batch auto-assign.

Three rule types

TypeWhen appliedWhat it does
AccountImport review screenIf description contains keyword → pre-select that expense account for the row
ProjectRun Auto-AssignIf description or account names contain keyword → assign entry to named project
DocumentRun Auto-AssignIf description or account names contain keyword → assign entry to named document

Managing rules

  • Add — select the tab (Account / Project / Document), fill in the keyword and target, click Add Rule. Keywords are case-insensitive.
  • Edit — click the pencil icon on any rule row to edit the keyword or target inline. Press Enter to save or Escape to cancel.
  • Delete — click the button on the rule row.
  • Run a single rule — click ▶ Run on any rule to apply just that rule immediately. For Account rules, choose DR or CR to specify which side of the matching entries to update. Tick Override to reassign entries that already have an account assigned.

How Auto-Assign works

Clicking ▶ Run Auto-Assign runs a batch pass over all journal entries. Here is exactly what happens:

  1. Which entries are scanned — every entry that is missing a project or missing a document. Entries that already have both are skipped entirely.
  2. What is matched against — for each entry the system builds a search text from the entry's description plus the account names of all its lines, joined together. Matching is case-insensitive substring (e.g. keyword "wool" matches "WOOLWORTHS").
  3. First rule wins — rules are tested in the order they were created. The first rule whose keyword appears anywhere in the search text is applied. Later rules are not tested for that field once a match is found.
  4. Project assignment — if the entry has no project and a project rule matches, the entry is linked to the named project. If no project with that name exists yet, it is created automatically.
  5. Document assignment — same logic independently for documents. A single run can assign both a project and a document to the same entry if separate rules match.
  6. Never overwrites — existing project or document assignments are never changed. Only null fields are filled.

The result banner shows N tagged to projects, N tagged to documents (N entries scanned). You can run Auto-Assign as many times as you like — it is safe to re-run after adding new rules.

Rule order matters. If two project rules could match the same entry, only the first one (top of the list) applies. To change precedence, delete the lower-priority rule and re-add it — rules are ordered by creation time.

Smart Assign

Bulk project assignment using date-range matching and AI classification — ideal for years of historical data.

Two-stage process

Stage 1 — Date-Range Auto-Match

If an entry's date falls within exactly one project's start/end date range, it is auto-matched with certainty. No AI required. Prerequisite: projects must have Start Date and End Date set.

Stage 2 — AI Classification

Entries that fall in a period where multiple projects overlap are sent to the AI model in batches. The AI reads the entry description, account names, and candidate project names/descriptions, then returns a project assignment with a confidence rating (High / Medium / Low) and brief reasoning. Prerequisite: AI_API_KEY must be configured.

Workflow

  1. Set project start/end dates on all projects (Project detail → Edit).
  2. Open Smart Assign from the sidebar.
  3. Set the Limit (how many unassigned entries to analyse at once; default 200).
  4. Click Analyze.
  5. Review Stage 1 (auto-matched) and Stage 2 (AI suggestions). Uncheck any you disagree with.
  6. Click Apply Selected. The page re-analyses and shows remaining unassigned entries.
  7. Repeat until satisfied. Unmatched entries can be assigned manually via the Journal or Project pages.
Best practice: Run Smart Assign before closing a fiscal year to ensure all entries have a project. Cost reports only count assigned entries.

Fiscal Years

Year-end closing — zero Revenue & Expense accounts and transfer net income to Retained Earnings.

Why close a year?

In standard accounting, Revenue and Expense accounts are reset to zero at the end of each year. The net profit (or loss) is posted to Retained Earnings (account 3900) in Equity. This lets you see each year's performance cleanly on an Income Statement without prior years' figures mixing in.

Closing workflow

  1. Ensure all entries for the year are posted and correct.
  2. Click Fiscal Years in the sidebar.
  3. Create the fiscal year if it doesn't exist (year number, start date, end date).
  4. Click Preview Close to see the closing entry that will be posted — debits each Revenue account, credits each Expense account, and posts the net to Retained Earnings.
  5. Click Close Year (or Confirm & Post from the preview panel) to post the entry.
  6. The year is now marked Closed. The closing entry reference (e.g. CLOSE-2024) is shown as a link to the Journal.

Re-opening a closed year

If you find missing records after closing, click Re-open on the year. This posts a reversal of the closing entry (restoring all Revenue and Expense balances), lets you add the missing transactions, then you close again. Re-open is safe — it never deletes anything.

Effect on project costs

Year-end closing does not affect project cost reports. Project costs are accumulated across all years regardless of fiscal periods.

Recommended workflow for historical data: Post all records for a year → Smart Assign entries to projects → Preview Close → Close Year. Repeat for each year oldest-to-newest.

Reports

Income Statement and Balance Sheet.

Income Statement
Shows Revenue and Expenses for a date range, and the resulting Net Income. Useful for a single year's profitability view. Accounts can be collapsed or expanded.
Tip: For a closed year, run the Income Statement with the year's dates — the closing entry zeroes the accounts so Net Income = 0, confirming the close was correct.
Balance Sheet
Shows financial position (Assets = Liabilities + Equity) as of a chosen date. Automatically includes Net Income for the current open period in Equity.
Tip: Run the Balance Sheet on the last day of a fiscal year to verify Retained Earnings matches expectations before closing.

POS Sync

Automatic polling from a Point of Sale system.

The POS Sync panel lives in the bottom-left corner of every page. It polls the configured POS server at regular intervals and imports new sales transactions automatically.

Status indicators

  • ● Connected — polling is active and last poll succeeded.
  • ● POS Offline — polling active but POS server unreachable. Shows last attempt time and error.
  • ○ Connecting… — enabled but first poll not yet complete.
  • ○ Sync disabled — polling is off. Click Enable to start.

Controls

  • Enable / Disable — toggle automatic polling on or off.
  • Sync Now — trigger an immediate poll without waiting for the next interval.

Imported POS entries appear in the Journal with a POS source badge and can be assigned to projects and documents like any other entry.

New Business Instance

How to run a completely separate copy of the app for a second business.

Each business needs its own database, its own .env, and its own Chart of Accounts. The app is stateless in code — only the database and environment files differ between instances.

Step-by-step

  1. Set the business name — add NUXT_PUBLIC_BUSINESS_NAME="Acme Corp" to apps/web/.env. The name appears at the top of the sidebar so you can instantly tell which business you are looking at.
  2. Configure the API — copy apps/api/.env.example to apps/api/.env and set a unique DATABASE_URL and PORT (e.g. 3004).
  3. Configure the web app — set NUXT_PUBLIC_API_BASE=http://localhost:3004 in apps/web/.env to point at the new API port.
  4. Start a separate database — pass different env vars to Docker Compose:
    DB_PORT=5437 POSTGRES_DB=acme docker-compose up -d
    Both Postgres containers run independently because the host port and database name are different.
  5. Apply schema and seed:
    pnpm db:push
    pnpm db:seed
  6. Customise the Chart of Accounts — edit apps/api/prisma/accounts.ts to add, remove, or rename accounts for the new business, then re-run pnpm db:seed. Seeding is idempotent — existing accounts are updated, not duplicated.
  7. Start the app — run pnpm dev (choose a different web port if running both at once).

What each config file controls

FileWhat to change
apps/web/.envNUXT_PUBLIC_BUSINESS_NAME and NUXT_PUBLIC_API_BASE
apps/api/.envDATABASE_URL and PORT
docker-compose.yml envDB_PORT, POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD
apps/api/prisma/accounts.tsDefault Chart of Accounts seeded on first pnpm db:seed
Tip: You can reuse the same code directory for both businesses — only the .env files and the running database differ. Use dotenv-cli or shell variable prefixes to switch between environments without editing files.

Recommended Workflows

Setting up from scratch
  1. Create your Chart of Accounts (or let the GnuCash import create them).
  2. Create your Projects with start/end dates.
  3. Add Category Rules for your common expense keywords.
  4. Import historical data year by year.
  5. Run Smart Assign to assign entries to projects.
  6. Close each completed fiscal year.
Day-to-day recording
  1. Use New Entry for individual manual postings.
  2. Use Import → CSV for periodic bank statement batches.
  3. Assign a Project to each entry so cost reports stay accurate.
  4. Check the Trial Balance to confirm no imbalances after bulk imports.
Year-end close
  1. Post any missing entries for the year.
  2. Run Smart Assign on remaining unassigned entries.
  3. Check the Income Statement for the year — confirm totals look correct.
  4. Preview and Close the Fiscal Year.
  5. Verify the Balance Sheet shows the expected Retained Earnings balance.