Getting started
Setup
Toolchain, Supabase project, environment files, the SEC corpus download, and the build checklist.
By the end of this stage the plumbing is done. A hosted Supabase project exists, both services have filled-in .env files, the 25-filing SEC corpus sits in data/downloads/, and you are on a development branch with a phased to-do list to build against.
None of this is glamorous, and that is the point. As Dave says in the video, "This is engineering in the real world. You don't just jump straight into your AI agent and say, build me this." Once the foundation is in place, everything after it moves fast.
Install the prerequisites
You need four things on your machine:
- Python 3.12+ with
uvfor the backend and all scripts - Node 20+ with
pnpmfor the frontend - Cursor or Claude Code as your AI coding agent (the repo's
AGENTS.mdfiles work with either; rename them toCLAUDE.mdfor Claude Code) - A GitHub account with
gitconfigured
Verify the runtimes:
uv --version
node --version
pnpm --versionClone the repo
The main branch is the starting point, with docs, guides, agent instructions, the data download script, and empty backend/ and frontend/ folders. The finished build lives on development if you ever want to peek ahead.
git clone https://github.com/daveebbelaar/document-copilot.git
cd document-copilotCreate the Supabase project
Supabase provides both the Postgres database (with pgvector) and email auth. Follow docs/guides/supabase-setup.md in the repo, or use the short version:
- Sign up at supabase.com (free tier is enough) and open New project.
- Name it (Dave uses
driftwood-capital) and set a strong database password. Save it. You need it for theDATABASE_URLlater. - Pick a region close to you, and remember it. Your Railway services should later deploy to the same region. If the backend sits in Europe and the database in the US, every query pays for a network hop across the ocean.
- Leave enable automatic row-level security checked, then create the project and wait until it reports healthy.
RLS is why the anon key can safely live in the browser later. With row-level security enabled and policies configured, a logged-in user can only touch their own rows. Without it, a public anon key is a back door into your database.
Create an OpenAI API key
Go to platform.openai.com, create a new API key (name it after the project so you can revoke it later), and copy it somewhere safe. You will not call OpenAI until the ingestion and agent phases, but setting it up now means the environment is complete in one pass.
Configure environment files
Both services ship with a committed .env.example. Copy each one and fill in real values; the .env files themselves are gitignored, so check git status and confirm nothing secret shows up.
cp backend/.env.example backend/.env
cp frontend/.env.example frontend/.envThe frontend needs only browser-safe values:
VITE_API_BASE_URL=http://localhost:8000
VITE_SUPABASE_URL=https://your-project-ref.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-public-keyFind the project URL and anon (publishable) key under Project Settings, API in the Supabase dashboard. The anon key is safe in the browser only because RLS is enabled; that is the deal.
The backend gets the same URL and anon key, plus two real secrets:
SUPABASE_URL=https://your-project-ref.supabase.co
SUPABASE_ANON_KEY=your-anon-public-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-secret-key
DATABASE_URL="postgresql://postgres:your-password@db.your-project-ref.supabase.co:5432/postgres"
OPENAI_API_KEY=sk-your-openai-api-keyTwo details here trip people up every time:
- The service role key bypasses RLS. It allows privileged access to everything in the project. It lives only in
backend/.env, never in the frontend, never in git. DATABASE_URLmust be a session-level connection. In the dashboard click Connect and use the direct connection or the session pooler string. Do not use the transaction pooler URL; Alembic migrations require a session connection. And put quotes around the whole URL. If your database password contains special characters like#or%, they break env file parsing without quotes. Dave hits exactly this in the video and the quotes are what fix it.
The remaining backend variables in .env.example (embedding model, retrieval tuning, ALLOWED_ORIGINS) can keep their defaults for now.
Download the corpus
The repo ships with data/download.py, a zero-dependency script that pulls 10-K filings from SEC EDGAR. Open it and set your user agent first; SEC requires a contact address on API requests:
# Params: edit these, then run `uv run data/download.py`
USER_AGENT = "Document Copilot your.email@example.com"
TICKERS = ["AAPL", "MSFT", "NVDA", "AMZN", "GOOGL"]
FILINGS_PER_COMPANY = 5Then run it from the repo root:
uv run data/download.py
# Downloaded 25 filing(s) to .../data/downloads
# Manifest: .../data/downloads/manifest.jsonThis fetches the last five fiscal years of 10-Ks for the five companies, organized by year, plus manifest.json, an index recording ticker, form, filing date, accession number, source URL, and local path for every file. The ingestion pipeline later reads its metadata from this manifest. The downloads are gitignored because the corpus is large.
Open one of the .htm files in your browser to see what you are dealing with. Each filing is hundreds of pages of narrative, numbers, and tables. This is the raw material the whole system exists to make queryable.
Generate the to-do list
Before building anything, have your AI agent turn the brief and the architecture into a phased checklist. Dave's prompt in the video, paraphrased, asks the agent to help set up a checklist in docs/todos.md and to figure out the most logical way to set up the project, backend or frontend first, so the architecture gets implemented and the client brief satisfied.
This is also the point in the video where Dave stops typing prompts and starts dictating them. The dictation bar you see popping up is Glaido.
Glaido is the #1 dictation tool for developers, and the one Dave uses throughout the video.
Try Glaido freeThe result in the repo is docs/todos.md, ten phases from Phase 0 (prerequisites) through Phase 9 (deployment), starting backend-first because a frontend without a backend is an empty shell. The ritual for the rest of the build is to work top to bottom, check items off between phases, and keep coming back to this file so you and the agent always share the same picture of what is done and what is next.
Phase 0 is exactly what you just did:
## Phase 0: Prerequisites & foundation
- [x] Install toolchain: Python 3.12+, `uv`, Node 20+, `pnpm`
- [x] Create Supabase project and collect credentials
- [x] Create OpenAI API key (needed from Phase 6 onward)
- [x] Set `USER_AGENT` in `data/download.py` and download sample 10-K corpus
- [x] Confirm `data/downloads/manifest.json` lists AAPL, MSFT, NVDA,
AMZN, GOOGL filings (2021-2025)Create a development branch
Keep main clean and do all work on a branch:
git checkout -b developmentThis mirrors the public repo, where main stays the tutorial starting point and development accumulates the finished build.
Checkpoint
Before starting on the backend, confirm:
uv --version,node --version, andpnpm --versionall work- Your Supabase project is healthy, with automatic RLS enabled, and you have the URL, anon key, service role key, and database password collected
backend/.envandfrontend/.envexist, are filled in, and do not appear ingit statusdata/downloads/manifest.jsonexists and lists 25 filings across AAPL, MSFT, NVDA, AMZN, GOOGL for 2021-2025docs/todos.mdexists with Phase 0 checked off, and you are on thedevelopmentbranch
Next: Backend foundation
Scaffold the FastAPI service, the settings module, SQLAlchemy models, and the first Alembic migration.