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.tsAfter (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 # mergedAPI 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(mergeshows/shows.ts+shows/codeGenerator.ts)domains/events.ts(fromshows/events.ts)domains/experiences.http.ts(fromshows/shows.http.ts)
Files to DELETE:
domains/shows/shows.tsdomains/shows/events.tsdomains/shows/shows.http.tsdomains/shows/codeGenerator.tsdomains/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 inanalytics/)
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 toapi.domains.experiences.*orapi.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
listAllFromDbto staticlistAll
// 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
experienceListtoshowList -
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_counttranslation
"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 --noEmitExpected: No errors
- Step 2: Run TypeScript check on frontend
cd apps/frontend && pnpm tsc --noEmitExpected: No errors
- Step 3: Build frontend
cd apps/frontend && pnpm buildExpected: 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.shows→experiences,shows.events→events
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?