plans
2026-05-10
2026 05 10 Experiences Page Fix

Shows Dashboard + Convex Domain Flattening Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Flatten convex domain structure from domains/<domain>/<module>.ts to domains/<domain>.ts. Fix /dashboard/shows page to use static show list with inline editing only for pricing fields.

Architecture:

  • Convex: Flat structure domains/<domain>.ts → API: api.domains.<domain>.<function>
  • Frontend: Shows are hardcoded static data. Users can only edit pricing fields and manage events.
  • No nested subdirectories in domains/

Tech Stack: Next.js 16 (App Router), Convex real-time DB, paraglide-js i18n


Convex Domain Flattening Map

Before (Nested):

domains/
├── analytics/analytics.ts
├── checkins/checkins.ts
├── crm/crm.ts, sync.ts, syncInternal.ts
├── forms/contactForm.ts, formSessions.ts, proposalForms.ts
├── minigames/challenges.ts, menu.ts, liveViewers.ts, recurrence.ts
├── notifications/notifications.ts, notificationsInternal.ts
├── payments/pricing.ts, orders.ts, addons.ts
├── profiles/profiles.ts
├── reservations/reservations.ts, createOrder.ts, bookingDrafts.ts
├── shows/shows.ts, events.ts, shows.http.ts, codeGenerator.ts

After (Flat):

domains/
├── analytics.ts      # merged
├── checkins.ts      # merged
├── crm.ts           # merged
├── events.ts        # from shows/events.ts
├── experiences.ts   # from shows/shows.ts + codeGenerator.ts
├── experiences.http.ts  # from shows/shows.http.ts
├── forms.ts         # merged
├── minigames.ts     # merged
├── notifications.ts # merged
├── payments.ts      # merged
├── profiles.ts      # merged
├── reservations.ts  # merged

API Result:

api.domains.experiences.listAll
api.domains.experiences.listActive
api.domains.events.listUpcoming
api.domains.analytics.*
api.domains.checkins.*
api.domains.crm.*
api.domains.forms.*
api.domains.minigames.*
api.domains.notifications.*
api.domains.payments.*
api.domains.profiles.*
api.domains.reservations.*

PHASE 1: Convex Domain Flattening

Task 1: Flatten shows/ Domain

Files to CREATE:

  • domains/experiences.ts (merge shows/shows.ts + shows/codeGenerator.ts)
  • domains/events.ts (from shows/events.ts)
  • domains/experiences.http.ts (from shows/shows.http.ts)

Files to DELETE:

  • domains/shows/shows.ts
  • domains/shows/events.ts
  • domains/shows/shows.http.ts
  • domains/shows/codeGenerator.ts
  • domains/shows/index.ts

Steps:

  • Step 1: Create domains/experiences.ts

Merge shows/shows.ts (excluding listAllFromDb) + shows/codeGenerator.ts. Remove listAllFromDb query.

  • Step 2: Create domains/events.ts

Copy contents from shows/events.ts.

  • Step 3: Create domains/experiences.http.ts

Copy contents from shows/shows.http.ts.

  • Step 4: Create domains/shows.ts (temporary redirect)

Create shows.ts that re-exports from experiences.ts for backward compat during migration:

// TEMPORARY - remove after frontend migration
export * from "./experiences";
  • Step 5: Delete old files
rm -rf domains/shows/
  • Step 6: Verify TypeScript compiles
cd packages/backend/convex && npx tsc --noEmit
  • Step 7: Commit
git add -A
git commit -m "refactor(convex): flatten shows/ to experiences.ts and events.ts"

Task 2: Flatten analytics/ Domain

Files to CREATE:

  • domains/analytics.ts (merge all files in analytics/)

Files to DELETE:

  • domains/analytics/analytics.ts

  • domains/analytics/scheduled.test.ts

  • domains/analytics/analytics.test.ts

  • domains/analytics/index.ts

  • Step 1: Create domains/analytics.ts

Merge all TypeScript files from analytics/ into single analytics.ts.

  • Step 2: Delete old directory
rm -rf domains/analytics/
  • Step 3: Verify TypeScript compiles
cd packages/backend/convex && npx tsc --noEmit
  • Step 4: Commit
git add -A
git commit -m "refactor(convex): flatten analytics/ to analytics.ts"

Task 3: Flatten checkins/ Domain

Files to CREATE:

  • domains/checkins.ts

Files to DELETE:

  • domains/checkins/checkins.ts

  • domains/checkins/index.ts

  • Step 1: Create domains/checkins.ts

Copy contents from checkins/checkins.ts.

  • Step 2: Delete old directory
rm -rf domains/checkins/
  • Step 3: Commit
git add -A
git commit -m "refactor(convex): flatten checkins/ to checkins.ts"

Task 4: Flatten crm/ Domain

Files to CREATE:

  • domains/crm.ts

Files to DELETE:

  • domains/crm/crm.ts

  • domains/crm/sync.ts

  • domains/crm/syncInternal.ts

  • domains/crm/index.ts

  • Step 1: Create domains/crm.ts

Merge all TypeScript files from crm/.

  • Step 2: Delete old directory
