# Phase 1 — Foundation Scaffold the project, wire up auth, build the app shell, and establish the design system. ## Checklist - [ ] Next.js 15 project init with App Router + TypeScript - [ ] Tailwind CSS 4 configuration - [ ] shadcn/ui setup (install CLI, add base components) - [ ] TypeScript types from API DTOs (all request/response shapes) - [ ] API client layer (typed fetch wrappers, token injection, error handling) - [ ] Auth flows: Login, Register, Verify Email, Forgot/Reset Password - [ ] Auth middleware (route protection, token cookie) - [ ] App shell: sidebar nav + top bar - [ ] Design system: color tokens matching mobile app - [ ] Theme switcher (11 themes, persisted to localStorage) ## 1. Project Scaffold ```bash npx create-next-app@latest honeyDueAPI-Web --typescript --tailwind --eslint --app --src-dir cd honeyDueAPI-Web npx shadcn@latest init ``` Install core dependencies: ```bash npm install @tanstack/react-query zustand react-hook-form @hookform/resolvers zod npm install lucide-react recharts @dnd-kit/core @dnd-kit/sortable npm install -D vitest @playwright/test ``` ## 2. TypeScript Types Generate TypeScript types matching the Go API DTOs. Source from: - `honeyDueAPI-go/internal/dto/requests/` — request shapes - `honeyDueAPI-go/internal/dto/responses/` — response shapes - `honeyDueAPI-go/internal/models/` — entity shapes Key types to define in `src/lib/types/`: ``` types/ ├── api.ts # ApiResult, PaginatedResponse, ErrorResponse ├── auth.ts # LoginRequest, RegisterRequest, UserResponse, TokenResponse ├── residence.ts # Residence, ResidenceDetail, MyResidencesResponse, CreateResidenceRequest ├── task.ts # Task, TaskDetail, TaskColumnsResponse, CreateTaskRequest, TaskCompletionRequest ├── contractor.ts # Contractor, ContractorDetail, CreateContractorRequest ├── document.ts # Document, DocumentDetail, CreateDocumentRequest ├── subscription.ts # SubscriptionStatus, FeatureBenefit, UpgradeTrigger ├── lookups.ts # TaskCategory, TaskPriority, TaskFrequency, ContractorSpecialty └── notification.ts # NotificationPreference, Notification ``` ## 3. API Client Layer Create typed fetch wrappers in `src/lib/api/`: ``` api/ ├── client.ts # Base fetch wrapper (token injection, error handling, base URL) ├── auth.ts # login(), register(), forgotPassword(), resetPassword() ├── residences.ts # getResidences(), getResidence(), createResidence(), updateResidence(), deleteResidence() ├── tasks.ts # getTasks(), getTasksByResidence(), createTask(), updateTask(), completeTask(), etc. ├── contractors.ts # getContractors(), getContractor(), createContractor(), etc. ├── documents.ts # getDocuments(), getDocument(), createDocument(), uploadFile(), etc. ├── lookups.ts # getStaticData(), getUpgradeTriggers() ├── subscription.ts # getSubscriptionStatus(), etc. └── notifications.ts # getPreferences(), updatePreference(), etc. ``` **Base client pattern:** ```typescript // src/lib/api/client.ts const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'https://honeyDue.treytartt.com/api'; async function apiFetch( path: string, options: RequestInit = {} ): Promise { const res = await fetch(`${API_BASE_URL}${path}`, { ...options, credentials: 'include', // Send httpOnly cookie headers: { 'Content-Type': 'application/json', ...options.headers, }, }); if (!res.ok) { const error = await res.json().catch(() => ({ detail: 'Unknown error' })); throw new ApiError(res.status, error.detail || error.message); } return res.json(); } ``` ## 4. Auth Flows ### Pages | Route | Screen | Components | |-------|--------|------------| | `/login` | Login form | Email, password, "Forgot password?" link, social sign-in buttons | | `/register` | Registration form | First name, last name, email, password, confirm password | | `/verify-email` | Email verification | Code input, resend button | | `/forgot-password` | Forgot password | Email input, submit | | `/reset-password` | Reset password | New password, confirm, token from URL | ### Auth Token Strategy ``` Login → Server returns token → API route stores token in httpOnly cookie → Client redirects to /app ↓ All subsequent requests include cookie ↓ Next.js middleware reads cookie for route protection ``` - Token format: `Token ` (Django-compatible, same as mobile) - Cookie: `httpOnly`, `SameSite=Strict`, `Secure` in production - Next.js middleware in `src/middleware.ts` checks cookie existence for protected routes ### Auth Store (Zustand) ```typescript // src/stores/auth.ts interface AuthState { user: UserResponse | null; isAuthenticated: boolean; isLoading: boolean; login: (email: string, password: string) => Promise; register: (data: RegisterRequest) => Promise; logout: () => Promise; fetchUser: () => Promise; } ``` ## 5. App Shell ### Layout Structure ``` ┌─────────────────────────────────────────────────────┐ │ Top Bar: Logo | Search (optional) | Profile Menu │ ├──────────┬──────────────────────────────────────────┤ │ │ │ │ Sidebar │ Main Content │ │ │ │ │ 🏠 Home │ │ │ 🏘 Resid │ │ │ ✅ Tasks │ │ │ 👷 Contr │ │ │ 📄 Docs │ │ │ │ │ │ ──────── │ │ │ ⚙ Setti │ │ │ │ │ ├──────────┴──────────────────────────────────────────┤ │ (mobile: bottom tab bar instead of sidebar) │ └─────────────────────────────────────────────────────┘ ``` - **Desktop (≥1024px)**: Collapsible sidebar + top bar - **Tablet (768-1023px)**: Collapsed sidebar (icons only) + top bar - **Mobile (<768px)**: Bottom tab bar (matches iOS app), no sidebar ### Navigation Items | Icon | Label | Route | |------|-------|-------| | Home | Home | `/app` | | Building | Residences | `/app/residences` | | CheckSquare | Tasks | `/app/tasks` | | HardHat | Contractors | `/app/contractors` | | FileText | Documents | `/app/documents` | | Settings | Settings | `/app/settings` | ## 6. Design System ### Color Tokens Map the mobile app's color palette to CSS custom properties and Tailwind config: ```css /* src/styles/theme.css */ :root { /* Default theme (matches iOS appPrimary, etc.) */ --color-primary: #07A0C3; /* BlueGreen */ --color-secondary: #0055A5; /* Cerulean */ --color-accent: #F5A623; /* BrightAmber */ --color-error: #DD1C1A; /* PrimaryScarlet */ --color-bg-primary: #FFF1D0; /* Cream */ --color-bg-secondary: #F0F4F8; /* Blue-gray */ --color-text-primary: #1A1A1A; --color-text-secondary: #6B7280; --color-text-on-primary: #FFFFFF; } [data-theme="dark"] { --color-bg-primary: #0A1929; --color-bg-secondary: #1A2A3A; --color-text-primary: #F0F0F0; --color-text-secondary: #9CA3AF; } ``` ### 11 Themes Match the mobile app's theme system: | Theme | Primary | Secondary | |-------|---------|-----------| | Default | #07A0C3 | #0055A5 | | Teal | TBD | TBD | | Ocean | TBD | TBD | | Forest | TBD | TBD | | Sunset | TBD | TBD | | Monochrome | TBD | TBD | | Lavender | TBD | TBD | | Crimson | TBD | TBD | | Midnight | TBD | TBD | | Desert | TBD | TBD | | Mint | TBD | TBD | Theme values sourced from `HoneyDueKMM/composeApp/src/commonMain/.../ui/theme/ThemeColors.kt`. ### Spacing ```css --spacing-xs: 4px; --spacing-sm: 8px; --spacing-md: 12px; --spacing-lg: 16px; --spacing-xl: 24px; ``` ## 7. TanStack Query Setup ```typescript // src/lib/hooks/useResidences.ts export function useResidences() { return useQuery({ queryKey: ['residences'], queryFn: () => api.residences.getResidences(), staleTime: 60 * 60 * 1000, // 1 hour (matches mobile cache timeout) refetchOnWindowFocus: true, }); } ``` ## 8. Lookups Initialization Match the mobile pattern — after login, fetch `/api/static_data/` and `/api/upgrade-triggers/`: ```typescript // After successful login await queryClient.prefetchQuery({ queryKey: ['lookups'], queryFn: () => api.lookups.getStaticData(), staleTime: Infinity, // ETag-based, manually invalidate }); ``` ## Deliverables At the end of Phase 1, you should have: 1. A working Next.js app with Tailwind + shadcn/ui 2. Login and registration flows that authenticate against the Go API 3. A protected app shell with sidebar navigation 4. A design system with color tokens matching the mobile app 5. Typed API client with error handling 6. Theme switching (light/dark + 11 color themes)