For the person who will ask how it actually works
You do not need this page to use Sales OS. It is here because somewhere between you and a signature there is an IT lead, a security reviewer or a curious CTO who will want it — so here is the whole shape of the thing: a browser tier that renders, a server tier that decides, a database that enforces, and the outside systems it keeps honest.
- 100
- Migrations
- 68
- Tables
- 161
- RLS policies
- 45
- DB functions
- 20
- AI features
- 10
- Scheduled jobs
What connects to what
Each boundary below is a real one — a different protocol, a different trust level, and a different failure mode.
Browser
React 19 · server-rendered shell, client-driven appTanStack Router
File-based routes
TanStack Query
Cache & invalidation
Tailwind v4 · shadcn/ui
Radix primitives
Tiptap · Recharts
Editing & charts
Application server
Nitro runtime · TanStack StartServer functions
One module per domain
Zod validation
Every boundary typed
Domain services
Pipeline, deals, meetings
Job runner
10 scheduled handlers
Integration clients
Graph · Odoo · OpenRouter
Export engine
docx · ExcelJS
Supabase
PostgresPostgres
68 tables · 161 RLS policies
Auth
Sessions & identity
Storage
Attachments & figures
Intelligence
OpenRouterModel gateway
Single provider surface
Structured output
JSON-schema responses
Web-grounded models
For research briefs
Systems of record
Customer-ownedMicrosoft Graph
Mail · Calendar · To Do
Odoo CRM
Leads · opportunities
Encrypted keys
AES-256-GCM at rest
Four decisions that shape everything else
Architecture is mostly the consequences of a handful of early choices. These are ours.
Typed from the button to the table
A click calls a server function whose arguments are parsed by Zod and whose return type flows back to the component. Database types are generated from the schema, so a column rename breaks the build rather than production.
The database decides who sees what
Authorization is expressed as row-level security policies next to the data, not as conditionals in the UI. A query issued from anywhere returns only the rows that caller is entitled to.
Sync belongs in the background
Nothing important waits for a page view. Scheduled handlers pull mail, calendar and CRM state, and every run is recorded with its duration, outcome and error.
Models are configuration, not architecture
Every AI call names a feature key; the model behind that key is chosen in Settings and routed through one provider. Swapping models is a dropdown, never a refactor.
One email, traced through the whole system
A single inbound reply touches every tier in the diagram above. Here is the actual path it takes.
A reply lands in Outlook
The inbox sync job pulls the thread through Microsoft Graph using a delta cursor, so only what changed comes across.
It is matched to a deal
Sender domain, contacts and existing links are scored against open opportunities. A confident match links the thread; an ambiguous one is left for a human.
The record moves
A deal event is written, activity is appended, and pipeline signals recompute — stage age, momentum, and whether the deal has gone quiet.
Work is proposed
The task generator turns commitments in the thread and meeting into tasks, and pushes them to Microsoft To Do so they surface where the rep already works.
An agent drafts
The drafter assembles the thread, client memory, meeting notes and prior documents into context, then streams a reply from the model assigned to that feature.
Documents compose
Estimation feeds the proposal; the approved SOW feeds the narrative. All three render from your templates against one set of numbers.
It leaves as a file
Export writes real DOCX and XLSX — styled documents with tables and figures, not HTML printed to a page.
Chosen deliberately, and kept small
Six groups, no duplicates, nothing in the tree that is not actually load-bearing.
Interface
- React 19Concurrent rendering
- TanStack RouterFile-based, type-safe routes
- TanStack QueryServer-state cache
- Tailwind CSS v4OKLCH token system
- shadcn/ui + RadixAccessible primitives
- Framer MotionInteraction & transition
Runtime
- TanStack StartServer functions as typed RPC
- NitroPortable server output
- Vite 8Build & dev server
- TypeScriptStrict, end to end
- ZodRuntime schema validation
- ESLint + PrettierEnforced in CI
Data
- Supabase Postgres68 tables, 100 migrations
- Row-level security161 policies
- Postgres functions45 server-side routines
- Supabase AuthSession & identity
- Supabase StorageAttachments and figures
- Generated typesSchema-derived, not hand-written
Intelligence
- OpenRouterOne gateway, many models
- 20 feature keysModel chosen per feature
- Structured outputJSON-schema responses
- StreamingToken-level UI updates
- Usage ledgerTokens and cost per call
- LlamaParseDocument ingestion
Integrations
- Microsoft GraphMail, calendar, To Do
- OAuth 2.0Per-user delegated access
- Odoo CRMTwo-way lead and deal sync
- AES-256-GCMConnection keys sealed at rest
- Delta cursorsIncremental, resumable sync
- Job registry10 scheduled handlers
Documents
- TiptapRich text with tables and figures
- docxNative Word output
- ExcelJSNative workbook output
- Turndown + markedMarkdown round-tripping
- Template engineEstimation, proposal, SOW
- RechartsPipeline and target charts