Skip to content

Data protection pack

Security overview

Version: draft v1.3, 12 October 2026 (updated for parent and pupil surveys, safeguarding alerts, the Annual plan and refunds)

This describes the security measures in Benchmark.Pulse as built today. Anything not yet in place is labelled planned. Known limits are stated plainly. We would rather a DPO knew the gaps than found them later.

It is written against the DfE's digital and technology standards for schools, including the cloud solution and cyber security standards (https://www.gov.uk/guidance/meeting-digital-and-technology-standards-in-schools-and-colleges), and Article 32 of the UK GDPR.

Summary

Measure Status
UK hosting of the database and storage (Supabase, London) In place [check: production project region]
Row Level Security on every table, with explicit table and column privileges In place
No direct access to responses or invitations for anyone but the server In place
Hashed, single-use personal links, emailed only by us, token kept out of web server logs In place
No identifiers stored with responses; no "used on" date on invitations In place
Invitation emails deleted when the link is used, 30 days after sending, or at close; surveys close automatically at their closing time In place
Small-group, small-cell and secondary suppression; free-text redaction In place
Safeguarding alerts readable only by named safeguarding leads; no survey opens without one In place
Results download holds aggregates only In place
Atomic payments; one paid report per survey; refunds processed by the system In place
Audit log In place
Encryption in transit and at rest In place via suppliers [check: Supabase and Netlify documentation for our plans]
MFA for school accounts Planned
Automatic retention deletion Planned
Documented backups and tested restore Planned
Cyber Essentials Planned before launch; Cyber Essentials Plus within the first year
Independent penetration test Planned (recommended before launch; not yet in the build plan)

Hosting and infrastructure

  • Database, authentication, storage and server functions: Supabase, London region (AWS eu-west-2) [check: confirm on the production project].
  • Web app: a static site on Netlify. It holds no survey data; all data is fetched from Supabase after sign-in, or through the two respondent functions.
  • Email: Resend, for sign-in codes, survey links and reminders, safeguarding alerts, and billing and support email.
  • Public server functions: a few functions take requests without sign-in: the Stripe and email webhooks, links in our emails (unsubscribe, approval, quote) and the reminder sign-up form. Each checks a signature, a signed token or a shared secret, or, for the reminder form, limits how often it can be used. None of them returns survey data to the caller.
  • Payments: Stripe Checkout. Card details go straight to Stripe and never reach our servers. Stripe's payment confirmations are accepted only with a valid Stripe signature.
  • Encryption: all traffic uses HTTPS. Supabase encrypts data at rest [check].
  • Secrets (the database service key, the Anthropic, Resend, Stripe and Apollo keys, and the webhook and scheduled-job secrets) are stored as server function secrets and never shipped to a browser.

Access control

Row Level Security (RLS) is switched on for every table. Table privileges for signed-in and anonymous users start from nothing and are granted explicitly, so a new table is not exposed by default.

Data Who can read it
Survey responses No one directly. RLS is on with no policies, and no privileges are granted to signed-in or anonymous users. Only server functions using the service role can read it, and they apply suppression before returning anything. The exception is a comment flagged for safeguarding: its original text is copied into a safeguarding alert (next row)
Safeguarding alerts (original, unredacted comment text, the question, the matched words, when it arrived, and the review outcome) Named safeguarding leads only. Owners and other members see only that an alert is waiting and for how long, never what it says
Invitations (emails, token hashes) No one directly, as above. School users see counts only, through a function that checks membership
Surveys Members of that school, except the open-link code, which only owners and editors can read, through a function
Reports, purchases, plans, credits Members of that school. A report is readable only once unlocked
Invoices and credit notes The school's owners and editors
Refund requests, team member emails and pending invitations The school's owners only
Audit log The school's owners only
School directory, question bank, benchmarks, price list Any signed-in user (public or non-personal data)
Product usage events and sales records Benchmark.Pulse platform administrators only. Events hold counts, statuses, products and prices, never survey content

