← Radlic

Data Retention and Deletion Policy

Beta version. In effect from 25 September 2026. We will email parents before we make any material change to it.

1. Principle

We keep children's personal information only for as long as it is reasonably necessary to provide the service for which it was collected. We do not keep it indefinitely and we do not retain it for any secondary purpose.

2. Retention schedule

DataWhere it livesRetained forEnforced?
Product events — session starts and similarlearner_events90 days, rollingYes. Nightly job purge-old-learner-events, 03:17. Watched deleting real rows
Old diagnostic answersdiagnostic item tables90 daysYes. Job prune-diagnostic-items, 03:22. Has not yet had a row old enough to delete
Crash recordserror_events90 daysYes. Job prune-error-events, 03:27. Not yet exercised on a real row
Adult email addresses captured before sign-updiagnostic_leads24 monthsYes. Job prune-diagnostic-leads, 03:32. First deletion falls due in 2028
Child profile — first name, avatar, age band, gradelearners, learner_accessUntil the account or the profile is deletedNo scheduled job. Deletion is by parent request only
Lesson progress, points, statistics, feedbacklesson_progress, point_events, learner_stats, lesson_feedback, game_settingsUntil the account or the profile is deletedNo scheduled job
Parent accountauth.users, profiles, parent_pinsUntil the account is deletedNo scheduled job
Account whose email address was never confirmed, with no childauth.users (from migration 20260923180000, a profile is created only once the address is confirmed)3 days from sign-upYes, once migrations 20260923180000 and 20260923180100 are applied to production. Nightly job prune-unconfirmed-users, 03:37, plus a one-time sweep when applied. Tested on a local copy of the schema; not yet exercised on production
Sign-in eventsauth_eventsCurrently kept indefinitelyNo scheduled job
Cancellations of the second consent email — the email provider's id for that message, the id of the consent it belonged to, when it was due, and whether cancelling it worked. No name, no address, nothing about the childconsent_b3_cancellationsCurrently kept indefinitely — including after the consent record and the account are deleted, because it is filled at the moment they are deleted so the email can still be cancelledNo scheduled job
Live sessions, including IP address and browserauth.sessionsUntil the session expiresProvider-managed
Provider request logs — IP address, browser, IP-derived city/region/country, account idOur database provider's own platform logsUnknown. The project is 20 days old and nothing has aged out, so "kept indefinitely" cannot yet be distinguished from "kept at least 20 days"Outside our jobs entirely
Hosting request and console logsHosting providerAvailable to us for 1 hour on our plan (Hobby), from the provider's dashboard, 24 September 2026Provider-managed
BackupsEncrypted build artifact, 30-day expiry by design30 daysWorking — restore proven 23 Sep 2026. See Section 6
Support correspondence with parentsEmail12 monthsNot automated

Consent records — parental_consents, built 23 September 2026. Holds the adult, the child, the method, the timestamps, the version of each document shown, and the state. It is linked to the adult account and cascades on account deletion, so closing an account erases the only evidence that consent was ever given or withdrawn.

That is a genuine tension, not an oversight: it is what "we delete everything we hold about you" requires, and it is the opposite of what record-keeping for children's consent usually wants. Resolving it needs an anonymised consent log that survives deletion, plus a sentence in the Privacy Policy describing it — neither exists. Decided by the founder for the beta on 24 September 2026, for attorney review: the cascade stands until an anonymised consent log is built, and the Privacy Policy and Terms say so.

3. Deletion on request

A parent may ask us to delete their child's information at any time, and may withdraw consent at any time. Either request triggers deletion under the Parent Rights procedure, ahead of the schedule above. Target: complete within 10 days of verifying the requester.

Known defect — deletion is not yet complete. Crash records carry a child's internal identifier with no database link back to the child, so they do not disappear when the child is deleted. Three such records already point at children who no longer exist, each holding the page they were on and their browser type. Until that link is added, "we delete your child's data" is not fully true, and a parent asking for deletion would have it honoured everywhere except here. This must be fixed before the Parent Rights page is published.

Resolved, 23 September 2026 (measured on production). Crash records now carry a database link to the child that deletes them with the child (error_events.learner_idlearners, on delete cascade — read from the production catalog). The three orphaned records were deleted when that link was added (crash records 9 → 6), and after the test children were cleared no crash record points at a child who no longer exists (0 orphaned). Deleting a child from the app was proven on real rows the same day: every one of that child's rows, and the child's own login, was gone afterwards, and another child on the same account was untouched. That child happened to have no crash records, so the crash-record cascade is proven by the catalog and by the clearing of the test children, not by that one deletion.

4. When we keep something longer

We keep information past its scheduled deletion only where we must: to comply with a legal obligation including tax and accounting record-keeping; to establish, exercise or defend a legal claim; to resolve a dispute or enforce our agreements; or to maintain security, where a limited log is necessary. Where we do, we keep the narrowest record necessary and delete it as soon as the reason ends. Every such hold is recorded with its reason and expected end date.

5. Backups and the provider's own logs

Two things sit outside our deletion jobs, and both must be described honestly to parents rather than glossed:

Backups. Deleting a record from the live database does not remove it from a backup. Backups are designed to expire after 30 days, so a deleted record can survive in a backup for up to that long. We never restore a deleted child's record from a backup. A backup holds everything in the database, including parents' sign-in session tokens, so it is encrypted and the passphrase is held only in the password manager and the code host's secret store.

The database provider's platform logs. These record the IP address, browser type and an IP-derived approximate location for every request, including requests made by children's devices. They are the provider's own logs, not our tables, and none of our deletion jobs reach them. On our plan the provider makes these logs available to us for 7 days (from its dashboard, 24 September 2026).

6. How this is enforced

ControlMechanismEvidence it works
Deletion of expired product eventspurge-old-learner-events, nightly 03:17Proven — a run reported deleting real rows. 19 runs since 4 September, no failures
Deletion of expired diagnostic answers, crash rows, lead emailsThree further nightly jobsActive, no failures, but none has yet had a row old enough to delete — so each is scheduled rather than proven
Deletion on parent requestParent Rights procedureThe parent-request log in Radlor Ops
BackupsNightly encrypted artifactRestore proven, 23 September 2026. The job had failed 13 nights running (10–22 Sep, missing secrets). Secrets fixed; run #39 (manual, dump 06:48:17–06:48:50 UTC) produced an 87,248-byte encrypted artifact. It was decrypted, restored into a throwaway local database, and all 32 public tables matched production exactly, table by table (968 rows in total) — checked against production, and separately against the row counts recorded in the dump itself. The decrypted copy was destroyed afterwards. Still to watch: the first scheduled nightly run succeeding on its own. Restoring needs auth and storage service versions matching production and the supabase_admin role; the restore note in backup.yml says so, including how to check production's versions first
Annual review of this policyOwner named aboveRecorded in Radlor Ops, alongside the parent-request log

Verification requirement. Before any deletion job is trusted it must be watched deleting a seeded test record, and watched not deleting a record still in date. A job reporting "0 rows deleted" means nothing until it has first been seen deleting something.

Questions about your child's data? Email support@radlor.com. You can download or delete everything from the parent dashboard.