rm -rf domains/crm/
  • Step 3: Commit
git add -A
git commit -m "refactor(convex): flatten crm/ to crm.ts"

Task 5: Flatten forms/ Domain

Files to CREATE:

  • domains/forms.ts

Files to DELETE:

  • domains/forms/contactForm.ts

  • domains/forms/formSessions.ts

  • domains/forms/proposalForms.ts

  • domains/forms/index.ts

  • Step 1: Create domains/forms.ts

Merge all TypeScript files from forms/.

  • Step 2: Delete old directory
rm -rf domains/forms/
  • Step 3: Commit
git add -A
git commit -m "refactor(convex): flatten forms/ to forms.ts"

Task 6: Flatten minigames/ Domain

Files to CREATE:

  • domains/minigames.ts

Files to DELETE:

  • domains/minigames/challenges.ts

  • domains/minigames/menu.ts

  • domains/minigames/liveViewers.ts

  • domains/minigames/recurrence.ts

  • domains/minigames/schemas/minigames.ts

  • domains/minigames/index.ts

  • Step 1: Create domains/minigames.ts

Merge all TypeScript files from minigames/. Note: schemas/minigames.ts may contain only type definitions - keep separate if needed.

  • Step 2: Delete old directory
rm -rf domains/minigames/
  • Step 3: Commit
git add -A
git commit -m "refactor(convex): flatten minigames/ to minigames.ts"

Task 7: Flatten notifications/ Domain

Files to CREATE:

  • domains/notifications.ts

Files to DELETE:

  • domains/notifications/notifications.ts

  • domains/notifications/notificationsInternal.ts

  • domains/notifications/index.ts

  • Step 1: Create domains/notifications.ts

Merge all TypeScript files from notifications/.

  • Step 2: Delete old directory
rm -rf domains/notifications/
  • Step 3: Commit
git add -A
git commit -m "refactor(convex): flatten notifications/ to notifications.ts"

Task 8: Flatten payments/ Domain

Files to CREATE:

  • domains/payments.ts

Files to DELETE:

  • domains/payments/pricing.ts

  • domains/payments/orders.ts

  • domains/payments/addons.ts

  • domains/payments/payments.ts

  • domains/payments/tables.ts

  • domains/payments/index.ts

  • Step 1: Create domains/payments.ts

Merge all TypeScript files from payments/. Note: tables.ts may contain only schema/table definitions - keep in schema.ts if needed.

  • Step 2: Delete old directory
rm -rf domains/payments/
  • Step 3: Commit
git add -A
git commit -m "refactor(convex): flatten payments/ to payments.ts"

Task 9: Flatten profiles/ Domain

Files to CREATE:

  • domains/profiles.ts

Files to DELETE:

  • domains/profiles/profiles.ts

  • domains/profiles/index.ts

  • Step 1: Create domains/profiles.ts

Copy contents from profiles/profiles.ts.

  • Step 2: Delete old directory
rm -rf domains/profiles/
  • Step 3: Commit
git add -A
git commit -m "refactor(convex): flatten profiles/ to profiles.ts"

Task 10: Flatten reservations/ Domain

Files to CREATE:

  • domains/reservations.ts

Files to DELETE:

  • domains/reservations/reservations.ts

  • domains/reservations/createOrder.ts

  • domains/reservations/bookingDrafts.ts

  • domains/reservations/booking.http.ts

  • domains/reservations/index.ts

  • Step 1: Create domains/reservations.ts

Merge all TypeScript files from reservations/.

  • Step 2: Create domains/reservations.http.ts (if HTTP handlers needed separately)

Move booking.http.ts contents if it contains HTTP action handlers.

  • Step 3: Delete old directory
rm -rf domains/reservations/
  • Step 4: Commit
git add -A
git commit -m "refactor(convex): flatten reservations/ to reservations.ts"

Task 11: Remove domains/shows.ts Temporary Redirect

Files to DELETE:

  • domains/shows.ts (temporary backward-compat file)

  • Step 1: Delete temporary redirect

rm domains/shows.ts
  • Step 2: Commit
git add -A
git commit -m "refactor(convex): remove shows.ts temporary redirect"

PHASE 2: Frontend Updates

Task 12: Update Frontend Imports

