Subsystem 02.1 · 2025 — present
Syncore Microfinance Suite
Lending, general ledger & central-bank reporting
The system of record for a regulated microfinance institution: every loan, every payment, every ledger line and every report the central bank asks for.
01What it is
An end-to-end loan management system for a microfinance institution in Kosovo. Branch staff onboard clients, guarantors, co-borrowers and collateral; applications go to an approval committee; approved loans get a generated repayment schedule and a contract; payments, arrears, penalties and court cases are tracked day by day.
Underneath, every financial event posts balanced double-entry lines to a general ledger. Accountants run purchases, cash registers, journals and payroll in the same system, management gets twenty reports, and the regulator gets its official templates filled in.
02The problem
Microfinance in Kosovo is regulated like banking. Loans must be classified by days overdue and provisioned accordingly, the effective interest rate must be disclosed using the central bank’s formula, and monthly, quarterly and half-yearly reports go to the regulator in a fixed format.
The institution ran on a legacy SQL Server system whose business rules lived in stored procedures. Moving off it could not mean starting over: every client, loan and payment had to come across, and the old rules — including a few peculiar ones — had to keep producing the same numbers.
03What I built
- The lending core: annuity and flat schedules with grace periods and irregular first periods, the effective-interest calculation, penalties, payment allocation and payoff rules.
- A replayable loan-event engine that can rebuild any loan day by day and post its ledger entries — the same path serves the nightly job, catch-up after downtime, backdated corrections and bulk rebuilds.
- A smart migration off the legacy system: clients, loans and their full history moved across in dependency order, the old rules reproduced and verified, and a cut-over date from which the new engine takes over — so the institution switched systems without missing a day.
- General ledger, cash register, purchases, manual journals and payroll with Kosovo’s progressive tax brackets and pension contributions.
- Twenty management reports and the central bank’s Excel pack, driven by the regulator’s chart of about 5,000 accounts.
- Identity on OpenIddict + ASP.NET Identity, 76 permissions, and branch-scoped data access enforced on the server.
- PDF documents rendered in headless Chromium, real-time notifications, GitLab CI to IIS, and a Windows desktop build with native printing.
04Architecture
05Technology
- Interface
- Angular 19TypeScriptTailwindElectron 37
- Services
- .NET 8ASP.NET CoreEF Core 9OpenIddict 6SignalRFluentValidation
- Data
- SQL Server52 EF migrations
- Documents
- PuppeteerSharpClosedXMLEPPlus
- Delivery
- GitLab CIIISDocker Compose (dev)
06Engineering notes
- 01
Matching the regulator to the sixth decimal
The effective interest rate is solved with Newton–Raphson on the net present value of the cash flows, with upfront and spread fees handled exactly as the regulation prescribes and cumulative rounding to the cent. The tests reproduce the central bank’s own published examples: 9.381299%, 10.474957% and 10.368635%.
- 02
A loan you can replay
Any loan can be rebuilt day by day from any date — disbursement, month-end accruals spread across months, fee amortisation, payments, class changes, payoff, provisioning — with every step posting balanced ledger entries. One code path serves the nightly run, catch-up after downtime, backdated payment corrections and bulk historical rebuilds; a cut-over date guarantees migrated loans are never posted twice.
- 03
Classification that can’t drift
Thirty, sixty, ninety and a hundred and eighty days overdue move a loan through five classes provisioned at 1, 5, 20, 50 and 100 percent. Lost is terminal. Provisions post as net adjustments and are reversed and re-booked on every change of class, so the ledger always explains itself.
- 04
Financial statements as formulas
Seventy-eight balance-sheet and income-statement lines are defined as formulas over account-code subtrees — sums, differences and percentage splits — each with a drill-down endpoint. The regulator’s pack fills the official templates, including a matrix of loans migrating between classes month over month.
- 05
A smooth move off the legacy system
Twenty-four migration services move the legacy database in dependency order, in batches of five thousand, mapping old user identities and repairing dangling references on the way. The legacy T-SQL became an executable specification — the old 360-day schedule, the old payoff rule and historical payrolls are reproduced and tested — and the replay engine takes over from a cut-over date, so nothing is ever posted twice.
- 06
One query engine for every grid
A JSON filter tree — nested AND/OR groups, nine operators, filtered includes, sorting and paging — is compiled into LINQ expression trees on the server, powering the query builder behind every table in the app.
07Results
- 283
- API endpoints
- 50
- database tables
- 76
- permissions
- 20
- reports + regulator pack
- 24
- migration services
- 294
- commits
- Running the institution’s lending and accounting in production since late 2025.
- A smooth transition from the legacy system: every client and loan migrated with its history, the old rules reproduced and verified.
- Central-bank disclosure examples reproduced to six decimal places in automated tests.
The client institution is not named.