e2172c20f2
Total rebrand across Web project: - Package name: casera-web -> honeydue-web - Cookie: casera-token -> honeydue-token - Theme store: casera-theme -> honeydue-theme - File sharing: .casera -> .honeydue, component/function renames - casera-file-handler.tsx -> honeydue-file-handler.tsx - All UI text, metadata, OG tags updated - Domains: casera.treytartt.com -> honeyDue.treytartt.com - Demo data emails updated - All documentation updated Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
9.6 KiB
9.6 KiB
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
npx create-next-app@latest honeyDueAPI-Web --typescript --tailwind --eslint --app --src-dir
cd honeyDueAPI-Web
npx shadcn@latest init
Install core dependencies:
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 shapeshoneyDueAPI-go/internal/dto/responses/— response shapeshoneyDueAPI-go/internal/models/— entity shapes
Key types to define in src/lib/types/:
types/
├── api.ts # ApiResult<T>, 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:
// src/lib/api/client.ts
const API_BASE_URL = process.env.NEXT_PUBLIC_API_URL || 'https://honeyDue.treytartt.com/api';
async function apiFetch<T>(
path: string,
options: RequestInit = {}
): Promise<T> {
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 <hex>(Django-compatible, same as mobile) - Cookie:
httpOnly,SameSite=Strict,Securein production - Next.js middleware in
src/middleware.tschecks cookie existence for protected routes
Auth Store (Zustand)
// src/stores/auth.ts
interface AuthState {
user: UserResponse | null;
isAuthenticated: boolean;
isLoading: boolean;
login: (email: string, password: string) => Promise<void>;
register: (data: RegisterRequest) => Promise<void>;
logout: () => Promise<void>;
fetchUser: () => Promise<void>;
}
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:
/* 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
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 12px;
--spacing-lg: 16px;
--spacing-xl: 24px;
7. TanStack Query Setup
// 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/:
// 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:
- A working Next.js app with Tailwind + shadcn/ui
- Login and registration flows that authenticate against the Go API
- A protected app shell with sidebar navigation
- A design system with color tokens matching the mobile app
- Typed API client with error handling
- Theme switching (light/dark + 11 color themes)