{"id":"69ef53e81b14310e06382dba","title":"2026 04 27 Build 627","path":"how-to/committee/release-notes/2026-04-27-build-627","contentMarkdown":"# 27-Apr-2026 — cascade-delete mail list audit rows on bulk delete + GDPR orphan sweep [ref #18](https://github.com/nbarrett/ngx-ramblers/issues/18)\n\n## [build 627](https://github.com/nbarrett/ngx-ramblers/actions/runs/24994004980) — [commit 3d9039e](https://github.com/nbarrett/ngx-ramblers/commit/3d9039efac9745461c5f923f9ca925ed52106aa1)\n\n_____\n\nWhen members are bulk-deleted we previously left their entries in the\nmailListAudit collection behind. That meant unsubscribe/audit history\nkept showing the bare Mongo ObjectId in the Brevo Unsubscribes view\n(no name, no email — just the deleted member's ID), and more\nimportantly it left identifiable records hanging around past the point\nwhere the member record itself was gone. Not appropriate for a Ramblers\nendorsed project.\n\n### Three pieces:\n\n1. **Cascade** — MemberBulkDeleteService now calls a new server endpoint\n(POST /api/database/mail-list-audit/delete-by-members) immediately\nafter deleting members. Audit rows for those member IDs are removed\nin a single deleteMany. Errors here log but don't fail the whole\nbulk-delete operation, so the member deletion is never left half\ndone.\n\n2. **Orphan sweep** — same flow then calls\nPOST /api/database/mail-list-audit/delete-orphans which removes any\naudit row whose memberId no longer matches an existing member.\nBackstop for any data that drifts in via other delete pathways or\ndirect database edits.\n\n3. **One-off migration** — 20260427100000-purge-orphan-mail-list-audit.ts\ndoes the same orphan sweep once on next deploy so historical\npre-cascade orphans are cleaned up before the new cascade goes\nlive. Idempotent — safe to re-run.\n\nMongoDB doesn't enforce foreign keys, so this is application-level\ncascade rather than DB-level. The migration is the necessary cleanup\nof pre-existing orphans before activating the new behaviour.","contentHtml":"<h1>27-Apr-2026 — cascade-delete mail list audit rows on bulk delete + GDPR orphan sweep <a href=\"https://github.com/nbarrett/ngx-ramblers/issues/18\">ref #18</a></h1>\n<h2><a href=\"https://github.com/nbarrett/ngx-ramblers/actions/runs/24994004980\">build 627</a> — <a href=\"https://github.com/nbarrett/ngx-ramblers/commit/3d9039efac9745461c5f923f9ca925ed52106aa1\">commit 3d9039e</a></h2>\n<hr>\n<p>When members are bulk-deleted we previously left their entries in the\nmailListAudit collection behind. That meant unsubscribe/audit history\nkept showing the bare Mongo ObjectId in the Brevo Unsubscribes view\n(no name, no email — just the deleted member&#39;s ID), and more\nimportantly it left identifiable records hanging around past the point\nwhere the member record itself was gone. Not appropriate for a Ramblers\nendorsed project.</p>\n<h3>Three pieces:</h3>\n<ol>\n<li><p><strong>Cascade</strong> — MemberBulkDeleteService now calls a new server endpoint\n(POST /api/database/mail-list-audit/delete-by-members) immediately\nafter deleting members. Audit rows for those member IDs are removed\nin a single deleteMany. Errors here log but don&#39;t fail the whole\nbulk-delete operation, so the member deletion is never left half\ndone.</p>\n</li>\n<li><p><strong>Orphan sweep</strong> — same flow then calls\nPOST /api/database/mail-list-audit/delete-orphans which removes any\naudit row whose memberId no longer matches an existing member.\nBackstop for any data that drifts in via other delete pathways or\ndirect database edits.</p>\n</li>\n<li><p><strong>One-off migration</strong> — 20260427100000-purge-orphan-mail-list-audit.ts\ndoes the same orphan sweep once on next deploy so historical\npre-cascade orphans are cleaned up before the new cascade goes\nlive. Idempotent — safe to re-run.</p>\n</li>\n</ol>\n<p>MongoDB doesn&#39;t enforce foreign keys, so this is application-level\ncascade rather than DB-level. The migration is the necessary cleanup\nof pre-existing orphans before activating the new behaviour.</p>\n"}