Skip to main content

The audit trail

Every state-changing operation writes an audit entry: who, what, when, on which entity, with the before and after values. This is not best-effort — it is enforced in CI. A state-changing route with no audit call in its import graph fails the build unless it carries a justified allowlist entry. Audit entries are also written on error paths and fallback redirects, because the failed attempt is often the interesting one.

What is masked

Sensitive values are masked before they are written. The masker covers authentication and security material — passwords and hashes, tokens of every kind, API keys, private keys, encryption keys, OTPs and PINs, confirmation codes — as well as identifiers like AHV numbers and IBANs, where enough is preserved for debugging (the last digits of an IBAN) without storing the value.
The masker does not mask salary amounts. Payroll audit rows can therefore carry compensation values in their before/after snapshots. This is precisely why audit:view is ADMIN+ only and is deliberately withheld from SYSTEM_ADMIN.

IP addresses

Client IPs are truncated before storage — enough to investigate an incident, not enough to track an individual.

AI operations

AI calls are audited as AI_OPERATION, with token usage in the metadata. What was sent for processing, when, and on whose instruction is a query rather than an investigation.

Version logging

Deployed versions are recorded, so an audit entry can be tied to the code that produced it.

Data subject requests (DSAR)

Under the revised Swiss data-protection act, a person can ask what you hold about them, ask for a copy, and ask for correction or erasure. The DSAR module handles the whole process.

Receiving a request

Requests arrive through a public endpoint — the requester may be a former employee or a rejected applicant with no account. That endpoint is protected:
  • CAPTCHA (Cloudflare Turnstile). Both CAPTCHA_SECRET and NEXT_PUBLIC_CAPTCHA_SITE_KEY must be set; a partial configuration fails closed, rejecting every submission with CAPTCHA_REQUIRED and logging a warning.
  • Identity verification by a confirmation link to the address on file, so a request cannot be used to extract someone else’s data.
  • A cooling period between requests from the same subject, so the endpoint cannot be used to hammer the system.

Processing

Preparing a response is HR work. Executing it — actually producing the export or performing the erasure — is ADMIN+, because erasure is irreversible.

What a request returns

An access request produces a structured export of everything held about the person across modules: their user record, applications, employment periods, absences, time entries, documents, correspondence, and payroll records.

What erasure does not remove

Swiss law requires records to be retained regardless of an erasure request: The response states what was erased and what was retained, with the legal basis. A response that quietly retains data is not a compliant response.

Swiss data protection

nDSG obligations, retention periods, and what the platform does about them.