Tenant isolation
Every database query is scoped to the requesting venue. Venue A cannot read venue B's orders, menus, staff or settings. Cross-tenant leakage is treated as a critical bug and is regression-tested across the backend.
Authentication and access control
- OAuth2 tokens for API and SPA access, issued by the platform
- Per-staff bitwise permission flags so a casual sees only the orders queue, not the entire venue
- Strong password policy on privileged accounts: 12 characters minimum, mixed case + numbers + symbols, checked against the Have-I-Been-Pwned breach corpus
- Login brute-force lockout with independent identifier and IP rate limits
- Optional MFA for elevated roles
Audit and traceability
Every privileged mutation flows through the audit service. Audit rows are append-only at the database level, with triggers that reject any UPDATE or DELETE. Optional secondary sinks write to object-lock-enabled S3 for an independent, WORM-stored audit copy.
Sensitive data
- Diner allergens and dietary information encrypted at rest (AES-256 via APP_KEY)
- Customer identity hashed with a salted HMAC; the cross-venue exposure gate sits at the consent layer, not the hash layer
- Payment card data never touches our servers; Stripe Elements handles the card field directly
Payments and webhooks
All payments are processed by Stripe under the Connect Express model. Webhooks are signature-verified, idempotent on Stripe event id, and stored as authoritative state. Order creation is gated on webhook confirmation, never on a client-side success callback.
Infrastructure
- Encrypted in transit (TLS 1.2+) and at rest
- Backups with point-in-time recovery on the primary database
- Deploys gated on a health check pass; failed deploys auto-rollback
- Sentry instrumentation on errors; rate-limited alert pipeline on critical audit events
Responsible disclosure
Found something? Email [email protected] with a description of the issue and a proof-of-concept where possible. We respond inside 48 hours and credit reporters on request.