Architecture at a glance
One app in front of one database, and the database, not the app, decides who can do what. (A Next.js application over a single PostgreSQL database; the app is a client of it.)
How it's put together
Veristep is a Next.js 16 application (App Router, server components, server actions) deployed on Vercel, in front of a single PostgreSQL database on Supabase with its storage and authentication. There is no separate API tier and no message bus: a request runs as the signed-in person, every read and write goes through PostgREST (the database's own web interface) or a direct server-side connection, and Postgres decides what that person may do.
That last sentence is the design. The rules live in the database itself: authorization, evidence rules, freezes and audit are triggers, policies and security-definer functions there. The app gives friendly refusals, but it's never the only thing standing between a person and a row.
- Application
- Next.js on Vercel. Pages read as the signed-in person and forms write as that person (server components and server actions); a handful of route handlers stream exports and run scheduled jobs (crons).
- Database
- PostgreSQL on Supabase, AWS us-east-2. Every table checks who may see each row (row-level security). 79 idempotent, checksummed migrations.
- Files
- Private storage. A file opens only through a signed link that expires after an hour, and who can see it follows the record that points at it (Supabase Storage, private bucket, lt_evidence_ref).
- Auth
- Supabase Auth: email and password, with an optional second factor from an authenticator app (TOTP, AAL2 step-up). Passwords never touch our application code.
- AI
- Ten AI assistants run on a model provider behind one interface (Gemini today; Anthropic and OpenAI-compatible endpoints supported). They can act only through a fixed list of tools, each permission-checked (the tool registry).
Every module can come out (sidecars)
Each part of the product is a self-contained module you could take out without breaking the rest. The codebase is divided into named modules in a manifest (modules.json): every source file and every migration belongs to exactly one, a module may import only from those it declares, the graph is acyclic, and a module marked non-core is never depended on by a core one. An automated test enforces all of that, so the AI assistants, billing, drawings, RFID and the rest can be removed without the quality platform noticing.
- · modules.json and test/architecture.test.mjs
- · db/ — read the migrations in order; each file states its purpose at the top
- · 01-product/architecture/ — the threat model, ADRs and role model
These are files in our codebase. If you’re a customer under agreement, we’ll walk you through any of them.
