Repository navigation
feat: delete MediaLit assets when their resource is deleted (#157) - #162
Merged
Merged
Conversation
) Template, sequence and sequence email deletes now delete the media rows they leave without references, and their MediaLit files. Media shown by sent mail is kept. Failed MediaLit deletes are queued for retry on a new media-deletion BullMQ queue and sent to captureError; team purges use the same path.
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.
Closes #157 (part of #152).
What
deleteOrphanedMedia(teamId, mediaIds)(apps/api/src/media/queries.ts).deleteMediaReferencesForResourcenow returns the media rows it released. Once the resource is deleted, each released row that has no references left and that no stored sent content (email_content_versions) shows is deleted, along with its MediaLit file.mediarow for it is left in any team.media-deletionBullMQ queue (src/media/deletion-queue.ts+ worker, same pattern as the contact deletion queue; shut down inindex.ts). The row is deleted first. A failed MediaLit delete goes tocaptureError(medialit_delete_failed) and is queued: first try after 1 minute, then exponential backoff over 10 attempts (~17h). The worker skips a file that is in use again.deleteTeamMediaFiles, used by org delete): it now deletes all rows and queues the files MediaLit fails to delete. Before, it kept the failed rows and never retried them.template_deleted,sequence_deletedandsequence_email_deletedcarrymedia_deleted_count(allowlisted).Decisions (ADR 0006)
Docs
OpenAPI descriptions for the three delete routes, MCP tool descriptions,
apps/api/docs/media-library.md, user docsworkspace/media.mdx, ADR 0006.Tests
Real PGlite DB with MediaLit
service.tsmocked: template delete (own media deleted; media shared with another template kept; transactional-sent template kept; another team's row for the same file is untouched), sequence email delete (shared kept), sequence delete across 3 emails (bulk), draft broadcast deleted vs sent broadcast kept, a draft email sharing an image with a sent email,deleteOrphanedMedia(references, sent-content check, other team's ids ignored), MediaLit failure → row gone, job queued andcaptureErrorcalled, then the retry deletes the file. Org delete: multi-team purge with other orgs untouched, plus the failure → queued case. Results: API 902+ pass / 0 fail, web and contract tests pass, lint, typecheck,check:driftandtest:conformanceall green.E2E (browser, real stack)
Isolated API + web (
next dev) + Postgres + Redis, with a local MediaLit stub that implements TUS upload, seal, delete and image serving. Its delete answers 503 while a flag file exists.DELETE lit…(A).DELETE seqone.DELETE seqtwoonly (the shared image was kept);DELETE draftbcast; the sent broadcast's image was kept. The "sent" state was set by inserting anemail_content_versionsrow (what a send writes). No real send happened.captureError(no PostHog key locally; unit tests check the call).