Roles within a school account: owner, editor, viewer and DSL. Only owners and editors can create, edit, open, close or distribute surveys, unlock reports, remove comments, and download results. Viewers and DSLs can read results and unlocked reports. Only owners manage the team and ask for refunds. An owner can also name any member a safeguarding lead; a member with the DSL role always is one. Only safeguarding leads can read safeguarding alerts. Owners may change only the school's display name and benchmarking choice directly; other school details are set by server functions.

Anonymous access is limited to exactly two database functions: loading a survey from a personal link or open link, and submitting a response. Every other function has execute rights removed from anonymous users, and the payment and retry functions are callable only by the server.

Changes to surveys go through server-side functions that check the user's role, so the rules are enforced in the database, not only in the browser. For example: questions lock once the first response arrives; benchmarked question wording cannot be altered; custom questions are limited to scale, free text, or single choice with 2 to 6 options; a survey cannot open until the school states how many people it will ask (1 to 5,000); and every survey checks comments for safeguarding concerns, so none can open until the school has named a safeguarding lead.

How anonymity is protected

  • Links go only from us to the person. Personal links are emailed by Benchmark.Pulse direct to each person and are never shown to a school user. The only exception is a developer's own machine (ENVIRONMENT=local), where no real email is sent. In production the service refuses to send links if no email provider is configured, and will not send email for a school account until it has been verified.
  • Hashed, single-use tokens. Each personal link carries a random token. Only its SHA-256 hash is stored, so the database never holds a working link. A token is created when the link is sent, and a reminder issues a fresh one, so the old link stops working. When a response is submitted the invitation is marked used, so the link cannot be used twice.
  • Token kept out of server logs. The token sits after "#" in the link (/s#token). Browsers do not send that part of a link to the web host, so it does not appear in Netlify's logs.
  • No join between invitations and responses. The responses table has no reference to invitations. A response stores the survey, the channel (personal or open link), the self-selected group (for example role or year group), the answers, a list of any answers withheld for safeguarding, and the day only. No token, user ID, IP address, user agent or time is stored. Invitations keep only a used flag, not the day the link was used. Limit: a safeguarding alert records when it arrived, to the second, so it can be escalated after 2 hours. That time stays on the alert after its comment text is deleted, and safeguarding leads can see it.
  • Emails deleted early. An invitation email address is deleted as soon as its link is used, 30 days after the link was sent, or when the survey closes, whichever comes first. Deletion on use happens in the same database update that marks the link used; a nightly job applies the 30-day rule; closing clears the rest. A scheduled job runs every 15 minutes and closes any survey past its closing time, and a school user can close a survey earlier. A survey with no closing time, such as a staff exit survey run all year, keeps no address for more than 30 days.
  • Known limitation. Marking a link as used and storing the response happen in one database transaction, and the link's email address is deleted in that same transaction, so a used invitation no longer holds an address. Someone with direct database administrator access, which only Benchmark.Pulse staff have, could in principle watch the database while a person answers. We do not do this, and the data processing agreement forbids it. Supabase request logs also record the IP address of requests, including survey submissions, for a limited period [check: log retention for our plan].
  • Suppression before anything is shown. In the server code that builds every headline, report and download:
    • no results below the minimum response count (10 for every survey except staff exit, which needs 5 and combines leavers over a rolling 12 months);
    • no group under 10 in staff surveys, or under 5 in parent and pupil surveys, judged per question using the number who answered it; live year-group counts in parent and pupil surveys hide groups below the same size;
    • hidden groups are pooled: while they hold fewer than 10 people together, the next smallest visible group is hidden too, so a hidden group cannot be worked out by subtraction;
    • any answer option chosen by fewer than 5 people is shown as "fewer than 5", with the same pooling for single-choice questions, whose options add up to the total;
    • no free text below the free-text minimum (10 for every survey except staff exit, which needs 5), and no comments for any question with fewer than 5 comments;
    • comments flagged for safeguarding are kept out of the report, the AI commentary and the download.
  • Padding guard. Invitation lists are capped at 1.2 times the stated headcount. If responses exceed the headcount, every role result is withheld and the report says why. Limit: anyone with the open link can submit, and a determined school leader could still add responses to try to isolate a small group. These measures reduce that risk; they do not remove it.
  • Redaction. Names with titles, first names, class codes, email addresses, phone numbers, links and initials are removed from free text before it is shown, downloaded or sent to the AI. In the paid report the AI also lists any comment that still identifies someone. Leaders can remove a comment; removal deletes it from the stored report and the results download, cannot be undone, and the report says how many were removed.
  • Safeguarding alerts. Every survey checks each comment as it arrives against a list of words and phrases that may indicate harm, and flags comments in scripts the check cannot read. A flagged comment's original, unredacted text is stored in a safeguarding alert that only named safeguarding leads can read. Leads are emailed within about 5 minutes; the email contains no comment text. An alert not reviewed after 2 hours is sent again to the leads, and owners are told that one is waiting, never what it says. If an alert email has not gone out after 15 minutes, the team sees a warning in the app. Comment text is deleted 30 days after a lead reviews it. Limit: an unreviewed alert keeps its text.
  • AI commentary is a per-survey setting, on by default except for pupil surveys, where it is off by default. Nothing from a survey is sent to Anthropic when it is off or before a full report is unlocked, and flagged comments are never sent.
  • No individual rows leave the service. The results download, available to owners and editors once a survey closes, contains the same suppressed figures as the report, plus the redacted comments listed separately from all other answers in random order. Raw response rows are never released, to the school or to anyone else.

Payments

  • Schools pay for a report or the Annual plan by card through Stripe, or by invoice on 30-day terms. Invoices and credit notes are issued and held by Benchmark.Pulse, not Stripe. Prepaid credits are not currently sold.
  • One paid report per survey, enforced by a unique index in the database.
  • Credit spends and unlocks under the Annual plan lock the school's record first, so two simultaneous requests cannot both succeed.
  • A card payment is marked paid exactly once, only for the exact amount expected, and only unlocks a report that is still locked. Repeated notifications from Stripe are harmless.
  • A failed report can be retried without paying again, one retry at a time.
  • Refunds: a card payment is refunded through Stripe and an unpaid invoice is cancelled with a credit note, both without anyone deciding. A refund of an invoice already paid goes to Benchmark.Pulse staff to return the money by bank transfer.

Audit log

Recorded with the acting user's ID and a timestamp: school account created, survey created, closing date extended, AI commentary switched on or off, invitation emails added (count only), links sent or reminders sent (count only), team member added, safeguarding lead named, safeguarding alert reviewed (with the outcome), comment removed from a report, results downloaded, report unlocked (and by which method), report first opened, invoice issued, plan started or renewed, and refund requested, processed, escalated or failed. Owners can read their school's log. Planned: record survey open and close, role changes and sign-ins.

Authentication

  • Sign-in is by a one-time code sent by email. Microsoft and Google sign-in are planned.
  • New schools are verified by matching the user's email domain against the school's website domain in the DfE register (GIAS). Unmatched schools stay unverified until checked by hand, and cannot send survey emails until then.
  • MFA: planned. MFA is not enabled in the project configuration. The plan is to require it for every school account, as the DfE cyber security standards expect for accounts with access to personal data.

Backups and recovery

Planned. Supabase takes daily backups on paid plans [check: plan and retention]. We will document the backup retention period, consider point-in-time recovery, and test a restore before launch. Deleted data remains in backups until the backup cycle completes.

Testing

Automated unit tests cover the statistics, suppression, redaction and AI validation logic, and end-to-end scripts cover the anonymous response flow, parent and pupil surveys, billing and refunds. Planned: an independent security review or penetration test before launch.

Certification

Cyber Essentials: planned before launch. Cyber Essentials Plus: planned within the first year. See https://www.ncsc.gov.uk/cyberessentials/overview.

Breach response

We will notify the school within 24 hours of becoming aware of a personal data breach affecting its data, so it can meet its own 72-hour deadline to report to the ICO (https://ico.org.uk/for-organisations/report-a-breach/). See the data processing agreement, clause 10. Planned: a written incident response procedure.

Contact

Security questions or vulnerability reports: [security contact email].