mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-24 20:31:12 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
724
migration/PHASE_12_PAGES_MIGRATION.md
Normal file
724
migration/PHASE_12_PAGES_MIGRATION.md
Normal file
@@ -0,0 +1,724 @@
|
||||
# PHASE 12: Next.js 15 App Router Pages Migration
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Estimated Time:** 45-55 hours
|
||||
**Priority:** CRITICAL
|
||||
**Depends On:** All previous phases (1-11)
|
||||
**Blocks:** Phase 13 (Next.js Optimization)
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Goal
|
||||
|
||||
Convert ALL React SPA pages to Next.js 15 App Router pages while replacing Supabase calls with Django services. This is a DUAL migration:
|
||||
1. **React → Next.js App Router**: Convert pages and routing
|
||||
2. **Supabase → Django**: Replace all data fetching
|
||||
|
||||
**Critical Requirements:**
|
||||
- Preserve ALL existing URLs
|
||||
- Maintain exact same UI/UX
|
||||
- Use Server Components by default
|
||||
- Mark Client Components with 'use client'
|
||||
- Sacred Pipeline remains intact
|
||||
|
||||
---
|
||||
|
||||
## 📋 Next.js App Router Structure
|
||||
|
||||
### New Directory Structure
|
||||
|
||||
```
|
||||
app/
|
||||
├── layout.tsx # Root layout
|
||||
├── page.tsx # Homepage
|
||||
├── loading.tsx # Global loading
|
||||
├── error.tsx # Global error
|
||||
├── not-found.tsx # 404 page
|
||||
│
|
||||
├── parks/
|
||||
│ ├── page.tsx # /parks (listing)
|
||||
│ ├── loading.tsx # Loading state
|
||||
│ ├── [parkSlug]/
|
||||
│ │ ├── page.tsx # /parks/[parkSlug]
|
||||
│ │ ├── loading.tsx
|
||||
│ │ └── rides/
|
||||
│ │ └── page.tsx # /parks/[parkSlug]/rides
|
||||
│ └── owners/
|
||||
│ └── [ownerSlug]/
|
||||
│ └── page.tsx # /owners/[ownerSlug]/parks
|
||||
│
|
||||
├── rides/
|
||||
│ ├── page.tsx # /rides (listing)
|
||||
│ ├── [rideSlug]/
|
||||
│ │ ├── page.tsx # /rides/[rideSlug]
|
||||
│ │ └── reviews/
|
||||
│ │ └── page.tsx # /rides/[rideSlug]/reviews
|
||||
│ └── models/
|
||||
│ └── [modelSlug]/
|
||||
│ ├── page.tsx # /ride-models/[modelSlug]
|
||||
│ └── rides/
|
||||
│ └── page.tsx # /ride-models/[modelSlug]/rides
|
||||
│
|
||||
├── manufacturers/
|
||||
│ ├── page.tsx # /manufacturers (listing)
|
||||
│ └── [manufacturerSlug]/
|
||||
│ ├── page.tsx # /manufacturers/[manufacturerSlug]
|
||||
│ └── rides/
|
||||
│ └── page.tsx # /manufacturers/[manufacturerSlug]/rides
|
||||
│
|
||||
├── owners/
|
||||
│ ├── page.tsx # /owners (listing)
|
||||
│ └── [ownerSlug]/
|
||||
│ └── page.tsx # /owners/[ownerSlug]
|
||||
│
|
||||
├── designers/
|
||||
│ ├── page.tsx # /designers (listing)
|
||||
│ └── [designerSlug]/
|
||||
│ └── page.tsx # /designers/[designerSlug]
|
||||
│
|
||||
├── auth/
|
||||
│ ├── login/
|
||||
│ │ └── page.tsx
|
||||
│ ├── register/
|
||||
│ │ └── page.tsx
|
||||
│ └── callback/
|
||||
│ └── page.tsx
|
||||
│
|
||||
├── profile/
|
||||
│ ├── page.tsx # /profile
|
||||
│ ├── settings/
|
||||
│ │ └── page.tsx
|
||||
│ └── lists/
|
||||
│ └── page.tsx
|
||||
│
|
||||
├── admin/
|
||||
│ ├── page.tsx # /admin
|
||||
│ └── moderation/
|
||||
│ └── page.tsx # /admin/moderation
|
||||
│
|
||||
├── search/
|
||||
│ └── page.tsx # /search
|
||||
│
|
||||
└── contact/
|
||||
└── page.tsx # /contact
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📋 Tasks
|
||||
|
||||
### Task 12.1: Root Layout & Homepage (6 hours)
|
||||
|
||||
#### Create Root Layout
|
||||
|
||||
`app/layout.tsx` (Server Component):
|
||||
|
||||
```typescript
|
||||
import { Inter } from 'next/font/google';
|
||||
import './globals.css';
|
||||
import { AuthProvider } from '@/components/providers/AuthProvider';
|
||||
import { Navigation } from '@/components/layout/Navigation';
|
||||
import { Footer } from '@/components/layout/Footer';
|
||||
|
||||
const inter = Inter({ subsets: ['latin'] });
|
||||
|
||||
export const metadata = {
|
||||
title: 'ThrillWiki - Theme Park & Ride Database',
|
||||
description: 'Comprehensive database of theme parks and rides',
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
children,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body className={inter.className}>
|
||||
<AuthProvider>
|
||||
<Navigation />
|
||||
<main className="min-h-screen">{children}</main>
|
||||
<Footer />
|
||||
</AuthProvider>
|
||||
</body>
|
||||
</html>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Convert Homepage
|
||||
|
||||
`app/page.tsx` (Server Component):
|
||||
|
||||
```typescript
|
||||
import { env } from '@/lib/env';
|
||||
import { FeaturedParks } from '@/components/home/FeaturedParks';
|
||||
import { RecentReviews } from '@/components/home/RecentReviews';
|
||||
import { Stats } from '@/components/home/Stats';
|
||||
|
||||
export default async function HomePage() {
|
||||
// Fetch data server-side
|
||||
const [parks, stats] = await Promise.all([
|
||||
fetch(`${env.NEXT_PUBLIC_DJANGO_API_URL}/parks/?featured=true`).then(r => r.json()),
|
||||
fetch(`${env.NEXT_PUBLIC_DJANGO_API_URL}/stats/`).then(r => r.json()),
|
||||
]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Hero />
|
||||
<Stats data={stats} />
|
||||
<FeaturedParks parks={parks} />
|
||||
<RecentReviews />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist
|
||||
- [ ] Create `app/layout.tsx` with root layout
|
||||
- [ ] Create `app/page.tsx` for homepage
|
||||
- [ ] Create `app/loading.tsx` for loading state
|
||||
- [ ] Create `app/error.tsx` for error boundary
|
||||
- [ ] Create `app/not-found.tsx` for 404
|
||||
- [ ] Move CSS to `app/globals.css`
|
||||
- [ ] Test homepage loads
|
||||
- [ ] Verify navigation works
|
||||
- [ ] Check loading states
|
||||
- [ ] Test error boundaries
|
||||
|
||||
---
|
||||
|
||||
### Task 12.2: Park Pages (8 hours)
|
||||
|
||||
#### Park Listing Page
|
||||
|
||||
`app/parks/page.tsx` (Server Component):
|
||||
|
||||
```typescript
|
||||
import { env } from '@/lib/env';
|
||||
import { ParksList } from '@/components/parks/ParksList';
|
||||
import { ParkFilters } from '@/components/parks/ParkFilters';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Theme Parks - ThrillWiki',
|
||||
description: 'Browse theme parks from around the world',
|
||||
};
|
||||
|
||||
export default async function ParksPage({
|
||||
searchParams,
|
||||
}: {
|
||||
searchParams: { [key: string]: string | undefined };
|
||||
}) {
|
||||
const params = new URLSearchParams(searchParams as any);
|
||||
const parks = await fetch(
|
||||
`${env.NEXT_PUBLIC_DJANGO_API_URL}/parks/?${params}`,
|
||||
{ next: { revalidate: 300 } } // Cache for 5 minutes
|
||||
).then(r => r.json());
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Theme Parks</h1>
|
||||
<ParkFilters /> {/* Client Component */}
|
||||
<ParksList parks={parks} /> {/* Can be Server Component */}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Park Detail Page
|
||||
|
||||
`app/parks/[parkSlug]/page.tsx` (Server Component):
|
||||
|
||||
```typescript
|
||||
import { env } from '@/lib/env';
|
||||
import { ParkDetail } from '@/components/parks/ParkDetail';
|
||||
import { notFound } from 'next/navigation';
|
||||
|
||||
export async function generateStaticParams() {
|
||||
// Pre-render top 100 parks
|
||||
const parks = await fetch(`${env.NEXT_PUBLIC_DJANGO_API_URL}/parks/?page_size=100`)
|
||||
.then(r => r.json());
|
||||
return parks.results.map((park: any) => ({
|
||||
parkSlug: park.slug,
|
||||
}));
|
||||
}
|
||||
|
||||
export async function generateMetadata({ params }: { params: { parkSlug: string } }) {
|
||||
const park = await fetch(`${env.NEXT_PUBLIC_DJANGO_API_URL}/parks/${params.parkSlug}/`)
|
||||
.then(r => r.json());
|
||||
|
||||
return {
|
||||
title: `${park.name} - ThrillWiki`,
|
||||
description: park.description,
|
||||
};
|
||||
}
|
||||
|
||||
export default async function ParkDetailPage({
|
||||
params
|
||||
}: {
|
||||
params: { parkSlug: string }
|
||||
}) {
|
||||
const park = await fetch(
|
||||
`${env.NEXT_PUBLIC_DJANGO_API_URL}/parks/${params.parkSlug}/`,
|
||||
{ next: { revalidate: 3600 } } // Cache for 1 hour
|
||||
).then(r => r.json())
|
||||
.catch(() => notFound());
|
||||
|
||||
return <ParkDetail park={park} />;
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist
|
||||
- [ ] Create `app/parks/page.tsx`
|
||||
- [ ] Create `app/parks/[parkSlug]/page.tsx`
|
||||
- [ ] Create `app/parks/[parkSlug]/rides/page.tsx`
|
||||
- [ ] Create `app/owners/[ownerSlug]/parks/page.tsx`
|
||||
- [ ] Create loading.tsx for each route
|
||||
- [ ] Implement generateStaticParams for ISR
|
||||
- [ ] Implement generateMetadata for SEO
|
||||
- [ ] Test all park URLs work
|
||||
- [ ] Verify filtering works
|
||||
- [ ] Test pagination
|
||||
|
||||
---
|
||||
|
||||
### Task 12.3: Ride Pages (8 hours)
|
||||
|
||||
#### Ride Listing Page
|
||||
|
||||
`app/rides/page.tsx` (Server Component with caching)
|
||||
|
||||
#### Ride Detail Page
|
||||
|
||||
`app/rides/[rideSlug]/page.tsx` (Server Component)
|
||||
|
||||
#### Ride Model Pages
|
||||
|
||||
`app/ride-models/[modelSlug]/page.tsx` (Server Component)
|
||||
|
||||
#### Checklist
|
||||
- [ ] Create `app/rides/page.tsx`
|
||||
- [ ] Create `app/rides/[rideSlug]/page.tsx`
|
||||
- [ ] Create `app/rides/[rideSlug]/reviews/page.tsx`
|
||||
- [ ] Create `app/ride-models/[modelSlug]/page.tsx`
|
||||
- [ ] Create `app/ride-models/[modelSlug]/rides/page.tsx`
|
||||
- [ ] Create loading states
|
||||
- [ ] Implement metadata
|
||||
- [ ] Test all ride URLs
|
||||
- [ ] Verify reviews work
|
||||
|
||||
---
|
||||
|
||||
### Task 12.4: Company Pages (8 hours)
|
||||
|
||||
Convert manufacturer, owner, and designer pages to App Router.
|
||||
|
||||
#### Checklist
|
||||
- [ ] Create `app/manufacturers/page.tsx`
|
||||
- [ ] Create `app/manufacturers/[manufacturerSlug]/page.tsx`
|
||||
- [ ] Create `app/manufacturers/[manufacturerSlug]/rides/page.tsx`
|
||||
- [ ] Create `app/owners/page.tsx`
|
||||
- [ ] Create `app/owners/[ownerSlug]/page.tsx`
|
||||
- [ ] Create `app/designers/page.tsx`
|
||||
- [ ] Create `app/designers/[designerSlug]/page.tsx`
|
||||
- [ ] Test all company URLs
|
||||
- [ ] Verify filtering works
|
||||
|
||||
---
|
||||
|
||||
### Task 12.5: User Pages (6 hours)
|
||||
|
||||
These pages need authentication and user-specific data.
|
||||
|
||||
#### Profile Page
|
||||
|
||||
`app/profile/page.tsx` (Server Component with auth check):
|
||||
|
||||
```typescript
|
||||
import { redirect } from 'next/navigation';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { ProfileView } from '@/components/profile/ProfileView';
|
||||
|
||||
export default async function ProfilePage() {
|
||||
const session = await getServerSession();
|
||||
|
||||
if (!session) {
|
||||
redirect('/auth/login');
|
||||
}
|
||||
|
||||
const user = await fetch(
|
||||
`${env.NEXT_PUBLIC_DJANGO_API_URL}/users/me/`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${session.accessToken}` },
|
||||
cache: 'no-store' // Don't cache user-specific data
|
||||
}
|
||||
).then(r => r.json());
|
||||
|
||||
return <ProfileView user={user} />;
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist
|
||||
- [ ] Create `app/profile/page.tsx`
|
||||
- [ ] Create `app/profile/settings/page.tsx`
|
||||
- [ ] Create `app/profile/lists/page.tsx`
|
||||
- [ ] Implement authentication checks
|
||||
- [ ] Disable caching for user data
|
||||
- [ ] Test profile loads
|
||||
- [ ] Test settings work
|
||||
- [ ] Test list management
|
||||
|
||||
---
|
||||
|
||||
### Task 12.6: Admin & Moderation Pages (6 hours)
|
||||
|
||||
Admin pages require role checks and real-time updates.
|
||||
|
||||
#### Moderation Queue
|
||||
|
||||
`app/admin/moderation/page.tsx` (Server Component):
|
||||
|
||||
```typescript
|
||||
import { redirect } from 'next/navigation';
|
||||
import { getServerSession } from 'next-auth';
|
||||
import { ModerationQueue } from '@/components/moderation/ModerationQueue';
|
||||
|
||||
export default async function ModerationPage() {
|
||||
const session = await getServerSession();
|
||||
|
||||
if (!session || session.user.role !== 'moderator') {
|
||||
redirect('/');
|
||||
}
|
||||
|
||||
// Fetch submissions server-side
|
||||
const submissions = await fetch(
|
||||
`${env.NEXT_PUBLIC_DJANGO_API_URL}/moderation/queue/`,
|
||||
{
|
||||
headers: { Authorization: `Bearer ${session.accessToken}` },
|
||||
cache: 'no-store'
|
||||
}
|
||||
).then(r => r.json());
|
||||
|
||||
return <ModerationQueue initialSubmissions={submissions} />;
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist
|
||||
- [ ] Create `app/admin/page.tsx`
|
||||
- [ ] Create `app/admin/moderation/page.tsx`
|
||||
- [ ] Implement role-based access
|
||||
- [ ] Add server-side permission checks
|
||||
- [ ] Test moderator access
|
||||
- [ ] Test admin dashboard
|
||||
- [ ] Verify Sacred Pipeline
|
||||
|
||||
---
|
||||
|
||||
### Task 12.7: Authentication Pages (4 hours)
|
||||
|
||||
#### Login Page
|
||||
|
||||
`app/auth/login/page.tsx` (Client Component - needs form state):
|
||||
|
||||
```typescript
|
||||
'use client';
|
||||
|
||||
import { LoginForm } from '@/components/auth/LoginForm';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { useSession } from 'next-auth/react';
|
||||
|
||||
export default function LoginPage() {
|
||||
const { data: session } = useSession();
|
||||
|
||||
if (session) {
|
||||
redirect('/profile');
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Login</h1>
|
||||
<LoginForm />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist
|
||||
- [ ] Create `app/auth/login/page.tsx`
|
||||
- [ ] Create `app/auth/register/page.tsx`
|
||||
- [ ] Create `app/auth/callback/page.tsx`
|
||||
- [ ] Create `app/auth/reset-password/page.tsx`
|
||||
- [ ] Test email/password login
|
||||
- [ ] Test OAuth login (Google, GitHub)
|
||||
- [ ] Test registration
|
||||
- [ ] Test password reset
|
||||
|
||||
---
|
||||
|
||||
### Task 12.8: Search & Contact Pages (3 hours)
|
||||
|
||||
#### Search Page
|
||||
|
||||
`app/search/page.tsx` (Client Component - needs interactive search):
|
||||
|
||||
```typescript
|
||||
'use client';
|
||||
|
||||
import { useSearchParams } from 'next/navigation';
|
||||
import { SearchResults } from '@/components/search/SearchResults';
|
||||
import { SearchFilters } from '@/components/search/SearchFilters';
|
||||
|
||||
export default function SearchPage() {
|
||||
const searchParams = useSearchParams();
|
||||
const query = searchParams.get('q');
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h1>Search Results</h1>
|
||||
<SearchFilters />
|
||||
<SearchResults query={query} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Contact Page
|
||||
|
||||
`app/contact/page.tsx` (Server Component):
|
||||
|
||||
```typescript
|
||||
import { ContactForm } from '@/components/contact/ContactForm';
|
||||
|
||||
export const metadata = {
|
||||
title: 'Contact Us - ThrillWiki',
|
||||
};
|
||||
|
||||
export default function ContactPage() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Contact Us</h1>
|
||||
<ContactForm />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
#### Checklist
|
||||
- [ ] Create `app/search/page.tsx`
|
||||
- [ ] Create `app/contact/page.tsx`
|
||||
- [ ] Test search functionality
|
||||
- [ ] Test contact form submission
|
||||
- [ ] Verify form validation
|
||||
|
||||
---
|
||||
|
||||
### Task 12.9: Component Migration (6 hours)
|
||||
|
||||
Convert React components to work with Next.js.
|
||||
|
||||
#### Server Components (Default)
|
||||
Components that only display data and don't need interactivity:
|
||||
- Lists (ParksL, RidesList)
|
||||
- Detail views (ParkDetail, RideDetail)
|
||||
- Static content
|
||||
|
||||
#### Client Components ('use client')
|
||||
Components that need interactivity:
|
||||
- Forms (LoginForm, SubmissionForm)
|
||||
- Interactive filters
|
||||
- Modals and dialogs
|
||||
- Components using useState, useEffect, etc.
|
||||
|
||||
#### Checklist
|
||||
- [ ] Identify all components using Supabase
|
||||
- [ ] Determine Server vs Client Component
|
||||
- [ ] Add 'use client' where needed
|
||||
- [ ] Replace Supabase with service calls
|
||||
- [ ] Test all components render
|
||||
- [ ] Verify interactions work
|
||||
- [ ] Check no hydration errors
|
||||
|
||||
---
|
||||
|
||||
### Task 12.10: Routing & Navigation (4 hours)
|
||||
|
||||
Update all navigation to use Next.js routing.
|
||||
|
||||
#### Replace React Router
|
||||
|
||||
```typescript
|
||||
// OLD (React Router)
|
||||
import { Link, useNavigate } from 'react-router-dom';
|
||||
|
||||
// NEW (Next.js)
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
```
|
||||
|
||||
#### Update All Links
|
||||
|
||||
```typescript
|
||||
// OLD
|
||||
<Link to="/parks">Parks</Link>
|
||||
|
||||
// NEW
|
||||
<Link href="/parks">Parks</Link>
|
||||
```
|
||||
|
||||
#### Checklist
|
||||
- [ ] Replace all React Router imports
|
||||
- [ ] Update all <Link> components
|
||||
- [ ] Update all navigate() calls to router.push()
|
||||
- [ ] Update all useParams to use params prop
|
||||
- [ ] Update all useSearchParams
|
||||
- [ ] Test navigation works
|
||||
- [ ] Test browser back button
|
||||
- [ ] Test deep linking
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Success Criteria
|
||||
|
||||
### Zero React Router Usage
|
||||
- [ ] No `react-router-dom` imports remain
|
||||
- [ ] All navigation uses Next.js Link/router
|
||||
- [ ] No old React pages in `src/pages/` (move to `app/`)
|
||||
|
||||
### Zero Supabase Usage
|
||||
- [ ] `grep -r "supabase\." app/ components/ lib/ --include="*.ts" --include="*.tsx"` returns 0
|
||||
- [ ] `grep -r "from '@/lib/supabaseClient'"` returns 0
|
||||
- [ ] `grep -r "from '@supabase/supabase-js'"` returns 0
|
||||
|
||||
### All URLs Preserved
|
||||
- [ ] `/parks` works
|
||||
- [ ] `/parks/[parkSlug]` works
|
||||
- [ ] `/parks/[parkSlug]/rides` works
|
||||
- [ ] `/owners/[ownerSlug]/parks` works
|
||||
- [ ] `/rides` works
|
||||
- [ ] `/rides/[rideSlug]` works
|
||||
- [ ] `/ride-models/[modelSlug]` works
|
||||
- [ ] `/manufacturers/[manufacturerSlug]` works
|
||||
- [ ] `/manufacturers/[manufacturerSlug]/rides` works
|
||||
- [ ] All other URLs work
|
||||
|
||||
### All Pages Load
|
||||
- [ ] Homepage loads (SSR)
|
||||
- [ ] All park pages load
|
||||
- [ ] All ride pages load
|
||||
- [ ] All company pages load
|
||||
- [ ] Profile page loads (auth check)
|
||||
- [ ] Settings page loads (auth check)
|
||||
- [ ] Admin dashboard loads (role check)
|
||||
- [ ] Moderation queue loads (role check)
|
||||
- [ ] Search page loads
|
||||
- [ ] Contact page loads
|
||||
- [ ] Auth pages load
|
||||
|
||||
### All Features Work
|
||||
- [ ] Can browse entities
|
||||
- [ ] Can view entity details
|
||||
- [ ] Can filter/sort
|
||||
- [ ] Can submit content (creates submission)
|
||||
- [ ] Can moderate content
|
||||
- [ ] Can write reviews
|
||||
- [ ] Can add ride credits
|
||||
- [ ] Can manage top lists
|
||||
- [ ] Can upload photos
|
||||
- [ ] Can search
|
||||
- [ ] Authentication works
|
||||
- [ ] Server-side rendering works
|
||||
- [ ] Client-side navigation works
|
||||
|
||||
### Next.js Specific
|
||||
- [ ] Server Components render on server
|
||||
- [ ] Client Components work in browser
|
||||
- [ ] No hydration errors
|
||||
- [ ] Loading states display
|
||||
- [ ] Error boundaries catch errors
|
||||
- [ ] Metadata API generates correct tags
|
||||
- [ ] ISR/SSR configured correctly
|
||||
- [ ] Build succeeds without errors
|
||||
|
||||
### Sacred Pipeline Intact
|
||||
- [ ] All entity changes go through submissions
|
||||
- [ ] Moderation queue receives submissions
|
||||
- [ ] Approval creates entities/updates
|
||||
- [ ] Rejection saves reason
|
||||
- [ ] No pipeline bypasses
|
||||
|
||||
---
|
||||
|
||||
## 📝 Implementation Strategy
|
||||
|
||||
### 1. Start with Entity Pages (Most Critical)
|
||||
Focus on parks, rides, companies first since they're core functionality.
|
||||
|
||||
### 2. Then User Pages
|
||||
Profile and settings are user-facing and important.
|
||||
|
||||
### 3. Then Admin Pages
|
||||
Moderation queue and admin dashboard.
|
||||
|
||||
### 4. Then Misc Pages
|
||||
Homepage, search, contact, etc.
|
||||
|
||||
### 5. Component Sweep
|
||||
Find any remaining components with Supabase calls.
|
||||
|
||||
### 6. Final Search
|
||||
Run grep commands to find ANY remaining Supabase usage.
|
||||
|
||||
---
|
||||
|
||||
## 🚨 Critical Rules
|
||||
|
||||
### DO NOT
|
||||
- ❌ Skip any page
|
||||
- ❌ Leave any `supabase.` calls
|
||||
- ❌ Assume a page works without testing it
|
||||
- ❌ Move to Phase 13 until grep returns 0 results
|
||||
|
||||
### MUST DO
|
||||
- ✅ Test EVERY page you touch
|
||||
- ✅ Verify EVERY interaction works
|
||||
- ✅ Check console for errors
|
||||
- ✅ Verify Sacred Pipeline intact
|
||||
- ✅ Document any issues found
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Related Documentation
|
||||
|
||||
Refer back to previous phases for service usage examples:
|
||||
- Phase 1: Foundation (BaseService pattern)
|
||||
- Phase 4: Entity Services (parks, rides, companies)
|
||||
- Phase 5: Reviews & Social
|
||||
- Phase 6: Moderation & Admin
|
||||
- Phase 7: Media & Photos
|
||||
- Phase 8: Search
|
||||
- Phase 9: Timeline & History
|
||||
- Phase 10: Users & Profiles
|
||||
- Phase 11: Contact & Reports
|
||||
|
||||
---
|
||||
|
||||
## ⏭️ Next Phase
|
||||
|
||||
Once this phase is complete, proceed to [Phase 13: Next.js Optimization](./PHASE_13_NEXTJS_OPTIMIZATION.md)
|
||||
|
||||
---
|
||||
|
||||
## 🔗 Related Documentation
|
||||
|
||||
- [Next.js 15 Migration Guide](./NEXTJS_15_MIGRATION_GUIDE.md)
|
||||
- [Environment Variables Guide](./ENVIRONMENT_VARIABLES.md)
|
||||
- [Phase 1: Foundation](./PHASE_01_FOUNDATION.md)
|
||||
- [Phase 13: Next.js Optimization](./PHASE_13_NEXTJS_OPTIMIZATION.md)
|
||||
- Next.js App Router: https://nextjs.org/docs/app
|
||||
- Server Components: https://nextjs.org/docs/app/building-your-application/rendering/server-components
|
||||
|
||||
---
|
||||
|
||||
**Document Version:** 2.0
|
||||
**Last Updated:** November 9, 2025
|
||||
**Changes:** Converted to Next.js 15 App Router migration
|
||||
Reference in New Issue
Block a user