Three-Tier Isolation.
Not a Marketing Claim — An Architecture Decision.
Most service desk tools put all clients in one database and filter by ID. StrataDesk creates a separate PostgreSQL database for every client. Here's how it works and why it matters.
How Most Tools Handle Multi-Tenancy
Most SaaS ticketing platforms use a single shared database for all clients. Data separation depends entirely on application code adding WHERE client_id = X to every query.
What can go wrong:
- A missing filter in one API endpoint exposes all clients' data
- A reporting bug pulls rows from the wrong client
- A backup restores data from all clients, not just the one you need
- Offboarding requires DELETE across dozens of tables — miss one and data remains
- A compliance auditor asks "prove client data is separate" and you can't
This isn't theoretical. Multi-tenant data leaks happen regularly in shared-database architectures.
Three Tiers of Isolation
Each one independently verifiable
Most help desks give every customer a slice of one shared database, separated by a tenant identifier on each row. That separation is real, but it is enforced entirely by application code: a query missing its tenant filter is all that stands between one customer's data and another's. StrataDesk does not work that way. Each organisation using StrataDesk gets its own instance — its own application containers, its own PostgreSQL server, its own storage — and within that instance, every one of its client companies gets a separate PostgreSQL database with its own credentials. Isolation is a property of the deployment, not of a WHERE clause.
This changes what we can tell you when it matters. Erasure under Article 17 is DROP DATABASE on that client alone — immediate and verifiable, not a soft-delete flag left in a shared table. Copies persist in backups until they age out — up to 30 days in our own archives, which are encrypted and per-instance. We keep no whole-disk images of the servers themselves. Nothing restores an erased client without a deliberate act, and we would rather say that than claim an erasure that reaches into backups it cannot. Portability under Article 20 is a standard pg_dump of that client's database, in a format any PostgreSQL installation can read, with no other customer's records to filter out. Backups are taken per client, so restoring one does not touch the rest. And when a client's compliance officer asks whether their data is stored separately from the other companies you support, the answer is a database name they can point at.
Infrastructure Isolation
Each StrataDesk deployment runs in its own Docker containers.
| Component | Isolation |
|---|---|
| PostgreSQL | Dedicated container |
| Redis cache | Dedicated container |
| Backend (FastAPI) | Dedicated container |
| Frontend (Angular) | Dedicated container |
| File storage | Dedicated volume |
| Network | Isolated Docker network |
How to verify: docker ps shows your containers. Your database server is yours alone.
Database-per-Client Isolation
Each of your end-clients gets their own PostgreSQL database.
What this means in practice:
| Operation | Shared DB (Competitors) | Database-per-Client (StrataDesk) |
|---|---|---|
| Data leak risk | One bad WHERE clause exposes everything | Physically impossible — different databases |
| Backup one client | Complex extraction from shared tables | pg_dump stratadesk_acme (standard) |
| Offboard a client | DELETE across 48+ tables | DROP DATABASE (complete, instant) |
| Audit compliance | "Trust our application code" | "Here are the separate databases" |
| Performance isolation | One client's query slows everyone | Separate query plans per database |
How to verify: Connect to PostgreSQL and run \l — you'll see separate databases listed.
Access Control
Centralized user identity with scoped client access.
The stratadesk_shared database manages:
- User accounts — One account per person
- User-to-client mapping
- Role-based permissions (57 individual permissions)
- Per-client role scoping
- Session management
| user | client_code | role |
| Ana | acme | admin |
| Ana | beta | admin |
| Ion | acme | tech |
| Dan | gamma | tech |
How to verify: Query user_client_access to see exactly who has access to which client databases.
Compliance & Data Protection
GDPR
Encryption
On encryption at rest. Our hosting provider, Hetzner, does not encrypt Cloud server storage at rest, on the basis that each server and volume is private and isolated per customer. We have confirmed this with them directly rather than assuming it. Server images are per-customer, so another customer cannot restore your data, and when a server is deleted its image is removed using a hardware-supported deletion method — normally within 48 hours. We do not keep whole-disk server images: they would be unencrypted copies of every database on the instance, and the per-instance backups below cover recovery without that.
So we encrypt the data volume ourselves. Every database and uploaded file on a shared host lives on a separate volume encrypted with LUKS2 (AES-XTS, 256-bit key, 512-bit total). The host holds no passphrase: it requests one over TLS at every boot, authenticating as itself, and the volume is opened and mounted before the container runtime is allowed to start. A host that cannot obtain its key does not start your service rather than starting it on unencrypted disk.
What this protects, and what it does not. A volume that is detached, snapshotted, improperly wiped or otherwise separated from its host is ciphertext. That is the realistic provider-side exposure, and it is the one this closes. It does not defend a running machine: the volume is open the whole time the service is up, so anyone who compromises the live host, or us, reads it as plainly as we do. Full-disk encryption on a cloud server would not change that — the unlock key must either sit on the same disk, which protects against nothing, or be typed in by hand at every boot, which would make your service depend on someone being awake. We would rather describe the boundary than display a padlock that means more than it does.
What we do encrypt is the data that leaves the machine. Backups are encrypted with AES-256-GCM before upload, under a key you generate and hold, so you can decrypt your own backups without us. We store that key wrapped so unattended nightly backups can run — which means we can decrypt them too. We will not claim otherwise.
Data Sovereignty
| Deployment | Data Location | Control |
|---|---|---|
| Managed Cloud | Falkenstein, Germany (new instances) Romania (control plane and earlier instances) |
StrataDesk operates infrastructure |
| Private Cloud | Your AWS/Azure/GCP account | You control the infrastructure |
| On-Premise | Your physical servers | Full control, data never leaves your network |
On Managed Cloud, no data is processed outside the EU. Ticket content, attachments and per-client databases are held on our hosting provider's infrastructure in Falkenstein, Germany. The control plane — signup records, instance metadata and approvals — runs on our own hardware in Romania, as do instances provisioned before the German pool existed. Platform backups stay in Falkenstein; they are not copied to any other region.
Subprocessors
Last updated: 5 August 2026The third parties we engage to process customer data on Managed Cloud, in full.
| Subprocessor | Purpose | Data processed | Location |
|---|---|---|---|
| Hetzner Online GmbH | Instance hosting and platform backups | Ticket content, attachments, per-client databases | Falkenstein, Germany |
| Amazon Web Services | Backup archive storage, where an instance is configured to use it | Encrypted backup archives — ticket content, attachments, per-client databases | eu-west-1, Ireland |
| DNSimple | DNS and certificate issuance | None — hostnames only | US company; no personal data |
| Mailgun | Transactional email | Recipient address, subject line | EU endpoint |
Backup destinations you configure are not our subprocessors. If you point backups at your own S3, Azure, GCS or FTP storage, that storage is yours and runs under your credentials. We write to it on your instruction and hold no copy elsewhere.
We will notify you before adding or replacing a subprocessor, giving you the opportunity to object, as required by Article 28(2) GDPR. That commitment is Section 7 of our Data Processing Agreement, published in full so your legal team can read it before talking to us.
Incident Response
If we become aware of a personal data breach affecting your instance, we will notify you without undue delay and in any case within 72 hours, so that you can meet your own obligation under Article 33 GDPR. The notification will describe what happened, which categories of data were involved, what we have done, and what we recommend you do.
Because each client has its own database, we can usually tell you which clients were affected and which were not — rather than reporting that "an incident occurred somewhere in a shared system".
Report a suspected incident to security@stratadesk.io. It reaches Luiza Badaceanu, Administrator, who is accountable for the controls on this page and owns the notification decision — a named person rather than a queue, so you know who is on the other end of that address before you need them. Our supervisory authority is the Romanian National Supervisory Authority for Personal Data Processing (ANSPDCP).
Application Security
Authentication
- Password hashing with bcrypt (work factor 12)
- Configurable session expiration
- Two-factor authentication (TOTP), required for the platform administrator and optional for everyone else
- Single-use backup codes, stored hashed
- Per-device session tracking
- Forced logout capability
Authorization
- Role-based access control (RBAC)
- 57 granular permissions
- 1 platform role + 4 client roles, plus custom roles
- Per-client role scoping
API Security
- Token-based authentication
- Rate limiting
- Input validation (Pydantic)
- SQL injection prevention (SQLAlchemy ORM)
Callback & Integration Security
Recurring plans accept signed callbacks from your external scripts. Here's the trust model.
Per-token credentials
Each integration token is a pair: a high-entropy
bearer (128-bit) for Authorization and a
per-token HMAC secret (256-bit) for signing. Both are
minted server-side and shown exactly once. Rotation
is the only recovery path.
SHA-256 + HMAC pepper at rest
Bearer tokens are stored as HMAC-SHA256 hashes salted with a server-side pepper held outside the database. A DB leak alone doesn't expose tokens — an attacker needs both the dump and the pepper.
Replay protection
Every callback carries an X-Timestamp
header that must be within ±5 minutes of server time;
the timestamp is part of the signed payload, so an
attacker can't replay an intercepted request after
the window closes.
Idempotency keys
X-Idempotency-Key ensures retries
don't double-process. The same key on the same ticket
returns the cached response — no double counters, no
duplicate audit rows.
Tenant isolation enforced
Tokens are minted per recurring plan, which lives in one tenant's database. A callback can only resolve tickets in its plan — cross-tenant attempts are rejected at the handler level, not just at the DB layer.
Audit trail per delivery
Every authentication failure
(token_invalid,
timestamp_stale,
hmac_mismatch) emits an event into the
tenant's append-only event log alongside the
successful deliveries.
Backup & Recovery
Because each client has their own database, backups are clean and independent.
Per-Client Backup
pg_dump stratadesk_acme
pg_restore stratadesk_acme
Configurable Backup System
- Manual, automatic, and scheduled backups
- Configurable frequency: hourly, daily, weekly, monthly
- Multiple storage: local, S3, Azure Blob, GCS, FTP/SFTP
- Backup encryption and retention policies
How StrataDesk Compares to Industry Approaches
| Approach | Used By | Isolation Level | Risk |
|---|---|---|---|
| Shared database, row filter | Most multi-tenant SaaS | Application code | High — one bug = data leak |
| Shared database, RLS policies | Some enterprise tools | Database policies | Medium — policy misconfiguration |
| Shared instance, separate schemas | Some multi-tenant platforms | Schema-level | Low-Medium |
| Separate database per client | StrataDesk | Database-level | Lowest — physical separation |
| Separate instance per client | Enterprise on-premise | Infrastructure-level | Lowest, but expensive |
Questions from Security Teams
Vulnerability Disclosure
We invite testing on this page. It would be hollow without somewhere to send what you find.
Reporting
Email security@stratadesk.io with SECURITY in the subject. Tell us what you found, how to reproduce it, and what an attacker gains. Please don’t disclose publicly until we’ve agreed a date with you.
Machine-readable at /.well-known/security.txt.
What we commit to
- Acknowledgement within 3 business days
- Initial assessment within 10 business days
- Progress updates at least every 14 days
- Credit in the fix notes, if you want it
We don’t run a bug bounty and there is no payment. We’d rather say that up front than let you find out afterwards.
Testing authorization
- Self-hosted: test freely, no arrangement needed. Your infrastructure, your data.
- Managed cloud: schedule with us first — other tenants share that infrastructure, and we can’t tell your traffic from a real attack without notice.
Priority targets: cross-tenant isolation, authentication and session handling, the pool-host volume key release endpoint, and the backup and restore path.
Safe harbour
Report privately, don’t access or retain other people’s data beyond what it takes to demonstrate the issue, and give us a reasonable window to fix it — and we will not pursue legal action against you. We’ll put that in writing if you ask. Acting in good faith and getting it slightly wrong is covered; exfiltrating a tenant’s data to prove a point is not.
Security That's Verifiable, Not Promised
Don't take our word for it. Deploy StrataDesk and verify the architecture yourself. Separate databases. Separate containers. Auditable access control.
Security questions? Contact us