Security & privacy
EU-hosted, permission-scoped, and honest about what we do not have
Outbound work means handling personal data about people who did not choose to be in your database. That deserves a clear answer about where the data lives, who can reach it, and how long it stays.
EU data residency by construction
All infrastructure runs in AWS eu-central-1 (Frankfurt). Product analytics are on PostHog EU cloud and error monitoring is on the EU region. This is where the system is built, not a region toggle.
Scope by permission, not by job title
The all-versus-rostered data decision keys off explicit permissions rather than role, so a contractor SDR restricted to their own projects and an employee with full visibility can hold the same role and differ only by permission template.
Tenant isolation on every path
Tenant is resolved from a request header and validated by middleware, which attaches the account before any handler runs. Authorisation then verifies account membership. Cross-tenant access is a middleware concern, not something each route remembers.
Validated input everywhere
Request and response shapes are validated with Zod schemas rather than trusted, so malformed or unexpected payloads are rejected at the boundary.
Documented retention and erasure
GDPR retention policy, right-to-be-forgotten procedure and outbound email compliance notes are maintained in the repository alongside the implementation, so the policy and the code change together.
Short clocks on sensitive data
Call recordings and transcripts are treated as high-sensitivity personal data, with automated archival and cleanup jobs rather than indefinite retention.
Engineering practice
The guarantees that protect the money
Most of what makes a billing system trustworthy is not a feature. It is the set of invariants that hold when a job retries, a queue redelivers or a process dies mid-write.
Events published after commit
A domain event is never emitted before the database transaction that justifies it commits, so no consumer ever reacts to something that was rolled back.
Transactional outbox
Events are written to an outbox table and published by a drainer, so a crash between the commit and the broker cannot lose an event.
Idempotent consumers
Processed messages are tracked per (message id, consumer), so an at-least-once redelivery cannot double-handle. Money paths additionally carry database-level unique constraints.
Schema before code
CI applies database migrations before deploying the application, and a migration failure blocks the deploy rather than leaving code running against an older schema.
Secrets out of source
Opaque secrets live in the CI secret store and are synced to the runtime environment at deploy time; infrastructure-derived values come from Terraform. Neither is committed.
Pinned dependencies
Every dependency across every workspace is pinned to an exact version, so CI, production and a developer machine cannot resolve to different code.
Questions
Including the awkward ones
Do you hold SOC 2 or ISO 27001?
Where exactly is the data?
How is a deletion request handled?
Can our clients see each other’s data in the portal?
What about call recording consent?
Is there an audit trail?
Related
Book a walkthrough
Send us your security questionnaire
We would rather answer it properly than publish a trust badge. Architecture, data model and access controls, walked through with your team.
EU-hosted · eu-central-1 · integrates the CRM, calendar and telephony you already run