Architecture decisions
This page summarises the decisions that shape the codebase. The authoritative, evolving source is the Linear document V1 Architecture Decisions; this page is the in-repo reflection of it.
Standing opinions
Section titled “Standing opinions”- Package manager: pnpm, exclusively. Enforced with
engines+engine-strict. - Monorepo: pnpm workspaces —
apps/*(andpackages/*as shared code emerges). - Lint + format: Biome, configured once at the root. CI runs
biome checkas a blocking gate.
Web framework: TanStack Start
Section titled “Web framework: TanStack Start”TanStack Start (Router + Query) fits an app built around large in-memory graph
state and optimistic editing better than Next.js or Remix. The data API is built
from server functions (createServerFn), not REST routes.
Supply-chain hardening: all @tanstack/* packages are pinned to exact
versions, CI runs with --frozen-lockfile, and Socket.dev monitors dependencies.
Database & auth: Supabase (PostgreSQL), EU region
Section titled “Database & auth: Supabase (PostgreSQL), EU region”One Supabase instance, two schemas — app and network. Row-Level Security is
on for every table. Data must stay in the EU (some cohort members work in
politically sensitive contexts) — this is a one-way door at provisioning.
Critical rule: no cross-schema SQL joins, ever. Any query needing data from both
appandnetworkis written as two queries assembled in application code. This keeps a future migration ofnetworkto its own database clean.
Graph database: PostgreSQL (network schema)
Section titled “Graph database: PostgreSQL (network schema)”At our scale (~180k nodes, ~400k edges across all maps) Postgres with good indexing is sufficient. Centrality and layout are computed client-side. Apache AGE is the escalation path before a standalone graph DB, if ever needed.
Hosting: Render.com, EU (Frankfurt)
Section titled “Hosting: Render.com, EU (Frankfurt)”Configuration-as-code via render.yaml (a web service for apps/app, a static
site for apps/docs). No manual dashboard setup; the same pattern translates to
a docker-compose.yml for self-hosters.
Visualisation: two renderers, one data layer
Section titled “Visualisation: two renderers, one data layer”@xyflow/react (React Flow v12) for editing mode; react-force-graph-2d for
visualisation mode. Both consume the same GraphData contract — the coupling
point between modes. Mode switching is a state change, not a data reload.
Self-documenting
Section titled “Self-documenting”This Starlight site lives in the repo and ships with the code. See Adding a feature for the docs-currency rule.