Skip to content

feat: delete sequences, blocked while active, with an explicit stats warning (#148) - #164

Merged
clbotdev merged 5 commits into
mainfrom
feat/148-sequence-delete
Oct 29, 2026
Merged

clbotdev merged 5 commits into
mainfrom
feat/148-sequence-delete

Conversation

@clbotdev

Copy link
Copy Markdown
Contributor

Closes #148

What

  • API: DELETE /sequences/:id refuses an active sequence (or sending broadcast) with 409 sequence_active. The status check is repeated in the delete statement, so a sequence started in between is kept. New GET /sequences/:id/deletion-preview returns { status, blocker, enrolledCount, emailsSentCount }. Blocker codes live in src/sequences/delete-blockers.ts, shared by REST, MCP and the dashboard, ready for Delete broadcasts (with archive for sent ones) #147's broadcast blockers.
  • Semantics (ADR 0007): a paused, draft or completed sequence is hard deleted after an explicit warning. Its enrollments, triggers, and delivery/open/click history go with it. This matches Mailchimp Journeys, ActiveCampaign and Klaviyo, where an automation must be paused or turned off and deleting it removes its reporting. Archive is reserved for sent broadcasts (Delete broadcasts (with archive for sent ones) #147). Kept: outbound_messages (delivery link set null), suppressions, contacts, and plan usage (counted from outbound_messages/buckets).
  • Media (ADR 0006): whether an email was sent is now read before the cascade removes its deliveries. Images of sent emails are kept; images only unsent emails used are deleted in MediaLit.
  • MCP: delete_sequence (destructive) and preview_sequence_deletion (read); parity manifest, policy and tool count (111) updated.
  • Dashboard: a ⋯ row menu on the Sequences list and a Delete button on the sequence page. Both are disabled while the sequence is active, with the reason ("Delete (pause first)" / title). The confirmation (DeleteConfirmationDialog, Loading while the preview loads) states the enrolled-contact count and that the stats of N sent emails can't be recovered.
  • Observability: sequence_deleted gains sequence_status, enrolled_count, emails_sent_count; new sequence_delete_blocked (allowlisted).
  • Docs: sequences guide "Delete a sequence", sequence_active in errors, MCP tools.

Tests

  • API (pglite): active sequence and sending broadcast are refused and keep everything; paused delete removes enrollments, deliveries, events, rules and emails but keeps the contact; never-started draft; team isolation for delete and preview; a delivered email's image is kept (MediaLit deleteMedia mocked) even though its deliveries cascade; route 409/204/404/preview; MCP tools.
  • Web: dialog shows counts and deletes; refuses and explains for active.
  • bun run lint, typecheck, all suites (API with --env-file=/dev/null: 922 pass), check:drift, test:conformance all pass.

Browser e2e (real stack: fresh DB, SMTP ESP → Mailpit, MediaLit stub)

  1. Created "Onboarding 148" (2 emails, an image uploaded in the editor for each, tag trigger), started it, tagged 3 contacts. The poll sent email 1 to all 3 in Mailpit; 3 enrolled waiting for email 2.
  2. While active: the list menu shows a disabled "Delete (pause first)", the page Delete is disabled with its reason, and DELETE gives 409 sequence_active.
  3. Paused from the page. From the list menu the dialog read: "3 contacts are enrolled and will get no more of its emails… Stats for 3 sent emails (deliveries, opens and clicks) are deleted and can't be recovered." Confirmed: the row is gone. In the DB the sequence, enrollments, deliveries and rules are gone; 3 outbound_messages and the 3 contacts are kept. MediaLit: the unsent email's image got a DELETE call, the sent email's image did not, and its media row is kept.
  4. Never-started draft with an image, deleted from its page: the dialog said "No contacts are enrolled / hasn't sent any email". It redirected to /sequences, and its image got a MediaLit DELETE call.
    Screenshots inspected (list menu disabled, page button disabled, both dialogs, list after delete).

Notes for #147 / #134

  • Broadcasts already get the active guard here (sending = active). Delete broadcasts (with archive for sent ones) #147 adds broadcast_sent + archive in delete-blockers.ts / sequenceDeleteBlocker, and its own UI. The list row menu is only rendered for type === "sequence" for now.

…removes (#148)

DELETE /sequences/:id now answers 409 sequence_active for an active
sequence or sending broadcast (re-checked in the delete statement).
GET /sequences/:id/deletion-preview returns the enrolled-contact and
sent-email counts. Media of sent emails is classified before the
cascade removes the deliveries. MCP gains delete_sequence and
preview_sequence_deletion. ADR 0007 records hard delete with an
explicit stats warning for sequences; archive stays for broadcasts.
A row menu on the Sequences list and a Delete button on the sequence
page open a confirmation that loads the deletion preview: how many
contacts are enrolled and how many sent emails' stats go with it.
Active sequences can't be deleted; the menu item and button say to
pause first, and the dialog explains it.
@clbotdev
clbotdev merged commit f80e46f into main Oct 29, 2026
5 checks passed
@clbotdev
clbotdev deleted the feat/148-sequence-delete branch October 29, 2026 11:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Delete sequences

2 participants