Who can see your deals, and what enforces it
Your mailbox content, your client relationships and your commercial terms are in here, so the fair first question is who else can reach them. The controls below are structural rather than procedural — they hold because of where they sit, not because everyone remembers to apply them.
- 68
- Tables with RLS
- 161
- Policies
- 100
- Migrations
- 45
- DB functions
Six things that are true regardless of the code path
Each of these sits below the application, so no feature can be written in a way that quietly opts out of it.
Authorization at the data layer
Row-level security is enabled on 68 tables behind 161 policies. Access is decided by the database on every query — not by whichever screen happened to render. A bug in the UI cannot widen what a query returns.
Encrypted integration credentials
Per-user connection keys are sealed with AES-256-GCM — a random IV per record and an authentication tag stored alongside — before they reach a row, and are decrypted only inside server-side code paths.
Secrets never reach the browser
The client holds a publishable key and nothing more. Service keys, the model-provider key and the connection-key secret exist only in server modules that the client bundle cannot import.
Least-privilege integration scopes
Microsoft access is delegated per user through OAuth 2.0 with the narrowest scope set each feature needs. Odoo credentials are configured per workspace, never shared across tenants or baked into a build.
Schema as source of truth
Every change ships as a numbered migration — 100 of them so far, alongside 45 database functions. There is no drifted production schema, because there is no path that edits one by hand.
Auditable by construction
Job runs, agent runs and their steps, AI usage and cost, deal events and activity are all first-class rows. Reconstructing what happened is a query, not an investigation.
What each tier is allowed to hold
The useful question is not whether a system is secure, but what each part of it can reach when something goes wrong.
| Tier | Holds | Never holds |
|---|---|---|
| Browser | Session token, publishable key, rendered data the user may already see. | Service keys, provider API keys, other users' rows. |
| Application server | Secrets, integration clients, decryption of connection keys, job execution. | Anything it has not been asked for by an authenticated caller. |
| Database | Workspace content, with policies attached to the tables themselves. | Rows returned to a caller who is not entitled to them. |
What leaves the system, and what is recorded when it does
Drafting features send workspace content to a model provider. That is worth being explicit about rather than burying in a policy page.
- Only the context a feature needs is sent — the thread, the notes, the figures behind that one draft.
- Requests route through a single provider gateway rather than many direct integrations.
- Every call is logged with its feature, model, token counts and cost, so what left the system is reviewable.
- Administrators choose which models are enabled per feature, and may restrict that choice for members.