South African personal information law requires more than a checkbox. Here's exactly how Zyden protects your residents' data — and yours.
Every personal identifier is encrypted at the application layer — before the INSERT. The database never sees plaintext names, phones, or ID numbers.
Column-level, not database-level
Full names, phone numbers, and other personal identifiers are encrypted with AES-256-CBC (256-bit key, random IV prepended to every ciphertext) at the application layer. Each field is independently encrypted.
HMAC-SHA256 · Never decrypted for lookup
South African ID numbers are special category data under POPIA — quasi-biometric. Zyden never stores them in plaintext. A keyed HMAC-SHA256 blind index is stored instead. This allows deduplication (same person, multiple schemes) without ever decrypting the SA ID for the lookup.
# What the database sees:
id_hash: a3f8c2d1e9b7... (HMAC-SHA256)
encrypted_id: AES256CBC(IV || ciphertext)
# What is never stored:
id_number: 9001015009087 ✕
Password reset tokens are SHA-256 hashed before storage. The raw token exists only in the email sent to the account holder — never in the database.
Access is not based on session state alone. Every admin request re-verifies the caller's role against the database.
Four roles — admin, trustee, owner, resident — stored in an access_map table. Every admin route executes a DB query to confirm the caller holds admin or trustee role for the active complex before processing.
Each estate operates on its own subdomain. Session context is bound to the subdomain. A resident from one estate cannot authenticate on another — even if they have an account on both.
Global admin access (for managing agents overseeing multiple schemes) requires explicit IS_SUPER_ADMIN flag in the database. It cannot be acquired by role or session manipulation — we actively tested and fixed this.
Not just what happened — who did it, when, and from where. The audit log is append-only and not editable through the admin console.
When a resident signs the complex rules during onboarding, Zyden logs: the vault item ID, the acting identity, the signature name they typed, their IP address, and the timestamp. This record is retained even if the vault item is later replaced.
This creates a defensible POPIA-compliant record of consent at the time of onboarding.
Every state-changing POST request requires a CSRF token. Token mismatch triggers a 403 — no silent bypass.
The forgot-password endpoint is rate-limited to 5 attempts per IP per 15 minutes. Rate-limited requests receive the same success message — no oracle for attackers.
Password reset tokens are SHA-256 hashed before database storage. The raw token exists only in the email — not in the database.
Sessions are scoped to the active complex. A session token from one subdomain cannot be reused on another.
Vault document downloads validate file paths with realpath() before serving. Paths outside the upload directory are blocked.
All account creation and password setup flows enforce a 12-character minimum server-side — not just client-side.
We're happy to walk through the architecture with your IT or compliance team. No sales deck — just an honest technical conversation.