# Plan: Admin Dashboard Auth + CRUD + Enhancements ## TL;DR Add password authentication to the admin dashboard, enable full CRUD for personas/pricing, and add useful admin features like order analytics and configurator settings management. ## Phase 1: Admin Authentication (Database-backed with Prisma + SQLite) ### Steps 1. **Setup Prisma + SQLite** - Install `prisma` and `@prisma/client` - Create `prisma/schema.prisma` with SQLite provider - Models: `AdminUser` (id, username, passwordHash, createdAt), `AppSettings` (key, value) - Run `npx prisma db push` to create the database - Create `src/lib/prisma.ts` — singleton Prisma client 2. **Create seed script** `prisma/seed.ts` - Creates default admin user with bcrypt-hashed password - Generates and stores JWT secret in `AppSettings` table - Run with `npx prisma db seed` 3. **Create admin auth API routes** - `src/app/api/admin/login/route.ts` — POST, accepts `{ username, password }`, verifies bcrypt hash from DB, returns JWT in httpOnly cookie (JWT secret from DB) - `src/app/api/admin/verify/route.ts` — GET, checks JWT cookie validity - `src/app/api/admin/logout/route.ts` — POST, clears auth cookie - `src/app/api/admin/change-password/route.ts` — POST, accepts `{ currentPassword, newPassword }`, updates hash in DB 4. **Create admin middleware** `src/middleware.ts` - Protects all `/admin/*` routes (except `/admin/login/`) - Checks for valid JWT cookie, redirects to `/admin/login/` if missing/invalid - Note: middleware can't use Prisma directly (edge runtime), so JWT secret needs to be in env OR verify via API call 5. **Create admin login page** `src/app/admin/login/page.tsx` - Username + password form (styled to match existing admin design) - Calls login API, redirects to `/admin/` on success - Shows error on wrong credentials 6. **Add JWT_SECRET to .env.local** (only this one — password is in DB) - Alternative: store JWT secret in DB and load at startup into a module-level cache ### Dependencies to install - `prisma` (dev), `@prisma/client`, `bcryptjs`, `@types/bcryptjs` (dev), `jose` ## Phase 2: Full CRUD for Pricing Items + Personas ### Steps (depends on Phase 1) 6. **Add/Remove pricing items in admin** — Update `src/app/admin/page.tsx` - "Add Item" button with fields: id (auto-slug from label), label, price - Delete button per row (with confirmation) - Update `usePricingStore` to support `addItem()` and `removeItem()` actions 7. **Persona management section** — New section in admin page - List current personas with edit capability (label, description, colors) - Add new persona form - Delete persona button - Create `usePersonaStore` or extend `usePricingStore` to manage persona definitions - Sync persona list with ConfigPanel's `PERSONA_OPTIONS` (currently hardcoded) ## Phase 3: Additional Admin Features ### Steps (parallel with Phase 2) 8. **Orders dashboard section** — New section in admin page - Show orders from Stripe API (list recent payments) - Display: order ID, customer email, amount, status, date - New API route `src/app/api/admin/orders/route.ts` to fetch from Stripe 9. **Analytics overview cards** at top of admin page - Total revenue (from Stripe) - Number of orders - Most popular persona - Most popular color 10. **Configurator settings** section - Edit default color (`#96a2b6`) - Toggle available color options - Set min/max price boundaries 11. **Logout button** in admin header ## Relevant Files - `src/app/admin/page.tsx` — Main admin dashboard (add CRUD UI, analytics) - `src/app/admin/login/page.tsx` — New login page - `src/app/api/admin/login/route.ts` — New auth API - `src/app/api/admin/verify/route.ts` — New verify API - `src/app/api/admin/orders/route.ts` — New orders API - `src/middleware.ts` — New, protects admin routes - `src/lib/prisma.ts` — New, Prisma client singleton - `prisma/schema.prisma` — New, database schema (AdminUser, AppSettings) - `prisma/seed.ts` — New, seeds default admin user - `src/store/usePricingStore.ts` — Add `addItem()`, `removeItem()` actions - `src/components/ConfigPanel.tsx` — Persona options currently hardcoded (PERSONA_OPTIONS const) - `.env.local` — Add ADMIN_PASSWORD, ADMIN_JWT_SECRET ## Verification 1. Visit `/admin/` without login → redirected to `/admin/login/` 2. Enter wrong password → error message shown 3. Enter correct password → redirected to `/admin/` 4. Add a pricing item → appears in configurator pricing breakdown 5. Remove a pricing item → disappears from pricing 6. Edit persona → reflected in ConfigPanel 7. Orders section shows real Stripe payment data 8. Refresh admin page → still logged in (cookie persists) 9. Run `npx vitest run` → all existing tests pass ## Decisions - **Database: Prisma + SQLite** — file-based, no external server needed, real ORM - Admin password stored as bcrypt hash in DB (not in env vars) - JWT secret stored in AppSettings table in DB - JWT in httpOnly cookie — secure, no localStorage tokens - jose library for JWT — lightweight, edge-compatible (works in Next.js middleware) - Personas need to move from hardcoded array to store-driven — breaking change in ConfigPanel - Stripe orders fetched via Stripe API directly — no local DB needed for orders ## Further Considerations 1. **Persona storage**: Currently hardcoded in ConfigPanel. Moving to a store means ConfigPanel reads from store dynamically. This is required for admin CRUD to work. **Recommended: create persona store with localStorage persistence (same pattern as pricing store)** 2. **Stripe orders vs local orders**: Currently orders only exist client-side. To show in admin, we fetch from Stripe's payment intents list. **Recommended: use Stripe API directly, no local DB needed** 3. **Multi-admin support**: Currently single password. If needed later, can upgrade to NextAuth with credentials provider. **Recommended: start simple, upgrade if needed**