plans
2026-05-11
2026 05 11 Shadcn Only Migration

Shadcn-Only Migration 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: Enforce components/ui/ = shadcn/ui primitives only. Move 49 misplaced components to their proper directories and fix all 134 importing files.

Architecture: Migrate components in category batches. Each batch: (1) move files to target directory, (2) update all imports, (3) verify build passes, (4) commit. This isolates breaks and provides rollback points.

Tech Stack: Next.js 16, TypeScript, Tailwind CSS


Background

The components/ui/ directory contains 119 files. The shadcn-only rule (components/ui/.claude/rules/shadcn-only.md) allows only:

  • shadcn/ui base components (button.tsx, dialog.tsx, input.tsx, etc.)
  • shadcn derivatives that remain UI primitives
  • icon-symbol.tsx (icon exception)

Current violations: ~49 components violate this rule by being custom page/section components, feature components, or composited UI that should live in domain directories.

Duplicate crisis: Some components exist in BOTH ui/ AND their correct domain directory with DIFFERENT implementations (different sizes). This means consumers may be using the WRONG implementation.


Phase 0: Pre-Migration Audit

Before touching anything, verify build is clean and document current state.

  • Step 1: Verify current build passes
cd apps/frontend && bun run build 2>&1 | tail -20

Expected: Clean build with no errors.

  • Step 2: Document all ui/ components and their import counts
