fix(api): delete message_reactions before purging a channel account - #385
Open
detail-app[bot] wants to merge 1 commit into
Open
Conversation
setkyar
force-pushed
the
detail/bug-fix/fix-api-delete-message-reactions-before-purging-a-248d53
branch
from
September 12, 2026 14:04
160173d to
7f69b37
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Detail bug report: View on Detail
Closes #380
Problem
purgeArchivedChannelAccountpermanently deletes an archived channel-neutral account (e.g. Telegram) and all of its conversations, messages, routing rows, and bridged contacts inside one PostgreSQL transaction. The channel-spine schema addsmessage_reactions.channel_account_id → channel_accounts(id) ON DELETE RESTRICT, but the purge never deletedmessage_reactionsrows. Deleting the messages did not help — the basemessage_reactionstable has no FK onmessage_id, so reactions are not cascade-removed.As a result,
DELETE FROM channel_accountstripped themessage_reactions_account_fkRESTRICT and the entire transaction rolled back. Any archived account that had received or sent at least one reaction (written only when a workspace enables the neutral spine,write_authority = 'neutral'+ provider on) could never be purged — the failure was deterministic and the blocking rows never cleared.Fix
Delete the account's
message_reactionsrows inside the purge transaction, beforeDELETE FROM channel_accounts(apps/api/src/services/channel-account-purge.service.ts):The delete is scoped by
channel_account_id(notmessage_id) on purpose: it matches the RESTRICT FK column and also reaps any reactions whosemessagerow was already deleted elsewhere — a narrowermessage_id-in-(messageIds)scope (as the WhatsApp linked-device purge uses) would miss those orphans. This mirrors the existing precedent inwhatsapp/connection.ts, which already cleansmessage_reactionsexplicitly because of the absentmessage_idFK. No schema/migration change is needed; the constraint is correct, the application just had to satisfy it.Testing
channel-account-purge.integration.test.ts, run withRUN_DB_INTEGRATION=1against a migrated PostgreSQL):message_reactionsrow (channel_account_idset), then purged — the account, conversation, message, and reaction are all gone andconversation_casesis empty.message_idhas no matchingmessagesrow, then purged — the orphaned reaction is reaped, pinning thechannel_account_id-scope decision so a future narrowing tomessage_idscope can't silently reintroduce the RESTRICT failure.message_reactions_account_fkRESTRICT violation (code 23001,constraint "message_reactions_account_fk"), then passed again with the fix restored.app.request): verifiedPOST /api/channel-accounts/:id/purgereturns200with the purge payload for an archived account with a reaction,403for a member, and409for a non-archived account; and that a non-archived account rejects withChannelAccountNotArchivedErrorand leaves all seeded data intact, missing accounts reject withNotFoundError, and legacy WhatsApp-bridged accounts reject with the linked-device-flow error. Also confirmed reactions on other accounts and legacychannel_account_id IS NULLrows are preserved (not over-deleted).nats_outboxrelation; none referencemessage_reactions,channel_accounts, or the purge service.Operational / security impact
None. This is a data-deletion correctness fix: the purge now removes the reactions it was always supposed to remove. No new data is exposed, no credentials or external calls are involved, and no behavior changes for accounts without neutral-spine reactions.
Automatic Fixes PRs can be configured here.