Every rupee counted once
Recording expenses is the easy part. The hard part is keeping three views of the same money in agreement: what a project has cost, what each vendor is owed, and what the bank says. When they drift apart, someone spends a week working out why.
✓ All three are calculated from the same ledger entries, so they cannot disagree.
Owing money and paying it are separate things
The data model keeps the record of a debt apart from the record of a payment. A purchase creates what is owed. A payment settles it. An allocation connects the two and says which project the money belongs to. Each step writes to an append-only ledger, and every report reads from that ledger.
Green means money in
Receipts and credits. The colour is used for nothing else anywhere in the app.
Red means money out
Payments, purchases and debits.
Amber needs attention
Unreconciled bank lines, pending approvals, EMIs falling due.
What is in the app
The sidebar follows the navigation the client signed off. Each item is tied to a permission, so people only see the parts their role allows. An administrator can also switch off whole modules the company does not use.
Dashboard
The whole business at a glance: money in, money out, what is owed and what needs attention.
Projects
Each site, created together with its budget. Budget revisions, BOQ, income, expenses, P&L and a full project ledger.
Vendors
Suppliers, what you owe each one, purchase orders that need a Manager's approval, and quotations with price trends.
Field Officers
Staff who spend money on site and are reimbursed later, with or without a project attached.
Labour & Subcontractors
Teams grouped by department, the work they do, what they are paid and what is still due.
Materials
The items you buy, grouped into categories, and the purchases made against each project.
Donations
Donations committed per project, such as to a temple, as a fixed amount or a share of the contract value.
Loans
Borrowings, their EMI schedules, payments made and what is still outstanding.
Other Expenses
Costs outside a single project: office, personal and savings, plus shared overheads spread across active projects.
Accounts
The cash and bank accounts money moves through, bank statement upload and the reconciliation queue.
Reports
Every report in one explorer, with filters, column choice and export to Excel or PDF.
Administration
Users, roles and permissions, module configuration, masters, audit logs, an integrity check and notification channels.
Every main page also has a How it works guide in its top-right corner that explains what the page is for and the usual steps.
From bank statement to agreed books
Payments are usually recorded before the bank statement arrives. Reconciliation matches each bank line to what was already recorded, so nothing is booked twice and nothing is missed.
- Upload the statementThe file becomes a draft batch. Lines that are already in the system are flagged as duplicates.
- Review the draftFix parse errors, drop unwanted rows, and optionally say which project each line belongs to. A debit can be split across projects; a credit cannot.
- CommitAccepted rows become bank transactions, all pending. Nothing is posted to the ledger at this stage.
- Work the queueEach line shows suggested matches with a confidence score. Accept a suggestion, match by hand, or exclude the line with a reason.
- DoneMatched lines are reconciled. Excluded lines stay on record so a later import still recognises them.
Decisions that keep the numbers right
These are built into the database and the code, so they do not depend on anyone remembering them.
Budget first
A project cannot be created without a budget by cost category. Its estimated cost is the budget total, and each later change is saved as a new revision.
Calculated, never stored
Outstanding amounts, bank balances and project costs are summed from the ledger each time they are shown. There is no balance column that could go stale.
Nothing is deleted
Financial records are reversed or voided, never removed. A reversal writes a mirror entry, and the ledger refuses edits and deletes outright.
Every change is logged
Who changed what, when, and the old and new values, written in the same transaction as the change. Audit rows cannot be edited.
Exact decimals, Indian format
Amounts are stored as fixed decimals, never floating point, and shown as ₹1,15,000.00. When an amount is split, the last share takes the rounding remainder so the parts always add up.
No double posting
Every action that moves money confirms its effect in words and numbers first and rejects a repeated request, so a double click cannot pay a vendor twice.
A Manager signs off
Purchase orders and BOQ revisions wait in the Approvals queue until a Manager approves them, and orders are checked against the project's BOQ.
Indian financial year
Business dates carry no time or timezone, so an entry on the 1st never slips to the 31st. Reports include This FY and Previous FY presets (April to March).
Who sees what
A user has one role, and a role is a set of module.action permissions such as
vendors.edit or bank_reconciliation.reconcile. The server checks
every request. Hiding a menu item is a convenience, not the security boundary.
| Role | Default access |
|---|---|
| Super administrator | Belongs to no company. Adds and deactivates companies, creates their first administrator, and can open any company with full access. |
| Administrator | Everything inside their own company, including users, roles, module configuration and audit logs. |
| Accounts Team | View, add, edit, export and print on the financial modules; approve on projects, expenses and payments; reconcile bank statements. No delete anywhere. |
| Project Manager | Day-to-day project work, limited to the projects they are assigned to. |
| Management | Read and export only. |
| Data Entry User | View and add on the transaction entry screens. |
Project scoping
Give a user access to specific projects and every list and report is filtered to them. Users with no project grants see all projects.
Separate companies
Each company has its own projects, masters, ledger, users, roles and settings. Every database query is filtered to the signed-in company.
Editable roles
Administrators can add roles and change permissions at runtime. The code never checks a role by name.
How it is built
A Next.js frontend talks to an ASP.NET Core API over /api/v1. The API is split into layers so that business rules have no dependency on the database or the web framework.
Api → Application → Domain, with Infrastructure for EF Core, file storage and importers. FluentValidation, Serilog, problem+json errors.DECIMAL(18,2), optimistic concurrency stamps, migrations checked into source.Local setup and demo data
Needs the .NET 10 SDK, Node.js 20+, and MySQL/MariaDB on localhost:3306 (XAMPP works). The full steps are in README.md.
# API (http://localhost:5095) cd backend dotnet tool restore dotnet ef database update \ -p src/Ledgerstone.Infrastructure \ -s src/Ledgerstone.Api dotnet run --project src/Ledgerstone.Api \ --urls "http://localhost:5095" # Web (http://localhost:3000) cd frontend npm install npm run dev
# With the API running, fill an empty database: # 5 construction projects with budgets, vendors, # labour, purchases, payments, a loan and a donation node scripts/seed-demo.mjs # a few entries dated this month, for the # monthly dashboard on demo day node scripts/seed-demo.mjs --recent-only # a second company: ANSS Uns Crafters, # an interior design and fit-out firm node scripts/seed-anss.mjs
| Development sign-in | Password | |
|---|---|---|
| Administrator | admin@ledgerstone.local | Admin!23456 |
| Super administrator | superadmin@ledgerstone.local | SuperAdmin!23456 |
| ANSS administrator | admin@unscrafters.local | Crafters!23456 |
These accounts exist only in development. A production install seeds no users; the first administrator is created with the Ledgerstone.SeedAdmin tool (see README.md and docs/deployment.md).