Skip to content

Explore hiding signals instead of hard-deleting them (traceability) #68

Description

@BurningAXE

Problem

Deleting a signal today is a hard delete, performed by the client: _confirmDeleteSignal in lib/src/widgets/signal_details_screen.dart best-effort deletes the Storage photos, batch-deletes the comments subcollection, then deletes the signal document. Nothing survives.

That is at odds with where the case system is heading (Master Specification §4.5 case ownership history, §4.6 case timeline, §18.7 audit and oversight), and it causes concrete problems now:

  • The signal history is destroyed with the signal. The new events subcollection (signal timeline: status/urgency changes with mandatory update notes) is deleted along with everything else, so there is no record that a signal ever existed, or of who changed what.
  • The reporter can delete individual history entries. Firestore rules allow a comment/event delete by the parent signal's reporter — required for the delete cascade to work at all from the client. An audit trail its own subject can prune is not an audit trail.
  • The cascade is client-side and best-effort. If the app is killed mid-delete, subcollection documents are orphaned (Firestore keeps subcollection docs when the parent document is deleted) and nothing ever cleans them up.
  • Moderation has nowhere to go. §18.3 wants "hide post" as a moderator action distinct from deletion, and §4.10 wants expiry/archiving with reduced-quality media rather than erasure.

Idea to explore

Replace hard delete with hiding / soft delete:

  • A hidden (or deletedAt + hiddenBy) field on the signal, with rules excluding hidden signals from client queries, so the document and its history survive.
  • Move the actual destructive path server-side into a deleteSignal callable using an Admin SDK recursive delete, mirroring the existing deleteAccount callable. With deletion no longer client-driven, events can become allow delete: if false and the tamper hole closes.
  • Decide the retention story alongside §4.10 (archive after ~6 months, media deleted after 6–12 months) and the GDPR erasure path — soft delete must not become a way to retain personal data indefinitely.

Questions to settle

  • Who may hide: reporter only, or reporter + moderator/admin once those roles exist?
  • Is a hidden signal still reachable by direct link / share link, or 404?
  • Do profile statistics keep counting a hidden case? (§3.5.1 says stats survive case deletion.)
  • What actually gets purged, and when — photos first, document later?
  • Does the reporter still get a way to truly erase their own content, for GDPR?

Context

Came out of the signal-timeline work (Master Spec §4.6, "Case Timeline"), which introduces the signals/{id}/events subcollection. That change deliberately keeps allow delete: if isParentSignalReporter(...) on events so the existing cascade keeps working, and records the tamper hole as a known gap rather than fixing it — this issue is that fix.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions