11 — Published Content Manager (Screen 7, `/app/testimonials/published`)
Cursor-ready plan: admin surface for live testimonials—placement visibility, ordering, feature/pin, list/grid, unpublish.
11 — Published Content Manager (Screen 7)
Section titled “11 — Published Content Manager (Screen 7)”Source: 02-Implementation-Blueprint.md — Screen 7 - Published Content (/app/testimonials/published).
Product alignment: 01-Post-Purchase-Video-Testimonial-Collector-Plan.md — §6 (publish to storefront, control what buyers see).
This document is a build spec only. No code changes are implied until a task references this file.
Prerequisites: TestimonialSubmission with publish fields (published, publishedAt, featured, sortOrder per §5.7); public read API 05-storefront-widgets-and-read-api.md must filter by these flags when you add placement logic.
Related: 10-submission-detail-screen-6.md (first publish from detail), 05-storefront-widgets-and-read-api.md (storefront only returns allowed rows).
0) Goal (one sentence)
Section titled “0) Goal (one sentence)”Merchants use /app/testimonials/published to see only live testimonials, control where each item may appear (PDP, home, collection), pin/feature and reorder them, switch list vs grid for their own review, and unpublish without deleting the record.
1) Route and file
Section titled “1) Route and file”| Item | Value |
|---|---|
| Suggested file | app/routes/app.testimonial-published.jsx (see blueprint §6). |
| URL | /app/testimonials/published. |
Auth: authenticate.admin(request); all queries scoped by shopId.
Nav: add “Published” (or “Live”) under the testimonial group next to Submissions (09).
2) Data model additions (if not in schema today)
Section titled “2) Data model additions (if not in schema today)”Screen 7 needs per-placement visibility on a published submission. §5.7 lists published and merchandising; it may not list three booleans. Add in one migration (names illustrative — align with Prisma style):
| Field | Type | Purpose |
|---|---|---|
visibleOnPdp | Boolean @default(true) | Show in PDP widget query when placement=pdp. |
visibleOnHome | Boolean @default(false) | Eligible for home “top videos” and home carousel. |
visibleOnCollection | Boolean @default(false) | Future collection sections. |
featured | already in blueprint | Pin / weight in home ordering (05 featured_then_newest). |
sortOrder | Int? | Manual ordering within a context (see §5). |
Alternative: one Json field placementVisibility: { pdp, home, collection } — pick one approach and use it in 05 API filters.
Invariant: if published === false, all visibility flags are ignored and the row should not appear in 05 public API.
3) Loader: which rows to show
Section titled “3) Loader: which rows to show”where: { shopId, published: true, status: 'approved' }(tighten if you usestatus+publishedtogether — only approved content should be published).include: { mediaAsset: true }for thumbnails.orderBy:defaultsortOrder ascthenpublishedAt desc(document tie-breaker).
Do not include rejected or pending rows on this screen.
4) URL state (optional v1)
Section titled “4) URL state (optional v1)”view=grid|list— stored insearchParamsfor shareable admin view preference (no DB).
5) UI (Polaris)
Section titled “5) UI (Polaris)”5.1 Page header
Section titled “5.1 Page header”- Title: “Published testimonials”
- Secondary action: link to Submissions inbox (09)
- View toggle:
ButtonGrouporTabs— List vs Grid (affectsResourceListvsCardgrid only; same data).
5.2 Row / card content
Section titled “5.2 Row / card content”- Thumbnail, product title, media type, short quote or headline, submitted / published dates.
- Product assignment column: primary product title (from
Productjoin or snapshot); show “+N” ifTestimonialProductLinkhas extras.
5.3 Per-row controls (map to blueprint Fields)
Section titled “5.3 Per-row controls (map to blueprint Fields)”| Blueprint field | UI control | Persists |
|---|---|---|
| Visibility by placement: PDP | Checkbox or Toggle | visibleOnPdp |
| Home carousel | Toggle | visibleOnHome |
| Collection page | Toggle | visibleOnCollection |
| Feature/pin | Toggle | featured (or separate pinned if you split from “featured for algorithm” — v1: reuse featured) |
| Display order | Drag handle | sortOrder (see §6) |
| Unpublish | Button destructive or Button in kebab | published=false, publishedAt policy per 10 doc |
Batch save vs inline: v1 — Save per row on toggle (simplest) or sticky footer “Save changes” with dirty state — pick one to avoid partial updates.
5.4 Bulk actions (optional v2)
Section titled “5.4 Bulk actions (optional v2)”- “Unpublish selected”, “Show on home” — not required for MVP Screen 7 scope.
6) Drag-and-drop ordering
Section titled “6) Drag-and-drop ordering”- Use HTML5 DnD or a small library (e.g.
@dnd-kitif already in repo; else native) for reorder within the current list. - On drop: assign contiguous
sortOrdervalues (0, 1, 2, …) or gap-based (100, 200, …) for fewer rewrites. - POST
actionintent: "reorder"with ordered array of{ id, sortOrder }. - Transaction update many rows; verify each
idbelongs toshopId.
Scope of order: clarify whether sortOrder is global per shop or per placement (e.g. separate sort for home vs PDP). v1 recommendation: global sortOrder for simplicity; 05 API sorts featured first then sortOrder then date.
7) Actions (action export)
Section titled “7) Actions (action export)”| Intent | Behavior |
|---|---|
update_visibility | Update placement booleans for one submissionId. |
toggle_featured | Flip featured. |
unpublish | Set published=false; optional moderation log entry action=unpublish (08). |
reorder | Persist new sortOrder list. |
After each success: revalidate; toast confirmation.
8) Alignment with public API (05)
Section titled “8) Alignment with public API (05)”The GET testimonial endpoint must:
- Return only
published === trueandprocessingStatus === readyfor media. - For
placement=home: filtervisibleOnHome === true(and video rules from 05). - For
placement=pdp: filter by product id andvisibleOnPdp === true(unless you default PDP to true for product-bound items — document default: recommendvisibleOnPdpdefault true for submissions whose primary product matches).
Coordinate with whoever implements 05 so filters stay in sync.
9) Empty state
Section titled “9) Empty state”- If no published rows: EmptyState — “Nothing live yet. Approve and publish from Submissions.” + CTA to 09 or 10.
10) Testing checklist (acceptance criteria)
Section titled “10) Testing checklist (acceptance criteria)”- Only published submissions appear; changing unpublish removes them from this list and from 05 API.
- Toggling Home / PDP / Collection updates DB and changes 05 results for matching
placement(integration test or manual). - Reorder persists after reload; order reflected in home strip when using manual sort mode.
- Cross-shop id manipulation returns 404 or no-op in
action. -
featuredaffects ordering per agreed algorithm in 05.
11) Implementation order (for Cursor)
Section titled “11) Implementation order (for Cursor)”- Prisma migration: placement visibility fields + indexes
(shopId, published)if needed. - Loader for published-only list with includes.
- Page UI: list/grid, rows with toggles.
- Actions: unpublish, visibility, featured.
- Drag-and-drop reorder action.
- Update 05 public API filters in the same or linked PR (contract sync).
12) References
Section titled “12) References”02-Implementation-Blueprint.md— Screen 7, §5.7, §5.905-storefront-widgets-and-read-api.md— placement query rules10-submission-detail-screen-6.md— publish toggle origin
13) Note on numbering
Section titled “13) Note on numbering”This folder already includes 05–10 numbered plans. This file is 11-… (not 05-…).