Case study
CATSight.AI
A multi-tenant RAG system over scanned documents. It reads each page with a vision model, catalogues every document, and answers questions through a LangGraph agent that cites the passage and page it used. It began as my undergraduate thesis for MSU-IIT and is MIT-licensed, with a one-click public demo.

Problem
MSU-IIT keeps its institutional records, special orders and Board of Regents resolutions among them, as scanned PDFs. They could be opened and read page by page, but never queried. CATSight began as my undergraduate thesis to fix that.
What I built
A system that reads scanned records page by page, catalogues them, and answers questions with numbered citations that open the exact page.
- Organizations. Every document, tag and chat belongs to an organization, and every search, answer and agent run is scoped to the member's organization. Roles are per organization: admin, member, guest.
- Bring your own key. Each organization picks OpenRouter or OpenAI and pastes its own key, which is encrypted at rest and never shown again, or uses the server's Ollama. Saving checks the key with a real call. An organization without a provider is read-only.
- Reads scans, not just text layers. Every page is rendered and transcribed by a vision model that ignores "UNOFFICIAL COPY" watermarks and letterhead noise.
- Catalogues itself. One structured call per document writes the title, a summary, the document's own reference number, the issue date, tags from the organization's list, and two questions the document answers.
- A pipeline you can watch. Upload, read, catalogue, index, ready, live on the dashboard with per-page progress. A failure keeps its progress and shows why; a retry resumes where it stopped.
- The stack. React, TypeScript and Vite on the front; Django and DRF with Server-Sent Events for streaming answers; Celery and Redis for the pipeline; LangChain, and LangGraph with a Postgres checkpointer so chat history survives restarts; PostgreSQL 17 with pgvector and full-text search. It runs on Docker Compose on a Mac mini behind a Cloudflare Tunnel.
The coding-agent instructions are committed to the repository alongside a pinned skill set, and the test suite needs no paid model calls.
The hard part
Retrieval that finds identifiers. Records like these are cited by reference number and by name, so search is hybrid: semantic search (bge-m3) and Postgres full-text search run side by side, are fused with Reciprocal Rank Fusion, and are then reranked. Exact identifiers like SO 1592-2023 and surnames are found even when embeddings blur them.
Answers you can check. A LangGraph agent searches up to three times, answers only from what it found, and cites [1], [2] inline. Each citation opens the passage and the page it came from, so a reader can verify the answer against the scan instead of trusting it. Answers stream token by token, and you can stop, regenerate or edit a question.
Result
With the OpenRouter defaults, ingesting the 48-document thesis corpus (about 180 pages) cost about $0.30, and a question costs about $0.001, paid with the organization's own key.
The general edition is public. The live demo opens in one click with no sign-up, on a library of ten sample documents from a fictional water cooperative; the MSU-IIT thesis edition lives on its own branch. Running it in public took its own work: guest sessions in a demo organization that are read-only and deleted after 24 hours, per-visitor daily limits enforced atomically, a shared page budget, signed file URLs, and content-hash dedupe on upload.