When members are bulk-deleted we previously left their entries in the mailListAudit collection behind. That meant unsubscribe/audit history kept showing the bare Mongo ObjectId in the Brevo Unsubscribes view (no name, no email — just the deleted member's ID), and more importantly it left identifiable records hanging around past the point where the member record itself was gone. Not appropriate for a Ramblers endorsed project.
Cascade — MemberBulkDeleteService now calls a new server endpoint (POST /api/database/mail-list-audit/delete-by-members) immediately after deleting members. Audit rows for those member IDs are removed in a single deleteMany. Errors here log but don't fail the whole bulk-delete operation, so the member deletion is never left half done.
Orphan sweep — same flow then calls POST /api/database/mail-list-audit/delete-orphans which removes any audit row whose memberId no longer matches an existing member. Backstop for any data that drifts in via other delete pathways or direct database edits.
One-off migration — 20260427100000-purge-orphan-mail-list-audit.ts does the same orphan sweep once on next deploy so historical pre-cascade orphans are cleaned up before the new cascade goes live. Idempotent — safe to re-run.
MongoDB doesn't enforce foreign keys, so this is application-level cascade rather than DB-level. The migration is the necessary cleanup of pre-existing orphans before activating the new behaviour.