Kommit is a multi-tenant platform — every customer ("organization") shares one application instance and one Postgres database, but every row belongs to exactly one organization, and the database itself refuses to return another tenant's data to your queries. This page explains how that boundary is enforced.
Where your data lives
- —Region: EU only. All application and database infrastructure runs on Hetzner Cloud inside the EU.
- —Hosting: Dokploy-managed services on Hetzner. We do not use Vercel, AWS, or any non-EU cloud for production workloads.
- —In transit: Every request is HTTPS-terminated at the reverse proxy; database connections from the application to Postgres are TLS.
How tenancy is enforced
Tenancy is bound at three independent layers. A bug in one cannot leak data across the others.
1. Connection-level database role
The application's Postgres connection authenticates as kommit_app, a
restricted role with DML but not superuser privileges. Workers,
migrations, and the admin console use a separate role (beheerder). The
role is fixed on the connection string, not per query — meaning the
running process cannot escalate inside a request even if a code path
forgets to call a guard. At boot we verify the connected role against
pg_roles and refuse to start if it doesn't match the expected one.
2. Per-transaction tenant context
Before any tenant-scoped query runs, the app sets app.current_org_id to
the requesting user's app-organization UUID inside the same transaction:
withTenant(appOrg.id, async (tx) => {
// every query inside this block is filtered to appOrg.id by RLS
});
Postgres row-level security policies use that current_org_id as the
filter. Forgetting to wrap a query in withTenant returns an empty
result set, not another tenant's data.
3. Authentication-bound organization
Your sign-in session is tied to your Better Auth identity, and membership rows map your user to exactly the organizations you belong to. When you switch organizations in the UI, the session's active-organization ID is rebound on the server side; a stale client cookie cannot grant access to an organization you were removed from.
What happens when you delete your organization
A hard org-delete cascades through every tenant-owned table — workflows,
decision events, projects, support transcripts, audit logs, and the
embedding stores all carry ON DELETE CASCADE foreign keys to
organizations.id. We don't archive your data under a different name
after you ask us to delete it.
The audit log
Every governed action writes a row to a tenant-scoped audit log that is:
- —Hash-chained — each row's hash includes the previous row's hash, so retroactive edits or deletions are detectable.
- —Scoped to your organization — admins from other tenants cannot read or write to your audit log.
- —Exportable — you can pull your audit log out at any time via the Audit page or the API.
What we don't claim
Kommit is not SOC 2, HIPAA, GDPR, or EU AI Act certified — those are audits against the customer's operation, not the platform's. What Kommit ships is the control library and the evidence-collection plumbing so that you can pass those audits with Kommit as the system of record. If procurement needs a specific attestation from us, tell us which one and we'll walk you through the gap.
Questions?
Email security@getkommit.ai or ask the chat widget in the corner —
it's grounded in this article and the rest of the helpdesk.