Skip to content

19 — Dashboard (Screen 1, `/app`)

Cursor-ready plan: testimonial dashboard with KPI cards, date filter, top products, pending moderation CTA, and recent submissions feed.

Source: 02-Implementation-Blueprint.mdScreen 1 - Dashboard (/app).

Product alignment: 01-Post-Purchase-Video-Testimonial-Collector-Plan.md — operational overview and performance tracking for requests, submissions, approvals, and publication.

This document is a build spec only. No code changes are implied until a task references this file.

Related: 14-analytics-blueprint-screen-11.md (deep analytics), 09-submissions-inbox-screen-5.md (moderation queue), 13-requests-log-blueprint-screen-10.md (delivery status detail).


Merchants land on /app and immediately understand testimonial pipeline health through KPI cards, top products, pending moderation volume, and recent submission activity for a selected date range.


ItemValue
Suggested fileapp/routes/app._index.jsx (reuse existing dashboard route) or app/routes/app.testimonial-dashboard.jsx if you remap home route.
URL/app

Auth: authenticate.admin(request); all metrics scoped by current shopId.


Blueprint Screen 1 requires:

  • Date range filter (last 7/30/90 days)
  • KPI cards:
    • Requests sent
    • Request click rate
    • Submission rate
    • Approval rate
    • Published testimonials
  • Top products by testimonial count
  • Pending moderation count CTA
  • Recent submissions list (thumbnail, type, status)

This plan keeps exactly those as v1 scope.


Use URL search params:

  • range=7|30|90|custom
  • for custom: from=YYYY-MM-DD, to=YYYY-MM-DD

Use UTC day boundaries across all queries (consistent with blueprint build notes and existing app conventions).


For selected range:

  1. Requests sent

    • Count TestimonialRequest where sentAt in range.
  2. Request click rate

    • clicked_requests / sent_requests * 100
    • clicked_requests from clickedAt in range (or request event fallback).
  3. Submission rate

    • submitted_requests / sent_requests * 100
    • submitted_requests from submittedAt on request or linked submission in range.
  4. Approval rate

    • approved_submissions / submissions_count * 100
    • Use submission status and an approvedAt timestamp if available; otherwise derive from status with caveat.
  5. Published testimonials

    • Count submissions where published=true and publishedAt in range (or current published count if timestamp missing; label accordingly).

If denominator is 0, show 0% and helper tooltip “No sent requests in selected range”.


Group TestimonialSubmission by shopifyProductId in range (submitted or published depending on product choice).

Recommended v1:

  • sort by submissions_count desc
  • show top 5 products

Join with Product table for title fallback.

Per row:

  • Product title
  • Count badge
  • Optional breakdown approved/published

Compute:

  • pendingCount = submissions where status='pending'

Show card/banner with:

  • pending count
  • CTA button -> /app/testimonials?tab=pending

If zero:

  • show “No items waiting” neutral state.

Show latest N (e.g. 8–12) rows:

  • thumbnail (TestimonialMediaAsset.thumbnailUrl)
  • media type (video/photo)
  • status (pending/approved/rejected/archived)
  • submitted time
  • optional product title

Row click -> /app/testimonials/:id (Screen 6).


Single loader response with:

  • range
  • kpis
  • topProducts
  • pendingCount
  • recentSubmissions

Use Promise.all for query concurrency.


Suggested structure:

  1. Header: “Dashboard” + date range segmented control
  2. KPI row (5 cards)
  3. Two-column block:
    • left: Top products
    • right: Pending moderation CTA
  4. Recent submissions card/table

Use existing chart/card patterns already used in current app dashboard as baseline.


  • Keep recent submissions query small (take <= 12).
  • Add/confirm indexes:
    • TestimonialRequest(shopId, sentAt, clickedAt, submittedAt)
    • TestimonialSubmission(shopId, status, submittedAt, publishedAt, shopifyProductId)
  • Prefer pre-aggregated table (TestimonialDailyAnalytics, blueprint §5.11) later if live queries become slow.

  • If no testimonial data for range:
    • show empty-state guidance with CTA to Campaigns (/app/testimonial-campaigns)
  • If partial data (e.g. sent exists but no clicks):
    • still render cards with zero percentages.

  • Date range preset changes all KPI values consistently.
  • KPI formulas match SQL spot checks.
  • Pending CTA count matches inbox pending tab count.
  • Top product titles resolve correctly for missing local product rows.
  • Recent list shows correct status + timestamp + thumbnail fallback.
  • Cross-shop metric isolation verified.

  1. Replace chat-era dashboard loader queries with testimonial KPI queries.
  2. Implement date range parser and URL state.
  3. Build KPI cards and helper tooltips.
  4. Add top products + pending CTA cards.
  5. Add recent submissions list with links.
  6. Optional polish: trend deltas vs previous period.

  • 02-Implementation-Blueprint.md — Screen 1, §5.11, build notes (UTC buckets)
  • 14-analytics-blueprint-screen-11.md — deeper funnel definitions
  • 09-submissions-inbox-screen-5.md — pending queue semantics
  • 13-requests-log-blueprint-screen-10.md — request statuses

This folder already includes 05 through 18 plans. This file is 19-....