Security
Last updated October 8, 2026
This page describes how Foyer protects venue and guest data.
Hosting and infrastructure
Foyer runs entirely on Cloudflare's edge network (Workers, Durable Objects and R2 storage). There are no servers of our own to patch or expose — the application runs in Cloudflare's sandboxed runtime, behind Cloudflare's DDoS protection and web application firewall.
Each customer account is its own isolated database. One company's reports, accounts, and settings live in a database that no other company's requests can reach, and every request is routed to its own account before any data is read. Photographs and documents are kept in Cloudflare R2 object storage: one storage bucket holds every account's files, each under that account's own prefix, and every read, write, and delete is checked against the prefix of the account making the request.
We do not currently tie an account's data to a particular country or region. Cloudflare decides where each account's database is stored, and the AI, email, and text-message providers listed under Subprocessors process what is sent to them in their own facilities.
Encryption
In transit: all traffic is served over HTTPS with TLS. This includes the guest report form, the staff dashboard, and every API call.
At rest: all stored data is encrypted at rest on Cloudflare's infrastructure.
In the application: passwords are hashed with bcrypt and are never stored, logged, or emailed in plain text. Links and codes that grant access — scan identifiers, guest tracking links, password-reset links, sign-in codes, and recovery codes — are stored only as hashes. Authenticator-app secrets cannot be hashed, because the app has to compute codes from them; they are stored in your account's own database and are part of its backups (see below). Push notifications are end-to-end encrypted to each device using the Web Push standard (RFC 8291), so notification content is unreadable to the push relays that carry it, and they carry only where, how urgent, and which case — never a guest's words or contact details.
Access control
Access is role-based and enforced on the server, not just hidden in the interface. Head-office admins, location managers, and maintenance staff each get their own scope: a location manager sees only their own site, a maintenance account sees only the areas it has been granted, and every API route re-checks the caller's role and scope before answering. Additional permissions (such as letting a manager work the review queue) are narrow, individual grants rather than role upgrades.
Account admins can review who has access at any time on the Active users page, see each account's sign-in history, and download the full sign-in log.
Our support account is not one of your users; its address is shown on the Support access card in Settings. Without your permission it reads your account blinded: it sees the shape of your work — case references, issue types, severities, statuses, and dates — but none of its content. It sees no guest's words, no contact details, no photographs, no staff names, not which location a report came from, and none of your figures. It cannot change your cases, locations, inspection records, invoices, announcements, guides, or branding, and it cannot download anything. It can still administer accounts and settings — for example, set a temporary password or clear a lost second factor when one of your users is locked out, or change a setting — and it reads the bug reports and assistant feedback your staff send to us. When you need us to look closer, an administrator can turn on temporary support access for 1, 4, 8, or 24 hours; it ends by itself and can be ended early. While it is on, support can read your account's content, download a backup, and make changes at your direction. Every support sign-in, every grant, and any early end to a grant is emailed to your administrators, and your pages show a notice while support is present.
Authentication
Passwords must be at least 12 characters and pass a strength check that refuses common passwords, repeated or sequential characters, and the person's own name or email address; they are then hashed with bcrypt. The rule is the same for every account — there is no separate password policy to configure. Accounts created by an admin start with a temporary password that must be replaced at first sign-in. Sign-in attempts are rate-limited.
Two-step verification is available with an authenticator app (TOTP), with a six-digit code sent by email, or by signing in with a passkey, including Face ID and Touch ID on supported devices. An account admin can require two-step verification for every admin and developer account: such an account uses its passkey or authenticator app where it has one, and otherwise receives a six-digit code by email. Location manager and maintenance accounts are not covered by the requirement, because back-office computers are often shared. Sessions are server-side, end after 7 days or after 12 hours without use, and can be reviewed and revoked individually from Settings.
Data retention and deletion
Your data is retained for as long as the subscription is active, except where the app deletes it sooner — for example, a guest's email address is deleted as the one email is sent, or after 90 days, and the sign-in log keeps 180 days. Our Privacy Policy lists every retention period. Account admins can download a backup from Settings while the subscription is active (see Backups below for what it contains), and export detailed reports as PDF and spreadsheets.
When a customer leaves, deletion is scheduled with an explicit request that names the account — on the customer's written request, or by us at any time after 60 days following termination. Nothing changes for 30 days, during which the deletion can be called off; then the account's database — reports, photographs held in it, accounts, and settings — is deleted, along with the photographs and documents the account stored in file storage, and its web addresses stop resolving. Cloudflare keeps 30 days of point-in-time history of each database, so deleted data can remain recoverable there for up to 30 days after deletion. Data-subject requests (access, correction, erasure) are handled together with the customer, who remains the controller of their staff's and guests' data, within one month of the request.
Backups and disaster recovery
Stored data is durably replicated by Cloudflare as part of its Durable Objects storage, which also keeps 30 days of point-in-time history of each account's database. Independently of that, account admins can download a backup file from Settings whenever they choose while the subscription is active.
A backup is not a copy of everything. It contains every report, account, and setting, and — so that a restore never locks anyone out — every account's password hash, authenticator-app secret, recovery codes, and passkey public keys, so a backup file should be stored as carefully as a password. It leaves out the sign-in log, open sessions, guests' email addresses, bug reports, push subscriptions, and other short-lived or operational records. Photographs held in your account's database are included unless the admin chooses a backup without them; photographs and documents held in R2 storage are carried as references to the stored files, and invoice documents, inspection certificates, guide PDFs, and placard artwork are never included as files. Every download is recorded in the sign-in log, and we are notified by email.
Restores are carried out by us, not from a customer's own account: a restore replaces everything in an account, so an administrator must turn on temporary support access before we can run one. The export and restore paths are exercised by our automated test suite on every release, so a restore is a tested operation rather than a hopeful one.
Monitoring and logging
The service watches itself from both sides:
- Outside in: independent uptime checks probe the application — including the guest QR scan path end to end — from multiple regions, and alert on failure.
- Inside out: the application sweeps every account's health every 5 minutes and sends a heartbeat to our monitoring provider; if the heartbeat goes silent, an alert fires within about 15 minutes even if everything else looks fine (a dead-man's switch, so a failure that can't report itself still gets reported).
Inside the application, every action on a report — validation, release, notes, resolution, AI decisions — is recorded in that case's history under the name of whoever (or whatever) did it, and sign-ins are logged per account. The sign-in and security log keeps 180 days of entries.
Payments
Subscription payments are processed by Stripe. We never see or store full card numbers.
Guest anonymity
Guest reports are anonymous by default — guests are not asked to create an account or to give their name or phone number, and the form refuses a description that appears to contain personal details such as an email address or phone number. The one exception is the guest's own choice: an optional box (on by default; you can switch it off) to be emailed once when their report is resolved. That address is kept apart from the report, is never shown to your staff or sent to any AI provider, is left out of exports and backups, and is deleted as the email is sent, or after 90 days. Visit ratings are anonymous and carry no identifier. Each report records the language its form was shown in. Guest photographs are checked by an AI model before staff see them, and camera metadata such as location is removed before they are stored.
Subprocessors
Foyer processes data on behalf of its customers, and engages the following subprocessors. Because each account is isolated, no subprocessor ever receives a cross-customer dataset: each email, text, push notification, or AI request is made for one account and carries only that account's data, though one AI request can cover several of its reports — for example, a batch of the Needs review queue.
| Subprocessor | Purpose | Data touched |
|---|---|---|
| Cloudflare | Hosting, database and file storage, DNS, TLS, WAF | All service data, at rest and in transit, in per-account isolated databases and per-account storage prefixes |
| Cloudflare Workers AI, running TypeSafe AI's triage model | AI triage's first step — on by default, and it runs even with the AI assistant off; also picks which tools the assistant loads for each question | Each new guest report's words and translation, place, issue type, and seat, with short descriptions of open jobs in the same place; staff questions to the assistant and the previous exchange. |
| Anthropic | AI assistant, translation, AI verification and Two-step triage, guest-photo checks, and reading invoices, inspection certificates and guide PDFs where switched on — only while your AI assistant setting is on | Staff questions and the account data the answers draw on; report text and translations; guest photographs; uploaded documents; not used to train models |
| Resend (delivering via Amazon SES) | Transactional email | Staff email addresses and notification content, which can include what a guest wrote; a guest's address for the one "resolved" email |
| Twilio | SMS alerts, only where an account enables texting | Staff phone numbers; messages contain no guest-written text |
| Web push services (Apple, Google, Mozilla, or Microsoft, depending on the browser) | Push notifications to staff devices | Each device's subscription address; notification content they carry encrypted and cannot read |
| Stripe | Subscription billing | The customer business's billing details — never guest or operational data |
| Cronitor | Uptime monitoring and the status page | No customer or guest data — request URLs, response codes, and sweep counts only |
Switching off your AI assistant stops everything that goes to Anthropic, and with it translation, the guest-photo field, AI verification, and Two-step triage. AI triage has its own setting: its first step (One-step, the default) sends each new guest report to the triage model on Cloudflare Workers AI whether or not the assistant is on, and only setting AI triage to Off stops it.
If you switch on "Let staff connect their own AI assistant" (off by default), the answers a staff member asks for are delivered to the AI provider they connected, under their own account; that provider is not our subprocessor.
Compliance
We maintain an internal security control register mapped to the SOC 2 Trust Services Criteria, with written policies covering incident response, breach notification, data-subject requests, and subprocessor management. We do not currently hold a third-party certification and won't claim one here until an independent auditor has issued it.
Under GDPR, Foyer acts as a processor for its customers. Our outbound email is authenticated with SPF, DKIM, and DMARC.
Incident response
Incidents are detected by the monitoring described above and by reports from customers and staff. Every incident has a named lead who owns it from triage through fix and communication; availability incidents are reported as they happen.
If a security incident involves personal data, we notify affected customers within 24 hours of becoming aware, with the facts then known, and follow up within 72 hours with the fuller picture — categories of data involved, likely consequences, and measures taken — so customers can meet their own notification obligations. Every incident ends with a written review.
Report a vulnerability
Email Security@foyerops.com with details of the issue. We aim to acknowledge reports promptly and will keep you updated while we investigate.
CineScope LLC · max@cinescope-app.com