feat(account): cascade account delete to connected apps (BUNYIP-211) #231
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/bunyip-211-cascade-account-delete"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Deleting a bunyip account now fans an
account_deletedwebhook out to every active application with awebhook_url(mokosh and any other connected PSA app), so a "deleted" bunyip account no longer leaves a fully-populated downstream tenant behind.Bunyip side of BUNYIP-211:
BunyipEvent::AccountDeleted { user_id }to the in-process bus:name()returnsaccount_deleted,target_user()returns the user. Published after the soft delete commits so local subscribers (audit tail, SSE) see the terminal event.WebhookService::notify_account_deleted(fire-and-forget) plusdispatch_account_deleted, which retries the signed delivery 3 times with exponential backoff and returns the outcome. Sign-once over a fixed payload keeps the body andX-Webhook-SignatureHMAC identical across retries.delete_accountfans the webhook out (in a spawned task so a slow/unreachable downstream cannot block the already-committed delete), records a per-app audit row for every dispatch outcome, and persists a replayable row in the newaccount_delete_dispatch_failurestable when an app exhausts its retries.POST /v1/admin/account-deletes/{user_id}/replayto re-fire a single app's webhook for a stuck delete, recording the outcome the same way the fan-out does.Tested: wiremock integration tests assert the receiver sees
account_deletedwith the correctuser_idand a valid HMAC, that the dispatch retries to exhaustion and reports the error, and that a no-webhook app is a no-op success. fmt + clippy (-D warnings) + workspace lib tests green.The mokosh-server receiver (
POST /v1/webhooks/bunyip/account-deleted, sections 5-7 of the issue) is companion work in a separate repo and remains to be filed as a MAPPS ticket.#BUNYIP-211
Deleting a bunyip account now fans an `account_deleted` webhook out to every active application with a `webhook_url` (mokosh and any other connected PSA app), so a "deleted" bunyip account no longer leaves a fully-populated downstream tenant behind. Bunyip side of BUNYIP-211: - Add `BunyipEvent::AccountDeleted { user_id }` to the in-process bus: `name()` returns `account_deleted`, `target_user()` returns the user. Published after the soft delete commits so local subscribers (audit tail, SSE) see the terminal event. - Add `WebhookService::notify_account_deleted` (fire-and-forget) plus `dispatch_account_deleted`, which retries the signed delivery 3 times with exponential backoff and returns the outcome. Sign-once over a fixed payload keeps the body and `X-Webhook-Signature` HMAC identical across retries. - `delete_account` fans the webhook out (in a spawned task so a slow/unreachable downstream cannot block the already-committed delete), records a per-app audit row for every dispatch outcome, and persists a replayable row in the new `account_delete_dispatch_failures` table when an app exhausts its retries. - Add admin-gated `POST /v1/admin/account-deletes/{user_id}/replay` to re-fire a single app's webhook for a stuck delete, recording the outcome the same way the fan-out does. - bunyip-web delete confirmation copy now warns that connected-app data is purged; the existing two-step (password + TOTP) confirm is preserved. Tested: wiremock integration tests assert the receiver sees `account_deleted` with the correct `user_id` and a valid HMAC, that the dispatch retries to exhaustion and reports the error, and that a no-webhook app is a no-op success. fmt + clippy (-D warnings) + workspace lib tests green. The mokosh-server receiver (`POST /v1/webhooks/bunyip/account-deleted`, sections 5-7 of the issue) is companion work in a separate repo and remains to be filed as a MAPPS ticket. #BUNYIP-211