Architecture detail for InfoSec teams + technical buyers. The 7 layers between a customer's data and the public internet, in order.
1
Cloudflare edge — first contact
Every request hits Cloudflare first. WAF rules block common attack patterns. Rate limiting per IP. Bot detection. DDoS absorption. TLS 1.3 termination. Cloudflare cache for marketing pages; bypass for /api and /app.
WAF: OWASP Core Rule Set + custom rules
Rate limit: 1000 req/min per IP on /api/*
mTLS handshake for /api requests from known CIDR ranges
HTTP/3 + QUIC enabled
2
Application tier — Next.js + Node
Next.js 15 (RSC) on Hetzner VMs. Stateless. Horizontal scaling behind Cloudflare. Middleware enforces CSP nonce, security headers, request ID propagation. No secrets in process env at boot — fetched via 1Password Service Account.
JWT in HttpOnly + Secure + SameSite=Lax cookies. 30-day rolling sessions, killable from /app/settings. CSRF tokens on every mutating action. Magic-link emails are single-use, 48-hour expiry.
BCryptJS password hashing, cost 12
Failed-login lockout: 5 attempts → 15 min cooldown
MFA available; required for Owner role on Franchise plan
OAuth flows use PKCE; state nonce verified server-side
4
Authorization — RBAC + scope-checking
Every API route runs through withApi() which checks role + scope before touching the database. Roles map to permission sets; scopes are per-resource. The application code can\'t accidentally over-grant.
Permission denied responses don't leak existence (404 not 403 where appropriate)
5
Data layer — Postgres RLS
The load-bearing bit. Every tenant-scoped table has Row-Level Security policies that filter on tenant_id from a session variable. The application code can\'t bypass RLS — it connects as a non-superuser role.
inTenantTx() helper enforces SET adp.active_tenant_id at TX start
Cross-tenant query in CI tests: returns 0 rows, not 403
Audit logs cross-cut: each tenant reads own; no cross-tenant audit
Drizzle migrations diffed at build, applied at deploy with explicit RLS policy review
6
Encryption — at-rest + in-transit
AES-256 at rest. TLS 1.3 in transit. Per-tenant data encryption keys held in AWS KMS with HSM-backed key generation. Backup snapshots encrypted with the same envelope; cross-region replicated.
Envelope encryption: tenant key wraps data keys
Key rotation: annual baseline, immediate on suspicion
Recordings (Herald): separate encryption envelope, 30-day default retention
Database backups: 7-year retention encrypted at rest
7
Audit + observability
Every mutation writes an audit row with actor, IP, action, before-state, after-state. Anomaly detection on access patterns. Sentry for errors with PII scrubbing. Better Stack for structured logs.
Audit log retention: 7 years (SOX-aligned)
PII scrubber on every log line (regex + entropy heuristics)
Anomaly alerts: failed-login bursts, unusual API key usage
Quarterly access review with auto-revocation on offboard
What we don't do
Store credit-card data (Stripe Elements only — we're not in PCI scope)
Process protected health information (not in HIPAA scope)
Sell or rent customer data, ever
Allow third-party tracking pixels
Use customer data to train AI models
Cross-tenant queries from any application code path
Verifiable claims
Hit /api/healthz live: returns the production posture status
/security.txt + /humans.txt are standards-compliant
OpenAPI 3.1 spec at /api/openapi.json
CSP nonce visible on every page (view-source)
STS preload-eligible (verify on hstspreload.org)
Source code on request under NDA
Need to go deeper?
We share our threat model, internal pen-test reports, and architecture diagrams under NDA. Email security@ — most InfoSec teams turn around our docs in a day.