May 31, 2026

DOCSAI: how I structured a private PDF RAG app with citations

RAGNext.jspgvectorBetter Auth

DOCSAI is a document chat app designed around a simple rule: the assistant should answer from retrieved document context, not from general model memory.

The core flow is intentionally small and auditable:

  • Authenticated users upload PDF files.
  • The app validates and stores files privately.
  • A background worker parses pages with LiteParse.
  • A custom chunker prepares citation-ready fragments.
  • OpenAI or OpenRouter generates 1536-dimensional embeddings.
  • PostgreSQL with pgvector retrieves relevant chunks.
  • The chat answers only from retrieved context and cites sources like [S1].

Why I kept the stack boring

The project does not need LangChain, Redis, S3, or extra microservices for the first version. A focused stack makes it easier to debug ingestion, retrieval, and answer grounding.

The stack is:

  • Next.js, TypeScript, Tailwind CSS, and shadcn-style components.
  • Vercel AI SDK for streaming chat and provider integration.
  • LiteParse for PDF parsing.
  • Drizzle ORM with PostgreSQL and pgvector.
  • Graphile Worker for background ingestion.
  • Better Auth for email/password login.

Security decisions

DOCSAI is not a public anonymous chat. Uploads are private, signup can be closed, and local defaults bind services to 127.0.0.1. For a portfolio demo, the correct approach is a limited demo account with sample documents only.

What this proves

RAG quality is not only about the LLM. The boring parts matter: validation, chunking, background jobs, retrieval shape, citations, and auth boundaries.