Document intelligence · SaaS · 2025 — 2026 · Live

FinSight

Turning a messy bank statement into clean rows, for a market that bank-linking APIs do not serve.

Visit FinSight
Sole engineer

Architecture, backend, AI pipeline, frontend integration, payments and deployment. The marketing site predated the build; everything from the API surface inward is mine.

How it holds together

Statement type
  1. UploadPOST /upload
  2. CSV parsepandas · normalize
  3. Markdown tablerow/column kept
  4. Batchgroups of 40
  5. CategorizeGroq · LLaMA 3.3 · json
  6. PersistSupabase Postgres · RLS
  7. Chat + analysisRAG · SSE stream

The parser branches on file type here. Everything downstream depends on which branch recovers usable structure.

The problem

Bank statements are one of the richest personal datasets most people own and one of the least usable. They arrive as CSVs with inconsistent column names, or as PDFs where the transaction table is a visual artifact rather than structured data. Getting anything out of them means manual tagging in a spreadsheet, which almost nobody sustains past the first month.

For Nigerian users the existing tools are worse than tedious. Western personal-finance apps depend on bank-linking APIs with poor or no coverage for Nigerian banks, price in USD only, and categorize against merchant vocabularies that do not recognize local transaction descriptors.

The gap is not analytical sophistication. Once transactions are normalized and labeled, category breakdowns, trend lines and outlier detection are cheap. The whole product hinges on turning a messy document into clean rows without asking the user to do it — for a market the incumbent ingestion method cannot reach at all.

What I built

Upload a statement as CSV or PDF and get back categorized transactions, monthly trend charts, anomaly flags on unusual spending, a chat interface answering natural-language questions against your own history, and an on-demand savings report.

Behind it: authentication, per-user data isolation, a freemium paywall with Paystack billing in NGN and USD, and a documented two-platform deployment.

FinSight’s upload screen, where a CSV or PDF bank statement is dropped in.

The architecture

A monorepo with backend and frontend as separate deployment targets. Files hit POST /upload and the parser branches on type — CSV through pandas with column normalization, PDF through pdfplumber for structured table extraction with pymupdf as a raw-text fallback when there is no recoverable table structure.

Extracted tables are re-serialized as markdown before reaching the model. It preserves the row and column relationship the model needs in order to know that a number is an amount and not a date.

Isolation lives in the database. Supabase Postgres with row-level security policies, and FastAPI middleware validating Supabase JWTs on every request — the guarantee is not in application code.

Anomaly detection runs z-scores over per-category monthly baselines, so it flags genuine outliers rather than large absolute amounts.

Decisions

  • Fixed-size chunking splits transaction tables mid-row. Retrieved context then contains an amount orphaned from its date and description, and the model answers confidently and wrongly. Chunking semantically around section headers with row boundaries as hard splits fixed it. The failure never surfaced as an error — only as answers that looked right.

Stack

Backend
FastAPI · Python 3.11 · Railway
Model
Groq · LLaMA 3.3 · JSON mode · LlamaIndex RAG
Parsing
pdfplumber · pymupdf · pandas
Data & auth
Supabase Postgres · Row-level security · Google OAuth · JWT middleware
Payments
Paystack · HMAC-SHA512 webhooks · NGN + USD
Interface
Next.js App Router · Recharts · SSE · Vercel

What it demonstrates

  • Structured extraction from genuinely unstructured documents
  • RAG over private user data with per-tenant isolation enforced in the database
  • Streaming inference behind an entitlement check
  • Real payment integration with signature-verified webhooks
  • Market-specific engineering where the incumbent approach does not reach
Next systemFarmTwin