Recko
Reconciliation, commissions and payouts for high-volume transaction businesses — where the interesting number is not what matched, but what didn't.
- Role
- Architect & sole engineer
The application
Screens, captured from the running app
Booted against its seeded database and walked route by route — these are the real pages, not mockups.





The problem
An internet company takes money through a payment provider, the provider settles into a bank, and an internal ledger records what the company thinks happened. Three systems, three views of the same transaction, and none of them agree — because of timing, fees, partial refunds, duplicate webhook deliveries, and the occasional transaction that exists on one side and nowhere else.
Reconciling that by spreadsheet works until volume makes it impossible, at which point companies stop reconciling and start writing off the difference. The write-off is the leakage.
Matching, and being honest about what didn't match
The engine matches on reference first, then falls back to amount-and-date within a configurable tolerance. Anything left over is a break, and breaks are categorised rather than pooled:
- Timing — present on both sides, settled in different periods
- Amount mismatch — same reference, different value (usually a fee)
- Duplicate — the same transaction delivered twice
- Missing on A / missing on B — present on one side only
That taxonomy is the actual product. A single "unmatched" bucket tells an operator there is a problem; these five tell them which team to send it to. The current seed reconciles around 2,450 transactions at a 91% match rate, leaving roughly 250 breaks — deliberately, because a demo that matches everything demonstrates nothing.
Every match decision writes an audit record, including the rule that produced it, so a disputed match can be explained rather than re-run.
Commissions
A tiered, percentage and fixed-rate engine over the reconciled transactions, with refund reversal — when a transaction is refunded, the commission it generated is clawed back in the period the refund lands, not the period the sale did. Getting that wrong is how commission systems quietly overpay.
Runs are historical records, not recomputations: a commission run for last month keeps the numbers it produced, even if a rule changes afterwards.
Payouts
A payout is a state machine — draft, approved, processing, paid, failed — and the seed exercises the whole thing rather than the happy path, including failures, because the failure states are where the UI usually falls apart.
Architecture
Express and TypeScript over Prisma, with SQLite for development and PostgreSQL for production behind the same schema. JWT and bcrypt for auth. The job runner is in-process but written against a BullMQ-shaped interface, so moving reconciliation runs onto a real queue is a swap rather than a rewrite. The Next.js 14 dashboard reads through SWR; Recharts for the reporting surface.
The repository also carries the public marketing site alongside the operations dashboard — two quite different design registers in one codebase.