|
| 1 | +# Copilot Instructions for SPURT |
| 2 | + |
| 3 | +## Project Overview |
| 4 | +SPURT is a task management app built with **Next.js 15 App Router** for procrastinators who wait until the last minute. The app uses a persona system with characters that guide users through task completion. |
| 5 | + |
| 6 | +## Architecture |
| 7 | + |
| 8 | +### Route Structure |
| 9 | +- **App Router** with route groups: |
| 10 | + - `(auth)/` - Public authentication routes (login, OAuth callbacks) |
| 11 | + - `(protected)/` - Authenticated routes with `AuthProvider` |
| 12 | + - `(create)/` - Task creation flows (instant-create, scheduled-create) |
| 13 | + - `(root)/` - Home and main views |
| 14 | + - `action/`, `immersion/`, `retrospection/` - Task interaction flows |
| 15 | + - `my-page/` - User profile and settings |
| 16 | + - `api/` - API routes that proxy to backend (`NEXT_PUBLIC_API_URL`) |
| 17 | + |
| 18 | +### Authentication Flow |
| 19 | +1. OAuth callback routes (`/oauth/callback/kakao`, `/oauth/callback/apple`) handle social login |
| 20 | +2. API routes set **httpOnly** cookies (`accessToken`, `refreshToken`, `user`) with `sameSite: "lax"` for iOS WebView compatibility |
| 21 | +3. Middleware ([middleware.ts](middleware.ts)) redirects unauthenticated users to `/login` (except open paths) |
| 22 | +4. `serverKy.ts` handles automatic token refresh on 401 responses |
| 23 | + |
| 24 | +**Important**: Use `serverApi` from `src/lib/serverKy.ts` for all API calls (not client-side `ky.ts`): |
| 25 | +- Automatic Bearer token injection from server-side cookies |
| 26 | +- Token refresh on 401 with batch request optimization |
| 27 | +- Proper headers and credentials |
| 28 | +- All API routes proxy through `/api/*` endpoints using `serverApi` |
| 29 | + |
| 30 | +### State Management |
| 31 | +Uses **Zustand** stores (not Redux): |
| 32 | +- `useAuthStore` - Auth loading states |
| 33 | +- `useUserStore` - User profile data |
| 34 | +- `useTaskStore` - Task state management |
| 35 | + |
| 36 | +Access stores with hooks: `const { setUser } = useUserStore()` |
| 37 | + |
| 38 | +### Data Fetching Patterns |
| 39 | +1. **API routes**: All use `serverApi` from [serverKy.ts](src/lib/serverKy.ts) - has access to server-side cookies |
| 40 | +2. **Client components**: Call `/api/*` routes via `fetch` (which internally use `serverApi`) |
| 41 | +3. **React Query**: Configured in [providers.tsx](src/app/providers/providers.tsx) with 60s staleTime |
| 42 | +4. **Task data transformation**: Always use `convertApiResponseToTask()` from [task.ts](src/types/task.ts) to convert API responses |
| 43 | + |
| 44 | +### Multi-Step Forms |
| 45 | +Uses `@use-funnel/browser` for form flows (NOT react-hook-form): |
| 46 | +```typescript |
| 47 | +const funnel = useFunnel<{ task: string, deadlineDate: string }>({ |
| 48 | + id: "instant-create", |
| 49 | + initial: { step: "taskForm", context: { task: "", deadlineDate: "" } } |
| 50 | +}); |
| 51 | + |
| 52 | +<funnel.Render |
| 53 | + taskForm={({ context }) => <TaskFormStep context={context} />} |
| 54 | + taskTypeInput={({ context }) => <TaskTypeStep />} |
| 55 | +/> |
| 56 | +``` |
| 57 | +See [instant-create/page.tsx](src/app/(protected)/(create)/instant-create/page.tsx) for reference. |
| 58 | + |
| 59 | +## Code Style & Conventions |
| 60 | + |
| 61 | +### Formatting |
| 62 | +- Use **Biome** (not Prettier/ESLint alone) - `biome.json` config |
| 63 | +- Tabs for indentation |
| 64 | +- Double quotes for strings |
| 65 | +- Korean comments are acceptable (team preference) |
| 66 | + |
| 67 | +### Styling |
| 68 | +- **Tailwind CSS** with custom design tokens in [tailwind.config.ts](tailwind.config.ts) |
| 69 | +- Custom typography: `text-h1`, `text-t2`, `text-b3`, `text-c1` (header/title/body/caption scales) |
| 70 | +- Custom colors: `bg-background-primary`, `text-text-normal`, `bg-component-accent-primary` |
| 71 | +- Mobile-first (viewport locked): `maximum-scale=1.0, user-scalable=no` |
| 72 | +- Use `background-primary` (not `bg-white`) for consistent theming |
| 73 | + |
| 74 | +### Component Patterns |
| 75 | +- Shadcn-style components in `src/components/ui/` |
| 76 | +- Modular feature components in `src/components/` (BackHeader, DatePicker, Modal, etc.) |
| 77 | +- Client components marked with `"use client"` directive |
| 78 | +- Suspense boundaries for search params: wrap components using `useSearchParams()` in `<Suspense>` |
| 79 | + |
| 80 | +### Type Safety |
| 81 | +- Strict TypeScript enabled |
| 82 | +- API response types in `src/types/` (task.ts, auth.ts, user.ts, subtask.ts) |
| 83 | +- Task status types: `"pending" | "completed" | "reflected" | "procrastinating" | "inProgress"` |
| 84 | +- Always transform API responses with typed converters |
| 85 | + |
| 86 | +## Key Developer Workflows |
| 87 | + |
| 88 | +### Local Development |
| 89 | +```bash |
| 90 | +npm run dev # Start dev server |
| 91 | +npm run build # Production build |
| 92 | +npm run lint # Run Biome linter |
| 93 | +npm run init:ssl # Initialize SSL for local HTTPS |
| 94 | +``` |
| 95 | + |
| 96 | +### FCM Push Notifications |
| 97 | +- FCM tokens managed via `src/lib/fcmToken.ts` |
| 98 | +- Device registration in `api/fcm-devices/` |
| 99 | +- Firebase messaging worker: `public/firebase-messaging-sw.js` |
| 100 | + |
| 101 | +### WebView Communication |
| 102 | +- Use `useWebViewMessage` hook for native app bridge |
| 103 | +- Haptic feedback types defined in `src/types/haptic.ts` |
| 104 | + |
| 105 | +### Testing New Features |
| 106 | +1. Check route group structure - auth vs protected |
| 107 | +2. Verify middleware rules for new routes |
| 108 | +3. Use service layer for API calls, not direct fetch |
| 109 | +4. Transform API responses with type converters |
| 110 | +5. Use Zustand stores for shared state |
| 111 | + |
| 112 | +## Critical Files |
| 113 | +- [middleware.ts](src/middleware.ts) - Route protection logic |
| 114 | +- [serverKy.ts](src/lib/serverKy.ts) - Server-side API client with token refresh |
| 115 | +- [taskService.ts](src/services/taskService.ts) - Task data layer (calls `/api/*` endpoints) |
| 116 | +- [task.ts](src/types/task.ts) - Task type definitions & transformers |
| 117 | +- [tailwind.config.ts](tailwind.config.ts) - Design system tokens |
| 118 | + |
| 119 | +## Common Pitfalls |
| 120 | +❌ Don't use client-side `ky.ts` - use `serverApi` from `serverKy.ts` in API routes |
| 121 | +❌ Don't forget to wrap `useSearchParams()` components in `<Suspense>` |
| 122 | +❌ Don't bypass API routes - always proxy through `/api/*` endpoints |
| 123 | +❌ Don't use generic color classes (`bg-white`) - use design tokens (`bg-background-primary`) |
| 124 | +❌ Don't forget to transform API task responses with `convertApiResponseToTask()` |
0 commit comments