A production-ready Next.js 15 App Router frontend for AskPip - an AI-powered how-to guide platform with interactive chat support.
- Step-by-Step Guides: Clear, illustrated instructions generated from natural language prompts
- Interactive Chat: Real-time chat assistance contextualized to the current guide
- Smart Organization: Pin important guides, auto-expire old ones after 15 days
- Beautiful UI: Dark mode by default, Tailwind CSS, Framer Motion animations
- Accessible: WCAG 2.1 AA compliant, full keyboard navigation, screen reader support
- Responsive: Desktop split-view, mobile drawer, optimized for all screen sizes
- Authentication: Clerk integration with optional anonymous usage
- Framework: Next.js 15 (App Router, JavaScript)
- Styling: Tailwind CSS 4
- Animation: Framer Motion
- Auth: Clerk
- Database: Supabase (client setup ready)
- State: Zustand
- Validation: Zod
- Icons: Lucide React
- Theme: next-themes
- Install dependencies:
npm install- Set up environment variables:
The
.env.localfile should already be configured with your API keys. Verify it contains:
# App
NEXT_PUBLIC_APP_NAME=AskPip
# Clerk Authentication
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_...
CLERK_SECRET_KEY=sk_...
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://xxxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJh...
SUPABASE_SERVICE_ROLE_KEY=eyJh...
# Images
NEXT_PUBLIC_IMAGES_BASE=/pip- Run the development server:
npm run devOpen http://localhost:3000 to view the app.
src/
├── app/ # Next.js App Router pages
│ ├── api/ # API route stubs (mock data)
│ │ ├── generateGuide/ # POST - Generate new guide
│ │ ├── guides/ # GET - List guides
│ │ │ └── [id]/ # GET/DELETE - Single guide
│ │ ├── chat/ # POST - SSE chat stream
│ │ └── pin/ # POST - Toggle pin
│ ├── guide/[id]/ # Guide detail page
│ ├── library/ # Library page
│ ├── layout.js # Root layout with providers
│ ├── page.js # Landing page
│ └── globals.css # Global styles
├── components/ # React components
│ ├── NavBar.js # Top navigation
│ ├── LeftRail.js # Collapsible side navigation
│ ├── GuideCard.js # Guide preview card
│ ├── GuideHeader.js # Guide metadata header
│ ├── StepItem.js # Individual guide step
│ ├── PipBadge.js # Character pose badge
│ ├── ProgressBar.js # Step completion tracker
│ ├── ChatPanel.js # Chat interface container
│ ├── MessageList.js # Chat message display
│ ├── Composer.js # Chat input
│ ├── Skeletons.js # Loading states
│ └── Toaster.js # Toast notifications
├── lib/ # Utility functions
│ ├── api.js # API client functions
│ ├── supabase.js # Supabase client setup
│ ├── hashing.js # Deterministic ID generation
│ └── ttl.js # 15-day TTL logic
├── store/ # Zustand state management
│ ├── useGuideStore.js # Guide data & localStorage
│ ├── useChatStore.js # Chat messages & persistence
│ └── useUIStore.js # UI state (rail, drawer)
├── schemas/ # Zod validation schemas
│ └── guide.js # Guide/Step/Message schemas
├── types/ # JSDoc type definitions
│ └── index.js # TypeScript-style JSDoc types
└── middleware.js # Clerk auth middleware
public/
└── pip/ # Pip character poses (SVG)
├── point.svg
├── thumbs.svg
├── think.svg
└── celebrate.svg
All API routes currently return mock data. Replace with Supabase Edge Functions:
- Input:
{ prompt: string } - Output:
{ id: string, guide: Guide } - TODO: Call Gemini Flash → Generate steps → Queue Flux image jobs
- Output:
{ guides: Guide[] } - TODO: Query Supabase with RLS filtered by user
- Output:
{ guide: Guide } - TODO: Query Supabase with RLS
- Output:
{ ok: boolean } - TODO: Delete from Supabase + schedule image cleanup
- Input:
{ guideId: string, message: string } - Output: SSE stream
- TODO: Call Gemini Flash with guide context
- Input:
{ id: string, pinned: boolean } - Output:
{ ok: boolean } - TODO: Update Supabase guides table
- Anonymous Users: Guides stored in
localStorageonly, expire after page refresh - Authenticated Users: Same localStorage for now; will sync to Supabase once backend is ready
- TTL Logic: Client-side filter removes guides > 15 days old (pinned guides exempt)
- Primary: Blue (
#3b82f6) - Accent: Purple (
#8b5cf6) - Muted: Gray tones
- Surface: Dark backgrounds with layered depth
- Font: Inter (system fallback)
- Scale: 8pt spacing grid
- Duration: 150-250ms
- Easing: ease-in-out
- Respects:
prefers-reduced-motion
- ✅ WCAG 2.1 AA compliant color contrast (≥4.5:1)
- ✅ Full keyboard navigation (Tab, Enter, Escape)
- ✅ Focus visible indicators on all interactive elements
- ✅ ARIA labels and live regions for dynamic content
- ✅ Semantic HTML and heading hierarchy
- ✅ Alt text for all images
npm run lintnpm run test:e2enpm run formatnpm run build
npm startvercelEnvironment variables will need to be configured in Vercel dashboard.
- Replace
/api/generateGuidewith Supabase Edge Function calling Gemini Flash - Replace
/api/chatSSE with Gemini Flash streaming - Wire up Supabase RLS for guides/steps/messages tables
- Implement image generation queue (Flux Pro 1.1)
- Add server-side TTL purge job (replace client-side filtering)
- Connect Clerk JWT to Supabase auth for RLS
- Update
lib/api.jsendpoints to point to Edge Functions - Replace localStorage persistence with Supabase queries
npm run dev- Start development servernpm run build- Build for productionnpm run start- Start production servernpm run lint- Run ESLintnpm run format- Format with Prettiernpm run test:e2e- Run Playwright tests
This is a production-ready frontend scaffold. When integrating with the backend:
- Update API endpoints in
lib/api.js - Add Supabase Edge Function URLs
- Configure RLS policies
- Test authentication flow
- Verify image uploads work
- Test TTL cleanup job
MIT
Run npm install to ensure all dependencies are installed.
Verify Clerk API keys are correctly set in .env.local.
Ensure Tailwind CSS is properly configured and globals.css is imported.
Check that /public/pip/ contains all 4 SVG files (point, thumbs, think, celebrate).
Built with ❤️ for seamless learning experiences.