Skip to content

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.mdScreen 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).


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.


ItemValue
Suggested fileapp/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):

FieldTypePurpose
visibleOnPdpBoolean @default(true)Show in PDP widget query when placement=pdp.
visibleOnHomeBoolean @default(false)Eligible for home “top videos” and home carousel.
visibleOnCollectionBoolean @default(false)Future collection sections.
featuredalready in blueprintPin / weight in home ordering (05 featured_then_newest).
sortOrderInt?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.


  • where: { shopId, published: true, status: 'approved' } (tighten if you use status + published together — only approved content should be published).
  • include: { mediaAsset: true } for thumbnails.
  • orderBy: default sortOrder asc then publishedAt desc (document tie-breaker).

Do not include rejected or pending rows on this screen.


  • view=grid|list — stored in searchParams for shareable admin view preference (no DB).

  • Title: “Published testimonials”
  • Secondary action: link to Submissions inbox (09)
  • View toggle: ButtonGroup or TabsList vs Grid (affects ResourceList vs Card grid only; same data).
  • Thumbnail, product title, media type, short quote or headline, submitted / published dates.
  • Product assignment column: primary product title (from Product join or snapshot); show “+N” if TestimonialProductLink has extras.

5.3 Per-row controls (map to blueprint Fields)

Section titled “5.3 Per-row controls (map to blueprint Fields)”
Blueprint fieldUI controlPersists
Visibility by placement: PDPCheckbox or TogglevisibleOnPdp
Home carouselTogglevisibleOnHome
Collection pageTogglevisibleOnCollection
Feature/pinTogglefeatured (or separate pinned if you split from “featured for algorithm” — v1: reuse featured)
Display orderDrag handlesortOrder (see §6)
UnpublishButton destructive or Button in kebabpublished=false, publishedAt policy per 10 doc

Batch save vs inline: v1Save per row on toggle (simplest) or sticky footer “Save changes” with dirty state — pick one to avoid partial updates.

  • “Unpublish selected”, “Show on home” — not required for MVP Screen 7 scope.

  • Use HTML5 DnD or a small library (e.g. @dnd-kit if already in repo; else native) for reorder within the current list.
  • On drop: assign contiguous sortOrder values (0, 1, 2, …) or gap-based (100, 200, …) for fewer rewrites.
  • POST action intent: "reorder" with ordered array of { id, sortOrder }.
  • Transaction update many rows; verify each id belongs to shopId.

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.


IntentBehavior
update_visibilityUpdate placement booleans for one submissionId.
toggle_featuredFlip featured.
unpublishSet published=false; optional moderation log entry action=unpublish (08).
reorderPersist new sortOrder list.

After each success: revalidate; toast confirmation.


The GET testimonial endpoint must:

  • Return only published === true and processingStatus === ready for media.
  • For placement=home: filter visibleOnHome === true (and video rules from 05).
  • For placement=pdp: filter by product id and visibleOnPdp === true (unless you default PDP to true for product-bound items — document default: recommend visibleOnPdp default true for submissions whose primary product matches).

Coordinate with whoever implements 05 so filters stay in sync.


  • 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.
  • featured affects ordering per agreed algorithm in 05.

  1. Prisma migration: placement visibility fields + indexes (shopId, published) if needed.
  2. Loader for published-only list with includes.
  3. Page UI: list/grid, rows with toggles.
  4. Actions: unpublish, visibility, featured.
  5. Drag-and-drop reorder action.
  6. Update 05 public API filters in the same or linked PR (contract sync).

  • 02-Implementation-Blueprint.mdScreen 7, §5.7, §5.9
  • 05-storefront-widgets-and-read-api.md — placement query rules
  • 10-submission-detail-screen-6.md — publish toggle origin

This folder already includes 0510 numbered plans. This file is 11-… (not 05-…).