diff --git a/CLAUDE.md b/CLAUDE.md index c200e35..2ea78af 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -10,28 +10,28 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ```bash npm run dev # Start dev server (localhost:3000) -npm run build # Production build +npm run build # Production build --webpack (rolldown disabled) npm run lint # ESLint +npm run test # Vitest (unit tests only) ``` -No test framework is configured yet. - -Node version: `20.9.0` (see `.nvmrc`). +Node version: `>=20.19.0` (see `.nvmrc` / `engines` in package.json). ## Environment Setup -Copy `.env.example` to `.env.local` and fill in your Supabase project values: +Copy `.env.example` to `.env.local`: ``` NEXT_PUBLIC_SUPABASE_URL= NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY= +NEXT_PUBLIC_ENABLE_TEST_WIZARD=true # optional: enables /wizard-test route ``` Supabase project must have email/password auth enabled with email confirmation. Apply migrations from `supabase/migrations/` to your local/remote DB. ## Architecture -**Stack:** Next.js (App Router) + React 19 + TypeScript + Supabase (Auth + PostgreSQL) + shadcn/ui + Tailwind CSS. Deployed on Vercel. +**Stack:** Next.js 16 (App Router) + React 19 + TypeScript + Supabase (Auth + PostgreSQL) + shadcn/ui + Tailwind CSS. Deployed on Vercel. ### Route structure @@ -42,21 +42,37 @@ Supabase project must have email/password auth enabled with email confirmation. | `/auth/confirm` | Email confirmation callback | | `/onboarding` | Mandatory first-time setup | | `/dashboard` | Main protected page | +| `/planning` | Daily activity planning | +| `/check-in` | Morning check-in flow | | `/settings` | User preferences | +| `/wizard-test` | Internal wizard UI test (feature-flagged) | ### Auth & data flow -- `lib/auth/` — `getAuthState()` validates the session server-side from SSR cookies. All protected routes call this and redirect unauthenticated users to `/login`. -- New users are redirected to `/onboarding`; dashboard redirects there if onboarding is incomplete. -- On first protected page load, `profiles` and `user_settings` rows are auto-created with defaults if missing. -- Server Actions (`app/**/actions.ts`) handle form mutations; client components call these directly. +- `lib/auth/session.ts` — `getAuthState()` validates the session server-side from SSR cookies. All protected pages call this and redirect unauthenticated users to `/login`. +- New users are redirected to `/onboarding`; the dashboard redirects there if onboarding is incomplete. +- On first protected page load, `profiles` and `user_settings` rows are auto-created with defaults if missing (`lib/profile/service.ts`). +- Server Actions (`app/**/actions.ts`) handle all form mutations; client components call these directly. +- Status feedback after redirects flows via `?status=` search params → `lib/feedback/status-messages.ts` → `StatusToastBridge` component (Sonner toasts). + +### Energy model + +The core domain logic lives in `lib/check-in/` and `lib/planning/`: + +- **Morning check-in** (`lib/check-in/`) — user scores energy 1–10 and sleep quality. `budget.ts` derives `energyLevel` and `dailyBudget` (budget = score, formula versioned via `BUDGET_FORMULA_VERSION`). +- **Activity energy points** (`lib/planning/meter.ts`) — each activity scores points from duration band (1–4) × impact adjustment. The planning meter tracks `actualPoints` vs `dailyBudget`. +- **Day overview** (`lib/planning/day-overview.ts`) — aggregates activity counts and planned vs actual points for dashboard display. +- **Activity statuses**: `planned` → `completed` / `adjusted` / `skipped`. Ad-hoc activities can be added directly. ### Database -Two tables with Row Level Security (users see only their own rows): +Tables with Row Level Security (users see only their own rows): -- **`profiles`** — display name, locale, timezone, onboarding completion flags +- **`profiles`** — display name, locale, timezone, avatar, onboarding flags - **`user_settings`** — reminder preferences, energy point visibility +- **`morning_check_ins`** — per-day energy score, sleep quality, derived budget/level +- **`activities`** — daily activity records with status, duration, impact, priority, category +- **`activity_categories`** / **`skip_reasons`** — reference data (seeded) Migrations live in `supabase/migrations/`. @@ -65,12 +81,24 @@ Migrations live in `supabase/migrations/`. - `lib/supabase/` — Supabase client setup (server-side SSR client + proxy config) - `lib/auth/` — session helpers, navigation utilities, Dutch error messages - `lib/profile/service.ts` — CRUD for profiles and user_settings -- `lib/profile/types.ts` — shared TypeScript types for profile/settings data -- `lib/onboarding/` — onboarding options and timezone lists +- `lib/profile/types.ts` — shared TypeScript types +- `lib/forms/parse.ts` — typed FormData helpers (`getRequiredString`, `getEnumValue`, `getIntegerValue`, etc.) used in all Server Actions; throws `FormDataValidationError` with an error code string +- `lib/feedback/status-messages.ts` — maps `?status=` param keys to `StatusToast` objects +- `lib/wizard/` — generic multi-step wizard primitives (`WizardStepDefinition`, `useWizardFlow` hook); used by onboarding and check-in flows +- `lib/search-params.ts` — `getParamValue()` helper for server page `searchParams` +- `lib/config/feature-flags.ts` — `isTestWizardEnabled()` reads `NEXT_PUBLIC_ENABLE_TEST_WIZARD` ### UI components -`components/ui/` contains shadcn/ui primitives (button, card, input, select, alert, etc.). Feature-level components live in `components/auth/`, `components/onboarding/`, and `components/settings/`. Path alias `@/*` resolves from the repo root. +`components/ui/` contains shadcn/ui primitives. Feature-level components live in `components/auth/`, `components/check-in/`, `components/planning/`, `components/onboarding/`, `components/settings/`, `components/wizard/`, `components/navigation/`, `components/feedback/`, and `components/profile/`. Path alias `@/*` resolves from the repo root. + +The app uses the **Dusk theme** — dark-mode-first, semantic surface tokens, enhanced focus/a11y styles (`app/globals.css`). + +### Seeding + +```bash +npm run seed:demo-users # seeds demo personas via scripts/seed-demo-users.mjs +``` ## CI/CD diff --git a/app/check-in/loading.tsx b/app/check-in/loading.tsx index 7057309..1aee940 100644 --- a/app/check-in/loading.tsx +++ b/app/check-in/loading.tsx @@ -21,7 +21,7 @@ export default function CheckInLoading() {
- + @@ -36,7 +36,7 @@ export default function CheckInLoading() {
- + @@ -46,7 +46,7 @@ export default function CheckInLoading() { - + diff --git a/app/check-in/page.tsx b/app/check-in/page.tsx index 1458b9b..ca846bc 100644 --- a/app/check-in/page.tsx +++ b/app/check-in/page.tsx @@ -76,7 +76,7 @@ export default async function CheckInPage({ searchParams }: CheckInPageProps) {