feat(seed): seed-data tagging & wipe infrastructure (Pages reference) - #42
Merged
Conversation
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
…ages Pages is configured with trash: true, but Payload's local API find/delete default trash: false, which excludes/skips soft-deleted documents. This meant: - seedPages's idempotency find couldn't see a trashed seeded page, so re-running Seed would try to create a page with the same slug and collide with the still-present (trashed) row's unique constraint. - cleanPages's find for seeded-dummy-flagged pages skipped trashed pages, never collecting their hero media ids, permanently orphaning that media. - cleanPages's delete call for pages needed trash: true to permanently delete rather than no-op on an already-trashed page. MediaImages calls are left unchanged; that collection has no trash config. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
SeedActions.tsx opens its SSE subscription only after enqueueSeedCollection resolves and triggers a re-render. The job itself is triggered via after(() => payload.jobs.runByID(...)) and can start running immediately, so a fast cleanPages run (few/zero pages) can publish its terminal success/error message before the client has subscribed. Redis pub/sub has no replay, so that message is lost: the toast stays stuck on "Queued…" forever and router.refresh() never fires. Add a client-side fallback: after enqueueing, arm a 5s timeout that, if no terminal SSE message clears jobId first, performs the same cleanup a success message would (toast, clear jobId, router.refresh()). The timeout is cleared whenever a real terminal message arrives, so it never fires in the normal case. Also add the SeedActions modal stylesheet: SeedActions.tsx rendered seed-actions-modal / __body / __footer classes with no stylesheet defining them anywhere in the repo. Added SeedActions.styles.css following the co-located .styles.css convention (see MediaScopeTabs.styles.css) and the Payload theme custom properties already used under AdminPanel. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GjuWYPbCQ16C3Fkc1k8grT
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.
Summary
Adds a general-purpose seed-data tagging mechanism, plus a fully-built reference implementation for the
Pagescollection: create/wipe fixture data from the CLI or the admin panel, tagged so it can coexist with real content and be found/removed independently.GeneratorFlagsFieldwith aseeded-dummyflag, rolled out to 12 collections (all exceptUsers; Media collections already had the field).seedPages/cleanPageslogic (src/lib/seed/pages.ts) — the single source of truth for both callers below.cleanPagescascade-deletes the seeded media a page's hero referenced, gated by a live per-document flag re-check so a page that got its hero manually pointed at a real image never has that image deleted.pnpm seed:pages [-- --count N]/pnpm seed:pages:clean, synchronous, calls the shared logic directly.TranslateControls.tsx/bilingualTranslateChannelpattern).Design doc and implementation plan are local-only (
docs/is gitignored in this repo) — happy to share the content directly if useful for review.Scope
This PR builds infrastructure + the Pages reference implementation only. The other 11 seedable collections (BlogTopics, 6 Resume collections) are explicit non-goals here, to follow later using Pages as the template.
Process notes
Built via subagent-driven development: fresh implementer + reviewer per task, human-escalated one design decision (a spec-mandated safety check in
cleanPagesthat a plan-authoring bug had accidentally undermined — restored per your call), then a final whole-branch review (opus) that caught three cross-cutting issues no single task's review could see:cleanPages/seedPagesdidn't account forPages'trash: true— a soft-deleted seeded page was invisible to Clean, permanently orphaning its media, and broke re-Seed's idempotency check. Fixed.cleanPagesrun could complete before the client's SSE subscription opened, leaving a stuck toast and a stale list view. Fixed with a client-side timeout fallback.All three fixes independently re-reviewed and confirmed resolved. 6 Minor findings were logged but intentionally left unfixed (no auth check on the destructive server action — confirmed pre-existing pattern across every server action in this repo, not a regression; a few small robustness/consistency nits) — noted below as candidates for follow-up.
Verification
pnpm typecheck— 0 errorspnpm vitest run— 617/617 passing (+12 new tests)pnpm build— succeedsFollow-ups (not blocking, not in this PR)
enqueueSeedCollection(matches every other server action insrc/lib/actions/today — a repo-wide gap, not new here, but worth a dedicated pass since this one action is destructive)seedCollection.tsdispatches on a bare'pages'string rather than theCollectionSlugenum — fine for one entry, worth a lookup map once a second collection lands--countdoesn't validate a non-numeric/out-of-range value (silently seeds 0)seedPagesfailure can orphan an already-created hero image (tagged, so still manually findable)🤖 Generated with Claude Code