Vision is built for optical chains where customer prescriptions, billing records, and audit trails sit at the heart of regulated operations. This page summarises the technical controls in production today and the third-party certifications on our roadmap. It is not a substitute for a Master Service Agreement — but it should answer most of your security-questionnaire rows directly.
Tenant isolation
Every shop is a tenant. No row from one tenant is ever readable by another, regardless of the path taken — URL, search, audit log, error message, export. Isolation is enforced at the database, not just in application code, so an SQL injection or a forgotten WHERE clause cannot leak across the boundary.
Database-level row isolation on every tenant-scoped table
Per-request session GUC (app.organization_id) bound at the start of every transaction
RLS policies are tested explicitly — not inferred — by an integration suite that runs as the app role
Cross-tenant URL probes return 404 / 307 to the user's own organisation, never the foreign data
Audit log: append-only at the database
The audit log is append-only at the database grant level, not just in application code. The application database role has SELECT and INSERT on the audit_log table; UPDATE, DELETE, and TRUNCATE are revoked at the role-grant level. Even a server-side bug or a compromised application token cannot mutate audit history. Every export bundle ships with a SHA-256 chain hash and an HMAC signature so an external auditor can independently verify integrity — the verifier is open-source and ships in our repo.
Verifiable via pg_class.relacl (pg_table_privileges → app role: r/INSERT only)
Every state-changing action emits a structured row with key-level diffs
JSONB diffs render per-key (added/removed/changed), not raw blobs
External verifier: scripts/verify-audit-chain.mjs (Node built-ins only; see docs/runbooks/audit-log-verification.md). Exit 0 on a clean bundle; exit 1 on any row-hash mismatch or chain-link break
Encryption — what the application enforces
Every transport hop into and out of Vision is TLS-protected, and the secrets we store are hashed or encrypted before they hit the database. The bullets below are enforced at the code level — they ship with the application regardless of where you host it.
Browser → app: TLS 1.2+ floor, HSTS pinned in production (max-age 2 years, includeSubDomains, preload)
App ↔ database: SSL required in production. The DB client refuses to start if DATABASE_URL is set to sslmode=disable
Passwords: industry-standard memory-hard hashing (scrypt, N=16384, r=16, p=1, dkLen=64); never stored in plaintext, no recovery codepath that ever sees the cleartext
API tokens: SHA-256 hashes only; cleartext shown to the owner exactly once at creation, never logged or returned again
MFA secrets and recovery codes: XChaCha20-Poly1305 via the auth library's symmetric-encrypt helper; the encryption key is derived from BETTER_AUTH_SECRET, which fails hard at startup if missing in production
Authentication and access control
MFA is required for paid-tier OWNERs (T2+) and for every member of any org whose owner has set requires_mfa = true. Session cookies use HttpOnly + Secure + SameSite=Lax across every authentication-relevant endpoint. The session-signing secret fails hard at startup if the production environment is missing it — a misconfigured deploy refuses to boot rather than silently issuing weak sessions.
TOTP MFA enforced for paid-tier OWNERs and for every member of orgs with the requires_mfa toggle on; available to opt in for everyone else
Payment-processor webhook signatures verified via SDK (300s replay window enforced)
Trusted origins pinned to our own baseURL — callbackURL on email-verification + password-reset flows cannot bounce a user off-domain
E2E test endpoints have a hard NODE_ENV !== 'production' floor so a leaked staging deploy cannot accidentally enable them
Data residency and backups
Vision ships as a self-deployable application. Two parts of the residency-and-backups story are code-enforced and ship with the app; two parts depend on your hosting choice. We're explicit about which is which because a procurement form will be.
Code-enforced — self-serve export from /settings/data: JSON or CSV bundles with customers, visits, line items, audit log (including the per-org audit-chain hash so an external auditor with a past chain-head snapshot can verify integrity downstream)
Code-enforced — GDPR/PDPL erasure on customer request: PII fields wiped, visit history preserved with placeholder identifiers so reporting integrity is not lost
Hosting choice — primary region: pick a region whose data-protection regime matches your buyer's residency. UAE/KSA for PDPL, EU region for GDPR-aligned operations. Vision's reference deployment runs in a UAE region; self-deployers pick what fits
Hosting choice — at-rest encryption + backup retention: enable encryption at rest at the storage layer (RDS, Supabase, Cloud SQL all default it on) and configure ≥30-day point-in-time recovery. Vision does not ship its own backup orchestration; we rely on the managed database provider
Security headers (ASVS L2 §V14.4)
Every Vision response carries the baseline security headers: X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, Content-Security-Policy with same-origin defaults plus the Stripe payment iframe, Strict-Transport-Security pinned in production, and X-Powered-By stripped to remove server fingerprinting.
Vision is built to support compliance with the UAE Personal Data Protection Law (PDPL) and the EU General Data Protection Regulation (GDPR). The cookie-consent banner ships with no third-party trackers firing before opt-in. The contact form, the dashboard, and every authenticated surface respect a denied analytics consent without degrading functionality.
Cookie-consent banner with explicit opt-in for analytics
Analytics SDK does not boot until consent is granted
All in-product analytics events use first-party identifiers; no cross-site tracking
Right to erasure honoured at the customer level; right to export self-serve at /settings/data
Vulnerability management and disclosure
Vision runs a recurring offensive-security walk against the production code path (the cybersec persona walk in the repo's `ux-reports/` history). Each walk produces a verified-controls report and an issues list, both checked into the repo. We welcome responsible disclosure from external researchers — write to the address below and we'll reply within one business day.
Internal security-walk skill executed each release cycle; reports live under `ux-reports/<run>/`
Verified-controls list in `ux-reports/2026-05-04b-security-walk-testdrive/checks-passed.md` (re-walk produces a fresh dated report)
Public security disclosure address: security@visionsaas.example (reply within one business day)
Certifications: present and planned
We are honest about what we have and what's on the roadmap. Vision is not yet SOC 2 or ISO 27001 certified. Both certifications are on our 2026 roadmap. The technical controls listed above are in production today; the audit-evidence collection and third-party assessment are the deferred work.
Today: technical controls verified by internal security-walk
Q3 2026: SOC 2 Type I audit kickoff (planned)
Q4 2026: ISO 27001 readiness assessment (planned)
PDPL alignment: continuous
Have a security question we didn't answer?
Procurement teams, CISOs, and infrastructure architects: we'd rather have an explicit conversation than a copy-pasted questionnaire. We typically reply within one business day.
Suspected breach? See our 72-hour response runbook — disclosure within the regulatory window is a contractual commitment, not a courtesy. Breach response procedure