feat(gdpr): purge expired email-change requests and invite codes #275

Sammanfogat
supernaut sammanfogade 2 incheckningar från feat/256-gdpr-purge in i main 2026-10-02 09:52:52 +00:00
Ägare

What

Purge expired personal-data rows. Version 1.15.0.

  • scripts/purge-expired.mjs: deletes email_change_requests and invite_codes rows more than 7 days past expires_at or past consumed_at / used_at. Invite codes with neither timestamp are kept. Batched 500 rows per delete, looped until a short batch. Idempotent. Logs counts only.
  • scripts/server.mjs runs it on boot and hourly when DATABASE_URL is set. No infra timer needed.
  • signups is not purged: it is the per-account consent record with no expiry, covered by account-data retention.

Privacy policy (please read before merge)

New line in the Retention section, both languages:

  • EN: "Expired email-change links and invite codes: deleted 7 days after they expire or are used."
  • SV: "Utgångna länkar för byte av e-postadress och inbjudningskoder: raderas 7 dagar efter att de gått ut eller använts."

Verification

  • Real Postgres 17 with the repo migrations applied: email-change 5 rows → 2 deleted, invite codes 6 rows → 2 deleted, second run 0, 1203 rows across three batches all deleted.
  • Those DB tests (scripts/purge-expired.db.test.mjs) skip without TEST_DATABASE_URL; this repo's CI has no Postgres yet.
  • pnpm test 407 passed, 3 skipped. Lint, astro check, lang-check, build and e2e pass.

Closes #256

## What Purge expired personal-data rows. Version 1.15.0. - `scripts/purge-expired.mjs`: deletes `email_change_requests` and `invite_codes` rows more than 7 days past `expires_at` or past `consumed_at` / `used_at`. Invite codes with neither timestamp are kept. Batched 500 rows per delete, looped until a short batch. Idempotent. Logs counts only. - `scripts/server.mjs` runs it on boot and hourly when `DATABASE_URL` is set. No infra timer needed. - `signups` is not purged: it is the per-account consent record with no expiry, covered by account-data retention. ## Privacy policy (please read before merge) New line in the Retention section, both languages: - EN: "Expired email-change links and invite codes: deleted 7 days after they expire or are used." - SV: "Utgångna länkar för byte av e-postadress och inbjudningskoder: raderas 7 dagar efter att de gått ut eller använts." ## Verification - Real Postgres 17 with the repo migrations applied: email-change 5 rows → 2 deleted, invite codes 6 rows → 2 deleted, second run 0, 1203 rows across three batches all deleted. - Those DB tests (`scripts/purge-expired.db.test.mjs`) skip without `TEST_DATABASE_URL`; this repo's CI has no Postgres yet. - `pnpm test` 407 passed, 3 skipped. Lint, `astro check`, `lang-check`, build and e2e pass. Closes #256
supernaut lade till 2 incheckningar 2026-10-02 09:12:44 +00:00
Delete rows 7 days after they expire or are used, hourly, in the server process.
State the period in the privacy policy retention section.

Closes #256
test(gdpr): prove the purge SQL against real postgres
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m30s
fb9947faca
Gate the db test on TEST_DATABASE_URL. Reword the Swedish retention line.
supernaut tvångsskickade feat/256-gdpr-purge från fb9947faca
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m30s
till ff5c18c4de
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m24s
2026-10-02 09:50:53 +00:00
Jämför
supernaut schemalade den här ändringsförfrågan för automatisk sammanfogning när alla kontroller lyckas 2026-10-02 09:51:13 +00:00
supernaut sammanfogade incheckning f13ee5d721 till main 2026-10-02 09:52:52 +00:00
supernaut tog bort grenen feat/256-gdpr-purge 2026-10-02 09:52:53 +00:00
supernaut refererade denna ändringsförfrågan från en incheckning 2026-10-02 20:50:46 +00:00
Logga in för att delta i denna konversation.
Inga granskare
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-web!275
Ingen beskrivning angiven.