A booking system is rarely just a calendar. The moment someone reserves a slot, you're holding their name, email, phone number - and in a clinic, a salon, or a therapy practice, often something far more sensitive: why they're coming in.
That data is the most valuable thing you own, and the easiest thing to lose. One misconfigured table, one leaked token, one tenant able to read another tenant's rows, and the trust you spent years building is gone in an afternoon.
So at Timerise we don't treat security as a feature you switch on. We treat it as the architecture. Every layer - the network, the database, authentication, encryption, secrets, audit, and the tests that hold it all in place - assumes the layer above it could fail. That's defense in depth, and here's exactly how it works in our booking products.
EU data residency you can point to
Compliance starts with a simple question: where does my data physically live? For European customers, the answer needs to be "in Europe," with no asterisks.
Timerise runs on Google Cloud, Vercel, and Supabase - three providers that are independently audited, ISO 27001-certified, and HIPAA-ready, each backed by signed data processing agreements. We pin storage and compute to EU regions (Frankfurt for our highest-GDPR deployments), so personal data stays inside the European Economic Area by design rather than by accident.
That means when a customer asks where their patients' records are stored, you give them a region, not a shrug. Data residency is a configuration we own, not a hope we hold.
Security headers on every response
Before a single byte of application logic runs, the browser has already been told how to behave. We set hardened HTTP security headers globally, on every response:
| Header | Value |
|---|---|
Strict-Transport-Security | max-age=63072000; includeSubDomains; preload |
X-Content-Type-Options | nosniff |
X-Frame-Options | DENY |
Referrer-Policy | strict-origin-when-cross-origin |
Permissions-Policy | camera=(), microphone=(), geolocation=() |
Content-Security-Policy | locked-down baseline |
HSTS forces HTTPS for two years (and is on the browser preload list). X-Frame-Options: DENY and a frame-ancestors 'none' Content Security Policy make clickjacking a non-event. The CSP baseline starts from default-src 'self' and tightens from there - object-src 'none', base-uri and form-action locked to our own origin - so the set of places a page can load code or send a form from is small and explicit.
These aren't toggles a customer has to remember to flip. They ship on by default, everywhere.
Tenant isolation enforced in the database
Most multi-tenant breaches aren't dramatic exploits. They're a forgotten WHERE tenant_id = ? in some query written at 2 a.m. The only reliable defense is to stop trusting application code to remember.
So tenant isolation in Timerise lives in the database itself, through Postgres Row-Level Security (RLS). Every table carrying tenant data has policies that make a row invisible - for reads, writes, and inserts - to anyone outside its tenant. Combined with a server-first write model (clients never get a direct, privileged path to the data), one tenant simply cannot see or touch another's bookings, customers, or records. The database enforces it, even if a query forgets to.
This isn't a claim we ask you to take on faith. We prove it on every commit - more on that below.
Authentication built for sensitive workloads
Sessions are where convenience and security usually fight. We resolve it with Supabase Auth and a few non-negotiables.
- Hardened cookies. Sessions ride in HTTP-only, Secure, SameSite cookies managed by
@supabase/ssr- never readable by JavaScript, never sent cross-site. - Short-lived tokens with rotation. JWTs expire after one hour, and refresh tokens rotate on every use. A stolen, replayed refresh token is detected and invalidates the entire session family - so a leaked token is a dead end, not a master key.
- Scoped identity. Every request carries the user's role and tenant, and the authoritative access check runs server-side on protected layouts, not just optimistically at the edge.
- Brute force, blunted. Repeated failed logins trigger throttling and CAPTCHA escalation; sensitive API and auth routes are rate-limited with a token bucket.
- Strong credentials. Passwords must be at least 12 characters and are checked against known-breach databases at the moment they're set.
- MFA for the keys to the kingdom. TOTP multi-factor authentication protects owner and manager accounts - the roles that can see and change the most.
Encryption for health data (GDPR Article 9)
Health data is special-category data under GDPR Article 9, and we treat it that way - with a dedicated stack, not a checkbox.
Clinical fields live in their own isolated clinical schema and are protected with application-side envelope encryption: each tenant gets its own data encryption key, and that key is itself wrapped by a master key held in Supabase Vault or an external EU KMS - never in the repository, with a documented rotation policy. Decryption happens server-side only; the raw values never reach the browser. The stored columns are ciphertext, useless to anyone reading the database directly.
Before/after photos and other sensitive media live in a private bucket that has no public URLs at all. Access is granted only through short-lived signed URLs, issued after a server-side role check - so a link can't be guessed, scraped, or shared past its expiry.
Secrets that never touch the repo
The fastest way to leak everything is to commit a key. We make that hard to do by accident.
Secrets live only in the platform environment (Vercel env), never in the codebase; .env.local is gitignored and pulled on demand. gitleaks scans for credentials both in CI and as a pre-commit hook, so a stray key is caught before it ever reaches a remote branch. Encryption keys, as noted above, live in a vault or KMS - separate from the application entirely.
Every sensitive action is audited
When something does go wrong - or a customer, regulator, or auditor asks "who touched this record?" - you need an answer, not a guess.
Every mutation on clinical and financial data writes an append-only audit log row: who did it (the actor), when (timestamp), what (the entity), and a before/after diff of exactly what changed. Reads of clinical records are logged too, because in health contexts looking is itself a regulated event. The log is append-only by design - entries can be written, never quietly edited or deleted.
Proven, not promised: full test coverage
Security claims are worthless if nothing checks them after the next refactor. So the controls above aren't documented and forgotten - they're tested, and the tests gate every deploy.
- Unit tests with enforced coverage. Vitest with v8 coverage holds an 80% threshold on our core library code, including the encryption layer - round-trip correctness, tenant key isolation, and tamper detection (a modified ciphertext must fail to decrypt).
- The isolation matrix. Integration tests run against a real Postgres, not mocks, and assert the thing that matters most: tenant A can never read, write, or insert tenant B's rows, and the audit log stays append-only. A parallel clinical matrix proves special-category rows are visible to clinical roles and hidden from reception - and that stored columns are genuinely ciphertext.
- End-to-end smoke paths. Playwright drives the real booking flows on every deploy, with automated accessibility (Axe) checks that fail the build on serious or critical violations.
- Load tested. Weekly k6 runs keep hot paths fast under pressure, because availability is part of security too.
Lint, type-checking, and a dedicated RLS policy linter all gate CI as well. A change that weakens isolation doesn't get a stern code review - it gets a red build.
What this means for GDPR, ISO, and HIPAA
Frameworks don't secure systems; controls do. But it helps to see how these map:
- GDPR. EU data residency, Article 9 envelope encryption for health data, a complete audit trail, data minimization at the database layer, and signed DPAs with every subprocessor.
- ISO 27001. We build on ISO 27001-certified infrastructure and mirror its discipline in practice - least-privilege access, secret management, change control gated by CI, and tested isolation.
- HIPAA. The platform runs on HIPAA-ready infrastructure with the technical safeguards regulated health data demands: encryption at rest and in transit, strict access control, and audited access to protected records.
We don't hand you a framed certificate and call it a day. We hand you the architecture - and the tests that keep proving it's still true.
Summary
Security at Timerise isn't a setting; it's how the product is built. EU data residency, hardened headers, database-enforced tenant isolation, short-lived rotated sessions with MFA, envelope-encrypted health data, vaulted secrets, append-only audit logs - and a test suite that fails the build the moment any of it slips.
Your customers' data is the most sensitive thing you'll ever hold for them. Build it on a foundation that treats it that way.
Read our security & privacy documentation →
<br>Talk to us about your booking system
No sales script. Tell us what you are building, and we will tell you how we would build it.
Further reading
Booking APIs made simple: A beginner's guide to getting started
For businesses managing appointments, events, or rentals, a smooth booking system is essential. Whether you're a small business owner or a developer, ...
Timezone-Aware Booking API: Built for AI Agents & Custom Frontends
AI agents need precise timezone handling for cross-border bookings. See how Timerise GraphQL API uses UTC-first storage, IANA identifiers, and DateTimeISO.