A Financial Integrity Layer for Global Trade
This project represents the core infrastructure required to support high-value fintech operations like Enterprise Fintech Capital. In a ecosystem where retailers rely on Net-30/60 terms, the ability to accurately reconcile Credit Issued (Internal Ledger) against Cash Received (Bank Statements) is the foundation of liquidity management and risk control.
This engine is designed to provide the immutable proof of repayment needed to sustain a $60M+ credit facility, ensuring that working capital gaps are monitored in real-time.
- Reconciliation Engine: Automated matching logic (Exact & Partial matches).
- GraphQL API: Flexible data querying for dashboard and operations.
- Batch Ingestion: Optimized CSV parsing handling thousands of rows via batch upserts.
- Dashboard: Real-time visibility into reconciliation status (React/Vite/Tailwind).
- Observability: Structured JSON logging via
winston. - CI/CD: Automated testing pipeline via GitHub Actions.
- Backend: Node.js (TypeScript), Apollo Server (GraphQL), Prisma ORM.
- Database: PostgreSQL.
- Frontend: React 19, Vite, Tailwind CSS v4, Apollo Client.
- Infrastructure: Docker Compose, GitHub Actions.
Building the Enterprise Ledger: From Prototype to Production-Grade Financial Infrastructure
-
Start Services:
docker compose up -d
-
Start Backend:
npm install npm start
-
Start Frontend:
cd client npm install npm run dev -
Visit:
http://localhost:5173
This project demonstrates a "Senior Engineer" approach to building scalable financial systems.
- Challenge: Loop-based ingestion (finding and creating one-by-one) causes N+1 query performance issues.
- Solution: Implemented a Vectorized Ingestion Strategy in
IngestionService.- Parse all rows.
- fetch existing records in the date window (1 Read).
- Deduplicate in-memory using sets.
- Bulk insert new records (
createMany) (1 Write).
- Result: Complexity reduced from O(N) to O(1) database operations per batch.
- Tool:
winston - Strategy: Replaced
console.logwith structured logs.- Dev: Colorized, human-readable.
- Prod: JSON-formatted for ingestion by Splunk/Datadog/ELK.
- Context: Logs include metadata (
totalRows,insertedCount,matchCount) for easier debugging.
- CI/CD: GitHub Actions pipeline runs on every push.
- Pipeline:
Checkout->Install->Lint->DB Migrate->Test. - Tests: Unit tests for the Reconciliation Logic ensure financial accuracy.
Purpose: This section outlines the technical evolution from this prototype to a Production-Grade Financial System aligned with Enterprise architecture standards.
Current State (Prototype):
- Single Table:
LedgerEntry(Contains Amount + Direction + Metadata mixed). - Why we did this: Speed of implementation for the MVP.
Target State (Production): We must separate the Business Intent from the Accounting Impact.
Table 1: Transactions (The "Event")
id: UUIDtype:INVOICE_FUNDING,REPAYMENT_COLLECTIONreference_id: External ID (e.g., Stripe Payment Intent)metadata: JSON (User ID, Loan ID)
Table 2: Entries (The "Ledger") An immutable log of debits and credits.
id: UUIDtransaction_id: FK to Transactionsaccount_id: UUID (e.g., "Retailer_A_Wallet", "Platform_Revenue")direction:DEBIT|CREDITamount:BIGINT(Minor units, e.g., cents)currency:USD
Talking Point: "Currently, I store the ledger view directly. To scale, I would refactor to a
Transaction Header+Ledger Linesmodel. This allows one business event (e.g., a Repayment) to split across multiple accounts (Principal, Interest, Fees) atomically."
Current State (Monolith):
IngestionServiceruns in the same process.- Database is the shared state.
Target State (Event-Driven Microservices): We need to decouple "Intake" from "Processing".
- Ingestion Service: Parses CSV -> Publishes
bank-transactions-ingested. - Ledger Service: Consumes -> Runs Idempotency Check -> Publishes
transaction-recorded. - Reconciliation Engine: Consumes -> Matches -> Updates Status.
Talking Point: "I built a monolith for simplicity. In production, I would put a Kafka topic between the CSV Parser and the Database to handle backpressure."
Current State:
Decimal(10,2)for money.- Optimistic locking (Prisma defaults).
Target State:
- BigInt Checks: Store all money in cents (
amount / 100). Eliminates IEEE 754 errors. - Pessimistic Locking:
SELECT balance ... FOR UPDATE;to prevent double-spending during concurrent repayments.
Talking Point: "For extreme scale (10k+ TPS), I wouldn't store a
balancecolumn at all. I would use an Append-Only Log architecture where the balance is calculated on-the-fly from immutable entries."