cd apps/frontend
echo "=== ALL ui/ files with import counts ==="
for f in components/ui/*.tsx; do
  name=$(basename "$f" .tsx)
  count=$(grep -r "from \"~/components/ui/$name\"" --include="*.tsx" --include="*.ts" -l 2>/dev/null | wc -l | tr -d ' ')
  echo "$name: $count imports"
done | sort -t: -k2 -rn

Save output to docs/superpowers/plans/2026-05-11-shadcn-only-migration-AUDIT.md.

  • Step 3: Identify true duplicates (same name in ui/ AND domain dirs)
cd apps/frontend
for f in components/ui/*.tsx; do
  name=$(basename "$f")
  for dir in marketing home booking forms layout experiences; do
    if [ -f "components/$dir/$name" ]; then
      echo "DUPLICATE: $name in ui/ AND $dir/"
      echo "  ui/: $(wc -c < components/ui/$name)"
      echo "  $dir/: $(wc -c < components/$dir/$name)"
    fi
  done
done
  • Step 4: Commit audit results
git add docs/superpowers/plans/2026-05-11-shadcn-only-migration-AUDIT.md
git commit -m "docs: audit shadcn-only violations before migration"

Phase 1: Delete Duplicates (Remove Wrong Implementations)

Where a component exists in both ui/ and its correct domain, keep the domain version and delete the ui/ version.

Task 1: Handle page-hero duplicates

Files:

  • Delete: components/ui/page-hero.tsx (violation + duplicate)

  • Already exists: components/marketing/page-hero.tsx

  • Step 1: Verify files are identical

diff components/ui/page-hero.tsx components/marketing/page-hero.tsx && echo "IDENTICAL - safe to delete ui/ version"
  • Step 2: Delete ui/ version
rm components/ui/page-hero.tsx
  • Step 3: Verify no imports break
grep -r "from \"~/components/ui/page-hero\"" --include="*.tsx" --include="*.ts" -l

Expected: should show our-evening/page.tsx (already fixed earlier).

  • Step 4: Verify build
cd apps/frontend && bun run build 2>&1 | tail -10
  • Step 5: Commit
git add -A
git commit -m "fix: remove duplicate page-hero from ui/ (already exists in marketing/)"

Task 2: Handle experience-card duplicates

Files:

  • components/ui/experience-card.tsx (10526 bytes - likely bloated wrong version)

  • components/marketing/experience-card.tsx (1122 bytes - correct marketing version)

  • Step 1: Compare implementations

head -50 components/ui/experience-card.tsx
echo "---"
head -50 components/marketing/experience-card.tsx
  • Step 2: Identify which is the correct implementation Check which one matches the design system. The marketing/ version is 10x smaller - likely the correct abstracted version.

  • Step 3: Update imports to point to correct location If ui/ version is wrong:

# Find all imports of the WRONG implementation
grep -r "from \"~/components/ui/experience-card\"" --include="*.tsx" -l

Then update each to ~/components/marketing/experience-card.

  • Step 4: Delete ui/ version
rm components/ui/experience-card.tsx
  • Step 5: Verify build

  • Step 6: Commit


Task 3: Handle other duplicates (contact-info-section, gallery-section, experience-option)

Same pattern as Task 2.

Repeat for each:

  1. Compare implementations
  2. Identify correct version (usually the domain dir version is correct)
  3. Update imports to point to correct domain dir
  4. Delete ui/ version
  5. Verify build
  6. Commit

Phase 2: Move Section/Showcase Components to components/marketing/sections/

Target: components/marketing/sections/ (create if not exists)

Components to move (22):

  • content-section.tsx
  • corner-accent-overlay.tsx
  • corner-accents.tsx
  • form-section.tsx
  • form-step-wrapper.tsx
  • framed-image.tsx
  • gallery-section.tsx
  • google-reviews-link.tsx
  • highlights-section.tsx
  • icon-cards-grid.tsx
  • icon-grid.tsx
  • image-card-grid.tsx
  • image-frame.tsx
  • recommended-by-section.tsx
  • section-container.tsx
  • section-divider.tsx
  • section-nav.tsx
  • section-title.tsx
  • step-nav-footer.tsx
  • timeline-section.tsx
  • upcoming-shows-section.tsx
  • video-frame.tsx

Task 4: Create sections/ directory

  • Step 1: Create directory
mkdir -p components/marketing/sections
  • Step 2: Move components
cd components/ui
mv content-section.tsx corner-accent-overlay.tsx corner-accents.tsx form-section.tsx form-step-wrapper.tsx framed-image.tsx gallery-section.tsx google-reviews-link.tsx highlights-section.tsx icon-cards-grid.tsx icon-grid.tsx image-card-grid.tsx image-frame.tsx recommended-by-section.tsx section-container.tsx section-divider.tsx section-nav.tsx section-title.tsx step-nav-footer.tsx timeline-section.tsx upcoming-shows-section.tsx video-frame.tsx ../marketing/sections/
  • Step 3: Update ALL imports in 134 files
# Find all files importing from ui/ that should now use marketing/sections/
# This will be a large sed operation
cd ../..
find . -name "*.tsx" -o -name "*.ts" | xargs grep -l "~/components/ui/content-section" | head -20

For each component, run:

find . -name "*.tsx" -o -name "*.ts" | xargs sed -i '' 's|~/components/ui/COMPONENT_NAME|~/components/marketing/sections/COMPONENT_NAME|g'

IMPORTANT: Run these sed commands one component at a time, then verify build before proceeding.

  • Step 4: Verify build after each component batch
bun run build 2>&1 | grep -E "error|Error|FAILED" | head -20
  • Step 5: Commit after full batch passes
git add -A
git commit -m "refactor: move section/showcase components from ui/ to marketing/sections/"

Phase 3: Move Experience/Card Components

Target directory depends on component:

  • components/experiences/ for experience-specific cards
  • components/booking/ for booking-specific cards
  • components/marketing/ for marketing cards

Components to move (12):

  • booking-info-row.tsxcomponents/booking/
  • booking-modal.tsxcomponents/booking/
  • cinema-ticket-header.tsxcomponents/booking/ or components/confirmation/
  • experience-card.tsxcomponents/marketing/ (already duplicate handled in Phase 1)
  • experience-option.tsxcomponents/booking/ (already duplicate handled in Phase 1)
  • glass-card.tsxcomponents/marketing/
  • icon-box.tsx → needs review (could be generic primitive)
  • journey-card.tsxcomponents/experiences/
  • numbered-card.tsxcomponents/marketing/
  • premium-card.tsxcomponents/marketing/
  • service-card.tsxcomponents/marketing/
  • why-card.tsxcomponents/marketing/

Task 5: Move booking components

  • Move booking-info-row.tsx, booking-modal.tsx, cinema-ticket-header.tsx to components/booking/
  • Update imports
  • Verify build
  • Commit

Task 6: Move experience components

  • Move journey-card.tsx to components/experiences/
  • Update imports
  • Verify build
  • Commit

Task 7: Move marketing cards

  • Move glass-card.tsx, numbered-card.tsx, premium-card.tsx, service-card.tsx, why-card.tsx to components/marketing/
  • Update imports
  • Verify build
  • Commit

Task 8: Review icon-box (borderline)

  • Analyze icon-box.tsx usage
  • If generic primitive → keep in ui/ but document why
  • If domain-specific → move to appropriate directory

Phase 4: Move Info/Contact Components to components/marketing/

Components to move (7):

  • contact-info-block.tsxcomponents/marketing/
  • contact-info-section.tsxcomponents/marketing/ (already duplicate handled in Phase 1)
  • design-system-nav.tsxcomponents/admin/ or components/layout/
  • info-item.tsxcomponents/marketing/ or keep in ui/ if generic
  • overline.tsx → keep in ui/ if generic typography
  • recommendation-card.tsxcomponents/marketing/
  • review-card.tsxcomponents/marketing/

Task 9: Move info/contact components

  • Move each component to appropriate directory
  • Update imports
  • Verify build
  • Commit

Phase 5: Move Form Components to components/forms/

Components to move (6):

  • auto-resize-textarea.tsx
  • field.tsx
  • form-button.tsx
  • form-field.tsx
  • form.tsx
  • number-field.tsx

Task 10: Move form components

  • Move all 6 to components/forms/
  • Update imports
  • Verify build
  • Commit

Phase 6: Move Layout/Nav Components to components/layout/

Components to move (2):

  • locale-link.tsx
  • social-icons.tsx

Task 11: Move layout components

  • Move to components/layout/
  • Update imports
  • Verify build
  • Commit

Phase 7: Review "Potentially OK" Components

These need manual review to determine if they belong in ui/ or should be moved:

ComponentQuestion
hover-card.tsxIs this a shadcn derivative or custom?
info-row.tsxGeneric or domain-specific?
info-tooltip.tsxGeneric or domain-specific?
menu-book-modal.tsxBooking-specific → components/booking/?
modal-close-button.tsxGeneric primitive or domain?
security-badge.tsxBooking/trust-specific?
social-proof.tsxMarketing-specific?
spinner.tsxGeneric loading indicator (OK in ui/)
status-badge.tsxGeneric or domain-specific?

Task 12: Review each borderline component

For each:

  • Read the component source
  • Determine if it's a true shadcn primitive (generic, reusable)
  • If domain-specific → move to appropriate directory
  • If generic → document why it stays in ui/

Phase 8: Final Verification

  • Step 1: Run full build
cd apps/frontend && bun run build 2>&1 | tail -30
  • Step 2: Verify no imports from misplaced components
# Should return empty after all migrations
grep -r "from \"~/components/ui/(content-section|timeline-section|highlights-section|journey-card|experience-card|form-field|locale-link)\"" --include="*.tsx" components/
  • Step 3: Verify shadcn-only rule enforcement
echo "Remaining non-shadcn in ui/:"
ls components/ui/*.tsx | while read f; do
  name=$(basename "$f" .tsx)
  # Check if it's a known shadcn component
  case $name in
    accordion|badge|button|calendar|card|carousel|chart|checkbox|collapsible|command|confirm-dialog|dialog|dropdown-menu|input|input-otp|label|menubar|navigation-menu|popover|progress|radio-group|resizable|select|separator|sheet|skeleton|slider|sonner|switch|table|tabs|textarea|toggle|toggle-group|tooltip|icon-symbol)
      # Known shadcn - OK
      ;;
    *)
      echo "REVIEW: $name"
      ;;
  esac
done
  • Step 4: Final commit
git add -A
git commit -m "refactor: complete shadcn-only enforcement for components/ui/"

Rollback Plan

If build breaks during migration:

# Find last good commit
git log --oneline -10
 
# Rollback to last good state
git reset --hard <last-good-commit-sha>
 
# Then restart migration from next batch

Never use git push --force on main branch.


Files Created/Modified Summary

PhaseFiles CreatedFiles DeletedFiles Modified
Phase 0: Audit...-AUDIT.md00
Phase 1: Duplicates06~20
Phase 2: Sections022~80
Phase 3: Cards012~40
Phase 4: Info/Contact07~20
Phase 5: Forms06~15
Phase 6: Layout02~10
Phase 7: ReviewTBDTBDTBD
Total149134

Self-Review Checklist

Before marking plan complete:

  • All 49 misplaced components are accounted for
  • All 134 importing files will be updated
  • Each phase has rollback capability (commit after each)
  • Build verification steps included in each phase
  • No placeholder/TODO content in plan
  • File paths are exact (no wildcards in commands)