The database and the files are encrypted at rest by the infrastructure provider. On top of that, Heltio encrypts four of the most sensitive fields on its own side, so that reading the database alone is not enough to recover them.
What gets extra encryption
| What | Where |
|---|---|
| Patient PESEL | patient record |
| Clinical note body | clinical note |
| Visit recording transcript | AI assistant session |
| Note draft generated from a recording | AI assistant session |
Beyond that list, the practice's P1 integration certificates are also encrypted — kept in separate columns, with the fingerprint and expiry date visible in the wizard.
Not additionally encrypted: a foreign national's document number, bank account numbers, attachment metadata, and patient addresses. The previous version of this page listed them as covered.
How it works
Every value gets its own single-use key. That key encrypts the content with AES-256-GCM, which also detects tampering. The single-use key is then itself encrypted with the master key and travels together with the encrypted content in a single string — there is no separate key table.
That string also records the fingerprint of the master key used to seal it. This makes a master-key rotation detectable, and lets the old key serve for reads only for a while, while new writes already use the new one.
Encryption and decryption happen in the database access layer, not in individual places in the code. The consequence cuts both ways: no new screen can forget to encrypt, but any script written around that layer will write the data in the clear. The scripts that write to these fields are listed by name in the code and guarded by a dedicated test.
An encrypted PESEL number cannot be searched by comparison. Alongside it we therefore keep a one-way digest of it, computed with an additional application secret — enough for lookup and for matching records, and not enough on its own to reconstruct the number.
Where the data sits
Database and files: Frankfurt. Keys: an environment variable of the application running in the EU. E-mail: an EU provider. SMS: a provider in Poland. Offline work in the mobile app: an EU provider. Translation: Germany. The full list together with the discrepancies: Processors and data processing agreements.
Traffic to the application server goes over HTTPS. The server responds with headers enforcing an encrypted connection for two years, forbidding framing and forbidding content-type sniffing.
How practices are kept apart
Separation of practice data is implemented in the application layer, not in the database: there are no row-level security rules in the migrations. Instead, every query for patient data must carry the practice identifier, membership is checked before the procedure runs, and over the whole thing stands a lint rule and a set of ratchets run on every code change — the number of places without the filter can only go down.
Backups
Backups are made by a separate, independent service. Its health is watched by a guard running inside the main application process — deliberately outside the backup service, because a dead service will not report its own death. The alarm fires when a backup was never made, when the last run ended in error, or when the last good backup is more than thirty hours old.
What is missing
- An external penetration test with a published summary. The previous version of this page cited such a report and a contractor; the document does not exist.
- PDF attachments to this page. Every link to a file in the
/legal/directory led nowhere — none of those files was ever added.