# The web app: sign-in, members, live presence and at-rest encryption

> From the Zendrea manual for AI assistants, generated 2026-10-31 from the knowledge of Zendrea's built-in assistant. All topics: https://www.zendrea.ch/llms.txt; all of them in one file: https://www.zendrea.ch/llms-full.txt. Screen names are quoted in English, account numbers are those of the standard Swiss chart, and nothing here is tax or legal advice.

- **Authentication & user accounts.** Zendrea runs in the browser, behind a login (cookie-based session).
- **Members panel** (Settings → Members). Invite team members to a company by email with a role of "owner" or "member"; owners have full access, members have restricted permissions on settings. Each company can have multiple users.
- **Live presence** in the Members tab — when another user is currently active in the same company, the tab tints amber until you open it. Useful for avoiding edit collisions.
- **Security panel** (Settings → Security) — optional per-company data protection ("at-rest encryption"). An owner sets a company passphrase; the company's figures, names, texts and documents are then stored unreadable on the server and are only readable during an unlocked session. All members share the same passphrase; it is shown in full on the Security panel of an unlocked device. A one-time recovery code is the only other way in — if passphrase AND recovery code are lost, nobody (including the operator) can restore the data, so the panel pushes regular .zendrea exports to external media as the user's own safety net. When a company is LOCKED on this device (encrypted, no key here): reports and lists show empty, Zendrea's built-in assistant cannot read them, the Security tab tints amber and a lock icon shows next to the company name in the header dropdown. The fix is always: Settings → Security → enter the company passphrase (an owner can alternatively use the recovery code). AI features still send the data they use to the AI service when invoked.
  - *Technical detail (how the encryption works: keys, salt, algorithms):* It is **envelope encryption**. Each company has one random 256-bit **Data Key (DEK)** that actually encrypts the data. The DEK itself is never stored in the clear: it is wrapped (encrypted) twice — once under a key derived from the passphrase, and independently once under a key derived from the recovery code — and only those two wrapped blobs live on the server. Key derivation is **PBKDF2-HMAC-SHA256 at 600,000 iterations** (OWASP baseline) with a fresh random **16-byte salt per wrap**, so the same passphrase produces a different wrap every time and the salt is stored alongside the blob. All encryption — data and DEK-wrapping — is **AES-256-GCM** (a fresh 12-byte IV per operation; the GCM authentication tag both prevents tampering and serves as the "wrong passphrase" signal, since an incorrect key fails the tag check rather than yielding garbage). Database fields are stored as "enc1:iv:tag:ciphertext" with the GCM additional-authenticated-data bound to the "table.column" name (so a value can't be moved to a different column); document files use a self-describing "ZENC1" container that embeds the DEK id. All cryptography runs **client-side in the browser** (WebCrypto); the raw DEK is held only in the browser's local storage on unlocked devices and is sent to the server per request in a header for the duration of the session — it is never written to the database. The recovery code is 20 Crockford-base32 characters (~100 bits of entropy). **Threat model, stated honestly:** this defeats *casual at-rest reading* of the database, backups, and files by the operator (everything on disk is ciphertext), but it is **not** end-to-end / zero-knowledge encryption — because the server holds the DEK in memory during an active unlocked session to run the accounting logic, a determined operator with live server access could in principle capture it. It protects data at rest, not data in use.
- **User menu** in the app header (sign out, account settings).

- **Only the company owner can import a journal** (members see the Import Data panel disabled); importing a whole-company JSON archive is open to any user, since it creates a new company rather than writing into an existing one (the topic [importing-data](https://www.zendrea.ch/docs/importing-data.md)).

**Common questions:**
- "How do I share access with my bookkeeper?" → Settings → Members.
- "How do I back up?" → Data is managed server-side; backups are operational.
