Repository navigation
[TAS-6727] 🐛 Replace CMS tag book list in bulk tag update - #1534
Conversation
There was a problem hiding this comment.
🔵 Needs a closer look
It performs irreversible bulk deletion of CMS tag associations on production book documents based on externally-supplied automation input, which warrants human verification despite having no concrete defects.
No open issues 🎉
What changed in this PR
This PR fixes a bug (TAS-6727) in the bulk CMS tag update endpoint (POST /bulk/cms/tags). Previously the endpoint could only add/update/remove individual tag entries explicitly listed in the request. It now accepts a replaceTagIds array that treats the submitted entries as the complete book list for those tags: any book currently holding one of those tags but absent from entries is pruned, so stale/unlinked books no longer linger. This supports the Airtable-driven CMS automation that syncs a tag's full handpicked book list in one request.
Changes:
- Added
replaceTagIds(defaulting to[]) toBookCMSTagBulkBodySchema. - Added
listStaleCMSTagEntriesand extendedbulkSetNFTBookCMSTagOrderto merge requested entries with server-computed stale deletions for replace tags. - Removed the route's early empty-entries short-circuit so an empty
entrieswithreplaceTagIdsstill prunes, and added test coverage for the new behavior.
| File | Description |
|---|---|
src/util/api/likernft/book/schemas.ts |
Adds replaceTagIds array field (defaults to [], keeping the request backward compatible). |
src/util/api/likernft/book/cms.ts |
New listStaleCMSTagEntries queries books per replace tag and emits order: null deletes for books not in entries; bulkSetNFTBookCMSTagOrder merges them. |
src/routes/likernft/book/store.ts |
Destructures replaceTagIds, passes it through, and drops the empty-entries early return so prune-only requests work. |
test/api/likernft-book-cms-tags.test.ts |
Adds tests for pruning books missing from entries and clearing a replaced tag when entries is empty. |
The implementation is correct: the tagId/classId listed set is gated on order !== null, replaceTagIds is de-duplicated, requested entries precede stale deletes so a live order is never overwritten, and unrelated tags on a book are preserved via nested field-path updates. Tests and the Firestore stub (.where(...).select(), dot-path updates) back this up, and I found no concrete defects to comment on. One behavioral note for human reviewers: stale deletes are counted against BULK_LIMIT (500), so an all-or-nothing BULK_LIMIT_EXCEEDED is thrown for a tag that currently holds more books than the limit, and the per-tag existence query is unbounded.
Review effort: Balanced
No description provided.