Skip to content

Add script to purge private applicant answers for a concluded round - #43

Merged
efstajas merged 3 commits into
mainfrom
purge-private-answers-script
Jul 9, 2026
Merged

Add script to purge private applicant answers for a concluded round#43
efstajas merged 3 commits into
mainfrom
purge-private-answers-script

Conversation

@efstajas

@efstajas efstajas commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

What

Adds scripts/purge-private-answers.ts and an applications:purge-private-answers deno task to forget private applicant data once a round has concluded.

Private answers live in application_answers.answer (jsonb) — an answer is "private" only because its field's application_form_fields.private flag is true (there's no dedicated table or encryption; the app just filters these out at read time). This script nulls out those values in place, scoped to a single round: it forgets the content while leaving the row structure and referential integrity intact.

Usage

# 1. List rounds with their remaining private-answer counts
deno task applications:purge-private-answers

# 2. Dry run a specific round (no writes — prints a per-field breakdown)
deno task applications:purge-private-answers --round=<uuid>

# 3. Execute
deno task applications:purge-private-answers --round=<uuid> --confirm

DB_CONNECTION_STRING is read from the env file, same as the other scripts.

Safety

  • Scoped to one round via --round=<uuid>, through versions → applications.round_id, so it can't touch another round.
  • Dry-run by default; writes only with --confirm, inside a transaction.
  • Idempotent — only targets rows where answer IS NOT NULL.
  • Cache invalidation — busts the round + affected application caches afterward, since admin/submitter reads cache the raw answers.

Rendering safety (verified)

The script writes genuine SQL NULL. mapDbAnswersToDto surfaces that as { <value>: null } (e.g. { type: 'text', text: null }), keeping the answer object and its type intact. The frontend answer schemas are all .nullable() and the render component branches on === null for every field type, showing "No answer provided" — including in the admin review flow where private answers are visible. No page-level parse failures, no crashes.

Scope note

Per the intended use, this only touches private=true answers. It deliberately does not redact email-type answers that aren't flagged private, nor KYC PII (kyc_requests) — those can be added as a follow-up if wanted.

🤖 Generated with Claude Code

Adds scripts/purge-private-answers.ts (and an applications:purge-private-answers
deno task) to forget private applicant data after a round concludes.

Private answers live in application_answers.answer (jsonb); an answer is private
when its field's application_form_fields.private flag is true. The script nulls
out those values in place, scoped to a single round, forgetting the content
while leaving row structure and referential integrity intact.

Safety:
- Scoped to one round via --round=<uuid>.
- Dry-run by default; writes only with --confirm, inside a transaction.
- With no --round, lists rounds with their remaining private-answer counts.
- Idempotent (only targets answer IS NOT NULL).
- Invalidates cached admin/submitter reads after the purge.

Writes genuine SQL NULL, which mapDbAnswersToDto surfaces as { <value>: null };
the frontend renders this as "No answer provided" for every field type,
including in the admin review flow.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds an operational script and Deno task to permanently purge (“NULL out”) private application answers for a specific round, while keeping answer rows intact and invalidating relevant application caches afterward.

Changes:

  • Added scripts/purge-private-answers.ts to list candidate rounds, dry-run purge targets, and (with --confirm) update application_answers.answer to SQL NULL for application_form_fields.private = true scoped to one round.
  • Added applications:purge-private-answers task entry to deno.json.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
scripts/purge-private-answers.ts Implements round-scoped listing, dry-run reporting, transactional purge update, and cache invalidation.
deno.json Adds a Deno task to run the new purge script.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread scripts/purge-private-answers.ts
Comment thread scripts/purge-private-answers.ts
Comment thread scripts/purge-private-answers.ts
efstajas and others added 2 commits July 9, 2026 11:31
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@efstajas
efstajas merged commit ed6f0f2 into main Jul 9, 2026
8 checks passed
@efstajas
efstajas deleted the purge-private-answers-script branch July 9, 2026 09:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants