Seven stages, each isolated so one bad file cannot stop the batch. Only changed files run: the manifest diffs the filesystem on every start.
Small teams do not need someone waiting to be told what to build. Here is what you actually get.
On the RAG platform nobody handed me a spec. I defined the target scale, the file formats to support, the confidence thresholds and the failure behaviour, then built to them.
Every case study here lists the options I rejected and why. You will never inherit a design decision from me that has no reason attached to it.
React and Node on the front, Python or .NET services behind it, Docker and a queue in the middle, deployed and monitored. One person can carry a feature the whole way.
Not interview trivia. These are the specific places in the RAG platform where a data structure or a design decision was the difference between working and not working.
The manifest is a hash map keyed by SHA-256 content ID. Deciding whether a file needs reprocessing is a constant time lookup instead of a rescan, which is exactly what turns a 90 second restart into 4 seconds.
HNSW is a navigable small world graph, so choosing m=16 and cosine distance is a recall against memory trade off, not a default. Exhaustive search over 1024 dimensional vectors would not return inside a request.
Triage is a four tier cascade and gated OCR is a guard clause. Both are the same idea: put the O(1) deterministic test ahead of the expensive one so cost tracks the hard cases, not the volume.
Every stage is independently recoverable, manifest writes are temp file plus atomic replace, and the vector store has a numpy fallback. A crash mid batch costs you the current file, never the state.
Two internships, one degree, and a habit of reading the whole architecture before touching it.
Full stack and AI engineering, end to end. Open to startups in India, the US and Europe, on site in Hyderabad or remote in your hours. Full time or contract.
Drop in a pile of enterprise files in almost any format, readable or scanned, organised or not. The system reads them, works out what each one is, makes the whole repository searchable, and answers plain questions with citations back to the exact file and page.
Any file in, citable knowledge out. Technical deep dive below.
Ingestion runs offline and incrementally, writing to a vector index. Queries read from that same index online. A SHA-256 file manifest is what lets a restart skip everything that has not changed.
Enterprise repositories are not clean datasets. The brief I designed for was roughly four terabytes of raw material: scanned invoices as JPGs, PDFs with no extractable text layer, spreadsheets, Markdown notes, XML exports, and folders named random_dump. No schema, no labels, no guarantee a file is even readable.
Anyone can wire an embedding model to a vector store. The hard part is everything around it: getting text out of the unreadable half, classifying documents that arrive with no metadata, keeping ingestion cheap enough to restart daily, and making answers trustworthy enough that a finance team will act on them.
Every document needs a type and a department before it is indexed, so retrieval can filter instead of guessing. I explored three routes.
Fine tune a BERT style model on document types.
Send every document to the model and let it decide.
Cheap deterministic signals first, the LLM only as a last resort.
OCR on every page would have dominated ingestion time. Instead the parser extracts first and OCR is gated: it runs only when extracted text falls under 50 characters, then renders the page at 200 DPI and reads it.
Every file is hashed with SHA-256 and recorded in a JSON manifest with its status and metadata. On startup the scanner diffs the filesystem against it: new files are processed, modified files have old chunks deleted first, deleted files are cleaned out of the index, unchanged files are skipped entirely.
Pure vector search answered content questions but failed on counting and on questions about one named file. So the online path parses intent first, then assembles three layers of context into a single prompt.
The repository above is the exact prototype we deployed. It is public because I built it deliberately on free and open-source tools, so it could be shared. Taking it to production for the client was a different job, and I led it.
I designed and built it end to end on open tools: Groq for the LLM, BAAI/bge for embeddings, Tesseract for OCR, OpenSearch for the vector index. Everything runs from one docker-compose up.
I led a 10-engineer team that took this exact prototype to production on AWS. We moved every model in-account, so there are no external LLM calls, and the client's data, up to the 4 TB target, never leaves their environment. At scale we swap in more accurate models than the free ones the prototype ships with.
Every release meant a human clicking through the same flows and firing the same API calls by hand. It was slow, it was inconsistent between testers, and the parts that broke most often were the integrations between services, exactly where manual testing is weakest.
In parallel the product needed agents: LLM driven workflows that could take a backend task, call the existing APIs, and complete it without a person in the loop. Both problems shared a root cause, nothing was described in a reusable way.
The obvious route was to record and replay flows. I argued for BDD instead, and the trade off was real.
Fastest to a first green run. Anyone can record a flow.
Slower to the first test, because the step library has to exist first.
Page objects keep locators in one place, so a redesign touches one file instead of forty scenarios.
Integration paths get asserted at the contract level, where the failures actually were. Postman for the exploratory pass first.
Agents composed from small steps that call existing APIs, so each step is testable on its own rather than one opaque prompt.
The backend team pushed back on my first agent design: it called APIs the way a person would, one at a time, and it was too slow to sit in a real workflow. Their suggestion was to batch and to fail fast on validation before any LLM call.
I also stopped writing test documentation for testers and started writing it for the developers who would run the suite. Same content, different reader, and adoption changed completely.
Only you see this route. Checked against the server; never stored in the page.
Changes save to the server instantly and show across the site for everyone. Use Download JSON to keep a backup copy.
Edits save to the server and are live for every visitor immediately, not just this browser. The passcode is never stored in the page itself. Change it any time below.
Honest framing first: I did not design the OOPDAAS platform. I joined a globally deployed system as a backend intern, owned modules inside it, and learned how a 2 second SLA changes every decision you make. These are notes, not a portfolio piece about my architecture.
This is the experience I lean on when I design my own systems, and it is why the RAG platform is built around isolation, restartability and measurable budgets. That case study is the one to read if you want to see what I do when the architecture is mine.