Narawe turns a professional services firm's stack of scanned and uploaded PDFs into something searchable and summarised. Every document runs through OCR, keyword extraction and embedding, and comes back out through a hybrid search that blends exact keyword matches with semantic similarity. It is a working platform in active build, not a finished product, and its own engineering notes say so plainly.
The problem
Professional services firms sit on years of paper: scanned engagement letters, correspondence, statements, uploaded PDFs that never became searchable text. Nobody can find a specific clause across a client's history without opening file after file by hand, and nobody has time to re-read every document to remember a client's current situation. Narawe's pipeline exists to close that gap: OCR the image-based pages, extract and embed the text, and keep a standing summary per client rather than leaving that work to memory.
What we built
A Next.js 16 platform on Supabase Postgres, with three core tables, firms, clients and documents, behind two roles: an admin who onboards firms, and a firm that manages its own clients and documents. Nine API route files carry twelve handlers between them: uploading and processing documents, bulk OCR and streaming OCR with live progress, reordering pages in a drag-and-drop organiser, and building the per-client portfolio. Search runs through two custom Postgres functions. One fuses a keyword rank with vector similarity using Reciprocal Rank Fusion, tuned constants rather than a black-box relevance score. The other runs trigram fuzzy matching for as-you-type suggestions. Thirteen pages sit on top, including a processing view that shows OCR progress live while a client scans and reorders pages.
How it runs
A document lands, gets OCR'd, and its text gets keyword-indexed and embedded. It moves through an explicit status machine, processing, ready or failed, with an atomic guard so the same document cannot be processed twice if a trigger fires more than once. Once a document is ready, portfolio synthesis starts as a fire-and-forget background job: Gemini reads a client's accumulated documents and writes a structured portfolio. If that step fails, only the portfolio's own status flips to failed; the source document is untouched. Every external call, OCR, embedding, portfolio synthesis, runs behind a centralised retry policy targeting the actual transient failure codes, and OCR itself runs in batches of three pages with nested retries, up to around nine attempts on a single page before it is marked failed.
Under the hood
Tenant isolation does not rely on every API route remembering to filter by firm. Row Level Security is enforced at the Postgres layer on all three core tables, gated by security-definer helper functions that resolve the current firm and check admin status, so a query that forgets to check firm membership still cannot return another firm's rows, because the database refuses it before the application ever sees the data. That is the same principle we build for clients elsewhere: put the constraint where a bug cannot reach it.
What changed
Narawe went from schema to a working OCR-to-portfolio pipeline with hybrid search in about three and a half weeks of active, solo build. It is still in build, and that is stated plainly here too: there is no automated test suite running today, and QA has run manually up to this point. What is shipped is the harder half, a deterministic pipeline, tenant isolation enforced at the database layer, and explainable search, ahead of the more visible parts still being finished.
