ADR-0003: Database is Supabase (Postgres + pgvector + Auth)
We need a primary data store. Requirements:
- Status: accepted
- Date: 2026-05-27
Context
We need a primary data store. Requirements:
- Postgres (familiar, transactional, rich type system, pgvector for news embeddings)
- Auth — users sign in to author/deploy Skills; we don't want to roll our own
- Hosted — we're a small team, not running pg ourselves
- Vercel integration — auto env var provisioning, easy preview branches
- Realtime — Postgres
LISTEN/NOTIFYover a websocket bridge (needed at least for live-runner command dispatch; nice-to-have for future UI) - Storage for blobs (sim reports, optional Skill artifacts)
Candidates: Supabase, Neon, Vercel Postgres (deprecated, see knowledge-update doc), self-hosted on Fly/Railway.
Decision
Supabase as the unified database + Auth + Realtime + Storage layer. Provisioned via the Vercel Marketplace so env vars auto-populate. pgvector enabled for news embeddings.
All apps and packages access the DB through packages/db — a thin wrapper exposing a typed Supabase client. No app instantiates createClient(...) directly.
Alternatives considered
Alt A — Neon (pure Postgres serverless)
- Best-in-class branching (per-PR DB branches, per-sim-run DB branches)
- No bundled Auth — would need to add Clerk or build our own
- No realtime bridge built-in
- Storage requires Vercel Blob or S3
- Not picked: the 3-product bundle Supabase gives us (Postgres + Auth + Realtime) is more useful than Neon's branching, given we'd otherwise need to bolt on Clerk + something for realtime. Branching is nice but solvable with a
sim_run_idcolumn.
Alt B — Self-hosted Postgres on Fly
- Cheap at scale, full control
- Operational burden (backups, upgrades, monitoring)
- Not picked: premature optimization for a pre-MVP product. We'll absorb operational toil only when needed.
Alt C — Planetscale / Turso
- Distributed-first, eventual consistency model
- Not picked: trading data needs strict consistency; the eventual-consistency upside isn't worth the constraint.
Alt D — Supabase + separate Auth (Clerk)
- Clerk is excellent
- Adds another vendor + another bill
- Not picked: Supabase Auth is good enough for MVP. Migrate to Clerk later if/when we outgrow it (Auth is well-isolated behind a single helper).
Consequences
Positive
- One vendor for DB + Auth + Realtime + Storage = one bill, one dashboard, one set of credentials
- Postgres + pgvector means our news embeddings live next to the news table (no cross-store joins)
- Supabase Realtime is just
LISTEN/NOTIFYexposed — same channel the live runner uses internally for commands; we can repurpose for future UI - Vercel Marketplace install auto-provisions env vars across Vercel envs
- Supabase RLS gives us per-user data isolation enforced at the DB layer, not the app layer
Negative / trade-offs
- All-in on a single hosted vendor; switching cost is real
- Supabase Auth is less polished than Clerk for advanced flows (org management, social SSO matrix). Acceptable for MVP.
- We lose Neon's per-PR branching for previews — schema changes ride in the same DB across preview deploys. Mitigate with careful migration discipline.
- Realtime scaling has known limits (concurrent subscriptions); not a concern in MVP
Things we'll need to revisit
- If we add team/org features with complex RBAC, evaluate Clerk migration
- If we hit Supabase Realtime scale limits, front it with our own SSE layer
- For backtests with very large bar datasets (>50M rows), evaluate moving bars to DuckDB/ClickHouse and keeping just metadata in Supabase
References
docs/architecture/data-model.mdpackages/db/(when scaffolded)- Supabase docs: https://supabase.com/docs
ADR-0002: Agent runtime is Vercel AI SDK v6, routed via Vercel AI Gateway
Every Skill is, at its core, a structured call to an LLM with tools. We need an SDK that:
ADR-0004: Live runner runs on Fly.io Machines (one per deployment)
The live trading runtime has constraints that don't fit Vercel Functions: