Skip to content

Data processing

What we would hold on your students, and the country it would sit in.

The page your advisor asks for by name. It is written the way the rest of this site is written, which means it leads with the answer an EU buyer will like least.

This is not a signed data processing agreement, it has not been through a lawyer, and it is not in force, because there is nothing running for it to govern. Written on 5 August 2026. Plausible’s version of this page ends by saying that use of the service constitutes acceptance and no signature is required; we cannot honestly say that, because there is no service to use.

So what follows is the design, published early on purpose. Every measure described below exists in the code today and every gap is named as a gap. The point of publishing it before the first customer is that you get to read it in your own time instead of asking for it and waiting, and that everything on it can be checked against what actually arrives.

One consequence worth stating first: there is currently no student personal data in this system at all. No tenant exists, no student has ever signed in, and the cloud project holds one bucket containing nothing but the infrastructure code’s own state file. No database, no service, nothing running.

The roles

Who is the controller, and who is not

The legal words matter here because they decide who answers to a regulator. They translate into English without much loss.
You
The controller. Your students are your students, your staff are your staff, and the record of who studied what is yours. You decide what is collected and why, and we act on your instructions.
Us
The processor. We hold that record only because we run the software it sits in. We have no use of our own for it and no product that would make one.
Your students and staff
The data subjects. A student never has an account with us — the account is with your school, the screen carries your name, and nothing in it names a supplier.
Sub-processors
The companies we use to run the software. There are four that could touch your data and one that is switched off; all five are named below, with what each one does.
What we are not
We are not a controller of your students, we will not contact them, and we will never market to them. We have no course of our own to sell, which is the reason the promise is easy to keep rather than a matter of restraint.

What would be held

Every category of personal data in the design

Taken from the database schema rather than from a description of it, which is why the last item can be stated as flatly as it is.
  1. 1

    Who your staff are

    An email address, a display name, whether the identity provider asserted the person controls that address, which sign-in method was used, when they were last seen, their role in your organisation, and whether they are active or suspended.
  2. 2

    Who your students are

    An account and an enrolment row: which student, which published version of which course, which intake, when they enrolled, and whether the enrolment has finished or expired.
  3. 3

    What a student did

    Per lesson: a status, cumulative seconds spent, when it was last opened and when it was completed. The seconds are written as increments rather than recomputed, which means the number is a sum of study time and not a surveillance trail.
  4. 4

    What a student answered

    One row per attempt at a question: what was chosen, whether it was right, which attempt number it was, how long it took, and when. Attempts are numbered so that a first attempt stays distinguishable from a third.
  5. 5

    What your staff did

    An audit row for the actions that change who can do what or what a student sees: who did it, which action, to which thing, and the request it belonged to. The free-form part of that row never carries a credential or a raw email address.
  6. 6

    Nothing else

    There is no phone number, no postal address, no date of birth, no photograph, no free-text profile and no payment detail anywhere in the schema. Not held rarely, not held optionally. There is no column for any of them.

Where it sits

The United States, and there is no European option yet

This is the sentence an EU buyer wants before anything else, so it is not buried at the bottom under a heading called International transfers.

The whole stack is pinned to one Google Cloud region, us-central1, in the United States. That is not a default nobody looked at: the infrastructure code contains a validation rule that refuses every other value at plan time, and the message it prints when it refuses says that European residency is served later by a separate project reusing the same module, rather than by making one project span two continents.

So if data residency inside the EU is a condition of the sale, today the honest answer is that we cannot meet it, and you should know that now rather than after a proposal. The work to meet it is a second project and a second set of buckets, and the design was built to allow that; it has not been done, and we are not going to describe it as though it had.

Where the data would physically sit
Regionus-central1, United States
European regionNot available. A second project, not yet built
Multi-regionNo. One region for every component, deliberately
DatabaseCloud SQL for PostgreSQL 17, reachable only over an encrypted connection
Network exposure of the databaseNone. No permitted-network list exists, and none may be added
Your book and your questionsOne storage bucket per environment, versioned, public access blocked outright
Encryption at restGoogle-managed keys. No customer-managed key is configured
Backups7 retained in the lower environments, 30 in production
Point-in-time recoveryProduction only, with 7 days of transaction log
Running in production todayNothing. Zero services, zero databases, one bucket

Sub-processors

Every company that would touch it

Named rather than described. A vendor asking a regulated training provider to hand over their manual, and then declining to say who else holds it, is asking for something it has not earned.
Google Cloud
Runs the interface, the document worker, the database, both storage buckets, the job queue, the secrets and the logs. United States, us-central1. This is the one that matters; everything else on this list is small beside it.
Firebase Authentication
Also Google, inside the same project. Holds the sign-in credential for every account, staff and student alike, and sends the one email this product causes to exist, which is a password reset link.
Vercel
Serves the web application, including this page. It holds no database credential and no administrative credential: everything it needs it asks our own service for. The region has not been chosen yet — the plan is the one nearest us-central1, measured rather than assumed.
Sentry
Error reports, and only when a reporting address is configured. None is configured in any environment today, and with none the reporter is inert rather than quiet. When it is switched on, every payload passes through a scrubber that removes credentials both by field name and by shape, with no way for a caller to opt out of it.
Document AI and Vertex AI
Switched off in development, staging and production alike, by one flag that also withholds the permissions. Nothing in the product calls a language model on any code path. If that ever changes, this list is the first place it changes, and before rather than after.

That is the whole list. There is no marketing platform, no email service, no support desk, no chat widget and no content delivery network beyond the one that comes with serving the web application. Each of those is a company that would be on this list if it existed, which is most of the reason none of them does.

Two names sit in an awkward middle and belong here rather than in a footnote. The code has typed integration points for Sentry, for error reports, and for PostHog, for product analytics — interfaces with no-op implementations, no SDK installed in any bundle, and no key configured. Nothing is sent to either company today and nothing can be until somebody sets a key, at which point they become sub-processors and this page has to say so. We would rather name them now than have you find them in a dependency list later.

Measures

What actually stops one provider reading another

Six mechanisms rather than six adjectives. Each is a property of the code, which means each is a thing that can be demonstrated instead of asserted.
  1. 1

    The database refuses an unscoped query

    Every tenant-owned table carries the organisation it belongs to, and the policy on it compares that against a value set for the duration of one transaction. When the value is not set the comparison is neither true nor false, so the statement returns nothing. Unset means see nothing, never see everything.
  2. 2

    The service cannot switch its own policies off

    Two database roles. One owns the tables and runs migrations; the other runs the service and is created without the privileges that would let it bypass a policy. The running system never holds the credential that could turn the mechanism off.
  3. 3

    There are no key files

    The infrastructure resource that creates a downloadable service account key is banned in this repository and appears in it only in comments saying so. Every identity is a short-lived token issued at the moment it is used. A key file is a credential that can be copied; there are none to copy.
  4. 4

    Buckets are closed rather than configured closed

    Public access prevention is enforced, permissions are set at the bucket rather than per object, versioning is on, and a deleted object is recoverable for a window. A misconfigured object cannot be made public, because the setting that would allow it is refused at the bucket.
  5. 5

    Suspension takes effect immediately

    Every credential issued to a person at or before the moment they are suspended is refused from that moment. Not when their session happens to expire. This is the thing everyone assumes already works, and usually does not.
  6. 6

    Logs are redacted before they are written

    Authorisation headers, cookies and tokens never reach a log line, and raw email addresses are deliberately kept out of a store with a long retention period and broad read access. The error reporter applies the same rules again, by field name and by value shape, because an exception carries things a log statement never chose to include.

Four things a signed agreement contains that this page does not, and each is unwritten rather than omitted: how much notice you get before this list of sub-processors changes; a breach notification timetable in hours; a right of audit and what it would let you inspect; and the standard contractual clauses that a transfer to the United States needs. All four need the registered entity and a lawyer. Ask about any of them and you will get the same answer as this page gives, which is what is true today.

The measures above, at more length, together with where your own material sits and what is only a commitment so far. Security and data

Send one chapter.

Not a demo of somebody else’s course. A chapter of yours, converted properly, so you can look at your own questions and your own page numbers and decide whether it is any good. Pick the chapter you know best. If it is no good, you have lost an email.

We will ask who owns the copyright before we convert anything. If you do not hold the rights to the material, we will say so rather than take the work.