Files to check:

  • All files importing from api.domains.shows.* need to update to api.domains.experiences.* or api.domains.events.*

  • Files importing from packages/backend/convex/domains/shows/* need updates

  • Step 1: Find all files importing from shows domain

grep -r "domains.shows" apps/frontend --include="*.ts" --include="*.tsx"
  • Step 2: Update imports

Replace:

  • api.domains.shows.shows.*api.domains.experiences.*

  • api.domains.shows.events.*api.domains.events.*

  • Step 3: Commit

git add -A
git commit -m "refactor(frontend): update imports from shows to experiences"

Task 13: Rename Dashboard Route experiences/shows/

Files:

  • Rename: apps/frontend/app/dashboard/experiences/apps/frontend/app/dashboard/shows/

  • Step 1: Rename directory

mv apps/frontend/app/dashboard/experiences apps/frontend/app/dashboard/shows
  • Step 2: Commit
git add -A
git commit -m "refactor: rename dashboard/experiences route to dashboard/shows"

Task 14: Update Shows Page to Use Static listAll

Files:

  • Modify: apps/frontend/app/dashboard/shows/page.tsx

  • Step 1: Change data source from listAllFromDb to static listAll

// Before
const experienceList = useQuery(api.domains.shows.shows.listAllFromDb) as
  | Show[]
  | undefined;
 
// After
const showList = useQuery(api.domains.experiences.listAll) as
  | Show[]
  | undefined;
  • Step 2: Remove "Add New" button from PageHeader actions

Replace button with count display:

<span className="text-sm text-[var(--color-muted-foreground)]">
  {showList.length} {m.admin_shows_count()}
</span>
  • Step 3: Remove unused state and imports

Remove useTransition state for showCreateNew, remove Plus import if unused.

  • Step 4: Update remaining references from experienceList to showList

  • Step 5: Commit

git add apps/frontend/app/dashboard/shows/page.tsx
git commit -m "fix(shows): use static listAll from experiences API"

Task 15: Make Title/Tagline/Description Read-Only in ShowCard

Files:

  • Modify: apps/frontend/app/dashboard/shows/page.tsx

  • Step 1: Replace InlineEditField with static display for Title

// Before
<InlineEditField value={show.title} onSave={(v) => handleUpdate("title", v)} />
 
// After
<p className="text-lg font-semibold">{show.title}</p>
  • Step 2: Replace InlineEditField with static display for Tagline
<p className="text-sm text-[var(--color-muted-foreground)]">{show.tagline}</p>
  • Step 3: Replace InlineEditField with static display for Description
<p className="text-sm text-[var(--color-muted-foreground)] line-clamp-2">{show.description}</p>
  • Step 4: Replace InlineStatusField with static status badge
<span className={cn(
  "inline-flex items-center gap-1.5 px-2 py-0.5 rounded-full text-xs font-medium",
  show.status === "ACTIVE" ? "bg-green-500/20 text-green-400" :
  show.status === "DRAFT" ? "bg-yellow-500/20 text-yellow-400" :
  "bg-gray-500/20 text-gray-400"
)}>
  {show.status === "ACTIVE" ? m.admin_shows_form_statuses_active() :
   show.status === "DRAFT" ? m.admin_shows_form_statuses_draft() :
   m.admin_shows_form_statuses_archived()}
</span>
  • Step 5: Commit
git add apps/frontend/app/dashboard/shows/page.tsx
git commit -m "fix(shows): make title/tagline/description/status read-only"

Task 16: Remove Unused InlineEditField and InlineStatusField

Files:

  • Modify: apps/frontend/app/dashboard/shows/page.tsx

  • Step 1: Remove InlineEditField function

Delete the entire InlineEditField component (lines 53-125).

  • Step 2: Remove InlineStatusField function

Delete the entire InlineStatusField component.

  • Step 3: Clean up unused imports

Remove Textarea if no longer used, remove Pencil, Check from lucide imports.

Keep: useCallback (still used by handleUpdate).

  • Step 4: Commit
git add apps/frontend/app/dashboard/shows/page.tsx
git commit -m "refactor(shows): remove unused InlineEditField and InlineStatusField"

Task 17: Add Missing Translation Key

Files:

  • Modify: messages/en.json

  • Modify: messages/vi.json

  • Step 1: Add admin_shows_count translation

"admin_shows_count": "{count} shows"
"admin_shows_count": "{count} suất diễn"
  • Step 2: Compile paraglide
cd apps/frontend && node scripts/compile-paraglide.js
  • Step 3: Commit
git add messages/en.json messages/vi.json
git commit -m "i18n: add admin_shows_count translation key"

PHASE 3: Final Verification

Task 18: Full TypeScript Check

  • Step 1: Run TypeScript check on backend
cd packages/backend/convex && npx tsc --noEmit

Expected: No errors

  • Step 2: Run TypeScript check on frontend
cd apps/frontend && pnpm tsc --noEmit

Expected: No errors

  • Step 3: Build frontend
cd apps/frontend && pnpm build

Expected: Build succeeds

  • Step 4: Commit all remaining changes
git add -A
git commit -m "fix: complete shows dashboard and convex flattening"

Self-Review Checklist

  • Spec coverage:

    • Convex domains flattened to single files
    • API paths: api.domains.<domain>.<function>
    • Shows page uses static listAll
    • Only pricing fields editable inline
    • Title/tagline/description/status read-only
    • No "Add New Show" button
    • Event management preserved
  • No placeholder content (TBD, TODO)

  • Type consistency verified across all domains

  • Naming: All shows.showsexperiences, shows.eventsevents


Execution Options

Plan complete and saved to docs/superpowers/plans/2026-05-10-experiences-page-fix.md.

1. Subagent-Driven (recommended) - I dispatch a fresh subagent per task, review between tasks, fast iteration

2. Inline Execution - Execute tasks in this session using executing-plans, batch execution with checkpoints

Which approach?