Finance SystemSolo Full StackIn Development

Financial Ledger & Reconciliation Platform

A multi-account financial ledger with CSV/PDF bank import, ACID transaction processing, and automated reconciliation across 5 accounts.

Ongoing development

A finance platform built to replace manual bank statement processing for a business managing 5 bank accounts. The platform imports statements in CSV and PDF formats, processes transactions with ACID guarantees, maintains a double-entry ledger, and generates reconciliation reports that previously required hours of manual work. The core engineering challenge was reliable, accurate import from inconsistent bank statement formats combined with financial-grade data integrity guarantees.

The business challenge

The finance team was downloading bank statements monthly, manually extracting transactions, cross-referencing against internal records, and building reconciliation reports in spreadsheets. Across 5 accounts with 1,000+ transactions per import cycle, this was taking days of manual effort, introducing transcription errors, and making month-end close unpredictable. The business needed automated import, reliable matching, and reports that could be generated on demand.

My role

Designed and built the entire platform — import pipeline, ledger architecture, reconciliation engine, and reporting layer.

Engineering challenges

Parsing Inconsistent Bank Statement Formats

Each of the 5 banks produces statement files in slightly different formats — different CSV column orders, different date formats, different ways of representing debits and credits, and PDF statements that require text extraction.

Built a format-detection layer that identifies the bank from file metadata and applies the corresponding parser. CSV parsers handle column mapping and normalization. PDF statements go through a text extraction pipeline that identifies transaction blocks using pattern matching before normalization. All parsed output flows through a shared normalization schema before hitting the ledger.

Duplicate Transaction Detection on Re-Import

Bank statements overlap at boundaries — importing January and February statements separately means some transactions appear in both files. Naive re-import creates duplicates in the ledger.

Each transaction is fingerprinted by a hash of date, amount, description, and account. Import attempts to insert with a UNIQUE constraint on the fingerprint. Duplicates fail the constraint and are skipped with a count reported to the user. This makes re-import completely safe without requiring the user to manage what has already been processed.

ACID Guarantees on Ledger Writes

A partial import failure — where some transactions committed but others didn't — would leave the ledger in an inconsistent state that was difficult to detect and dangerous to correct.

All ledger writes for a single import batch execute inside a database transaction. If any write fails — validation error, constraint violation, or database error — the entire batch rolls back. The ledger is always either fully updated or unchanged. Import status is tracked with a state machine: PENDING → PROCESSING → COMPLETED or FAILED.

Architecture

Import PipelinePython + pdfplumber + pandasBank-specific parsers with normalization layer
LedgerPostgreSQL double-entryACID transactions, duplicate fingerprinting, audit log
APIDjango REST FrameworkImport endpoints, transaction queries, report generation
FrontendNext.jsImport dashboard, transaction browser, reconciliation reports
ReportingPostgreSQL aggregationsMonthly summaries, account reconciliation, category reports

What we built

Multi-Format Statement Import

CSV and PDF bank statements from 5 different banks imported through format-specific parsers into a normalized ledger. Re-imports are safe — duplicates are detected and skipped automatically.

Duplicate Transaction Detection

Each transaction is fingerprinted on import. Duplicate entries from overlapping statement periods are caught by database constraint and skipped with a report to the user.

Double-Entry Ledger

All transactions recorded as double-entry pairs — debit and credit — ensuring the ledger always balances and every amount is fully traceable.

Automated Reconciliation Reports

Monthly reconciliation reports comparing ledger totals against bank statement balances across all 5 accounts — generated on demand in seconds.

Transaction Categorization

Transactions categorized automatically by description pattern matching, with manual override available. Categories feed into expense and income reporting.

Audit Log

Every import, edit, and categorization change is logged with timestamp and operator. The complete history of every transaction is traceable.

Technical highlights

Bank-specific parser strategy pattern — new bank formats added without modifying existing parsers

Transaction fingerprinting with UNIQUE constraint — duplicate-safe re-import without application-level checks

Batch import wrapped in single database transaction — complete success or complete rollback, no partial states

Import state machine — PENDING, PROCESSING, COMPLETED, FAILED — with status visible to user in real time

PDF text extraction pipeline with pattern matching for transaction block identification

1,000+ transactions per import processed reliably with full ACID guarantees

Built with
Django REST FrameworkPostgreSQLPythonpdfplumberpandasNext.js

Add screenshots here — product gallery, admin panel, or key screens.

The impact

5

Bank accounts managed

1,000+

Transactions per import cycle

CSV + PDF

Statement formats supported

ACID

Transaction guarantees

Automated

Duplicate detection on re-import

Business outcomes

Month-End Close in Minutes

Reconciliation that previously took days of manual spreadsheet work is now generated on demand in seconds from imported ledger data.

Reliable Import Pipeline

Re-importing statement files — whether by mistake or for correction — is completely safe. No duplicates, no partial states, no manual cleanup required.

Lessons learned

PDF statement formats are significantly less consistent than CSV — investing in a robust extraction layer before worrying about parsing saved considerable time

Transaction fingerprinting is more reliable than date-range deduplication because statement periods frequently overlap at boundaries

Next project