diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 7c3d140..e983993 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -33,7 +33,11 @@ Decimal phases appear between their surrounding integers in numeric order. 3. Owner can edit and delete a pet profile they own 4. Owner with multiple pets can switch the active pet without logging out; the active pet identity is reflected throughout the UI 5. Owner can upload a photo via presigned R2 URL — the image is stored in Cloudflare R2 and served via CDN, never through the API server -**Plans**: TBD +**Plans**: +- 01: Walking Skeleton — scaffold, Clerk proxy, Prisma schema, tRPC wiring, test scaffold +- 02: Auth screens — sign-up, log-in, forgot/reset password, verify-email, app shell +- 03: Pet CRUD — create/edit/delete pet, My Pets grid, profile view, breed seed, unit tests +- 04: Media pipeline — presigned R2 upload, AvatarUpload component, CDN delivery, unit tests **UI hint**: yes ### Phase 2: Content Core @@ -121,7 +125,7 @@ Phases execute in numeric order. Phase 5 depends only on Phase 2 (not Phase 4) s | Phase | Plans Complete | Status | Completed | |-------|----------------|--------|-----------| -| 1. Foundation | 0/TBD | Not started | - | +| 1. Foundation | 0/4 | Not started | - | | 2. Content Core | 0/TBD | Not started | - | | 3. Engagement and Discovery | 0/TBD | Not started | - | | 4. Notifications | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index dc369d3..d1cf5d4 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -1,10 +1,15 @@ --- -gsd_state_version: '1.0' -status: planning +gsd_state_version: 1.0 +milestone: v1.0 +milestone_name: milestone +status: executing +stopped_at: Phase 1 plans complete (01-01 through 01-04) +last_updated: "2026-06-05T15:29:08.194Z" +last_activity: 2026-06-05 — Phase 1 plans created (01-01 through 01-04); ready for execution progress: total_phases: 7 completed_phases: 0 - total_plans: 0 + total_plans: 4 completed_plans: 0 percent: 0 --- @@ -21,15 +26,16 @@ See: .planning/PROJECT.md (updated 2026-06-05) ## Current Position Phase: 1 of 7 (Foundation) -Plan: 0 of TBD in current phase -Status: Ready to plan -Last activity: 2026-06-05 — Roadmap created; 43/43 v1 requirements mapped across 7 phases +Plan: 0 of 4 in current phase +Status: Ready to execute +Last activity: 2026-06-05 — Phase 1 plans created (01-01 through 01-04); ready for execution Progress: [░░░░░░░░░░] 0% ## Performance Metrics **Velocity:** + - Total plans completed: 0 - Average duration: - - Total execution time: 0 hours @@ -41,6 +47,7 @@ Progress: [░░░░░░░░░░] 0% | - | - | - | - | **Recent Trend:** + - Last 5 plans: - - Trend: - @@ -79,6 +86,6 @@ None yet. ## Session Continuity -Last session: 2026-06-05 -Stopped at: Roadmap created — ready to run /gsd-plan-phase 1 -Resume file: None +Last session: 2026-06-05T15:00:00.000Z +Stopped at: Phase 1 plans complete (01-01 through 01-04) +Resume file: .planning/phases/01-foundation/01-01-PLAN.md diff --git a/.planning/phases/01-foundation/01-01-PLAN.md b/.planning/phases/01-foundation/01-01-PLAN.md new file mode 100644 index 0000000..6564fe9 --- /dev/null +++ b/.planning/phases/01-foundation/01-01-PLAN.md @@ -0,0 +1,288 @@ +--- +phase: 01-foundation +plan: 01 +type: execute +wave: 0 +depends_on: [] +files_modified: + - package.json + - next.config.ts + - postcss.config.mjs + - src/app/globals.css + - src/app/layout.tsx + - src/app/(app)/layout.tsx + - src/app/(app)/pets/page.tsx + - src/app/(app)/onboarding/pet/page.tsx + - proxy.ts + - .env.example + - .env.local + - prisma/schema.prisma + - prisma/seed.ts + - src/lib/prisma.ts + - src/lib/r2.ts + - src/lib/auth.ts + - src/trpc/init.ts + - src/trpc/query-client.ts + - src/trpc/server.ts + - src/trpc/client.tsx + - src/trpc/routers/_app.ts + - src/trpc/routers/pets.ts + - src/app/api/trpc/[trpc]/route.ts + - src/context/ActivePetContext.tsx + - src/hooks/useActivePet.ts + - vitest.config.ts + - src/__tests__/auth.test.ts + - src/__tests__/pet-profile.test.ts + - src/__tests__/media-upload.test.ts + - src/__tests__/helpers/prisma-mock.ts +autonomous: false +requirements: [AUTH-01, AUTH-04, PET-01] +user_setup: + - service: supabase + why: "PostgreSQL host for all relational data" + env_vars: + - name: DATABASE_URL + source: "Supabase Dashboard -> Project Settings -> Database -> Connection string (pooled, port 6543, ?pgbouncer=true)" + - name: DIRECT_URL + source: "Supabase Dashboard -> Project Settings -> Database -> Connection string (direct, port 5432)" + dashboard_config: + - task: "Create a Supabase project and select a region close to the developer" + location: "supabase.com/dashboard -> New project" + - service: clerk + why: "Owner authentication (sign-up, login, email verification, password reset)" + env_vars: + - name: NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY + source: "Clerk Dashboard -> API Keys (keyless mode acceptable for initial local dev)" + - name: CLERK_SECRET_KEY + source: "Clerk Dashboard -> API Keys" + dashboard_config: + - task: "Create a Clerk application; enable Email + Password; enable email verification link" + location: "clerk.com/dashboard -> Create application" + - service: cloudflare-r2 + why: "Object storage for pet avatar photos (presigned PUT uploads)" + env_vars: + - name: CF_ACCOUNT_ID + source: "Cloudflare Dashboard -> R2 -> Account ID" + - name: R2_ACCESS_KEY_ID + source: "Cloudflare Dashboard -> R2 -> Manage R2 API Tokens" + - name: R2_SECRET_ACCESS_KEY + source: "Cloudflare Dashboard -> R2 -> Manage R2 API Tokens" + - name: R2_BUCKET_NAME + source: "Cloudflare Dashboard -> R2 -> bucket name you create" + - name: NEXT_PUBLIC_R2_PUBLIC_URL + source: "Cloudflare R2 -> bucket -> Public Development URL or custom CDN domain" + dashboard_config: + - task: "Create an R2 bucket and configure CORS to allow PUT and Content-Type header from http://localhost:3000 (and production origin)" + location: "Cloudflare Dashboard -> R2 -> bucket -> Settings -> CORS Policy" + +must_haves: + truths: + - "A signed-in owner can submit a pet-create form and the pet persists to Supabase PostgreSQL" + - "The newly created pet's name is read back from the DB and displayed in the app navigation" + - "Unauthenticated visits to /pets redirect to the Clerk sign-in flow" + - "npm run dev serves the full stack and npx vitest run executes the test scaffold" + artifacts: + - path: "proxy.ts" + provides: "Clerk auth enforcement on all non-public routes (Next.js 16 proxy convention)" + contains: "clerkMiddleware" + - path: "src/lib/prisma.ts" + provides: "PrismaClient singleton with Accelerate extension" + contains: "withAccelerate" + - path: "prisma/schema.prisma" + provides: "Owner, Species, Breed, Pet models" + contains: "model Pet" + - path: "src/trpc/routers/pets.ts" + provides: "pets.create, pets.list, pets.byId procedures with ownership assertion" + exports: ["petsRouter"] + - path: "src/app/api/trpc/[trpc]/route.ts" + provides: "tRPC fetch handler" + exports: ["GET", "POST"] + - path: "vitest.config.ts" + provides: "Vitest config with jsdom environment and @ path alias" + - path: "src/__tests__/pet-profile.test.ts" + provides: "Test scaffold (Wave 0) for PET-01..05 + ownership" + key_links: + - from: "src/app/(app)/onboarding/pet/page.tsx" + to: "pets.create" + via: "tRPC mutation via useTRPC hook" + pattern: "pets\\.create" + - from: "src/trpc/routers/pets.ts" + to: "prisma.pet" + via: "Prisma query" + pattern: "prisma\\.pet\\.(create|findMany|findUnique)" + - from: "proxy.ts" + to: "Clerk" + via: "clerkMiddleware + createRouteMatcher" + pattern: "createRouteMatcher" +--- + + +Establish the OnlyPets Walking Skeleton: the thinnest possible end-to-end vertical slice that exercises auth, routing, a real Supabase DB read and write, an interactive UI element, and the local full-stack run. After this plan, a signed-in owner can create a pet (name + species) via a form, the pet persists in PostgreSQL, and its name appears in the navigation. This plan also lands the Wave 0 test scaffold so all downstream tasks have automated verification targets. + +Purpose: Every subsequent phase depends on owner auth, the pet-as-actor identity model, the media pipeline foundation, and the tRPC/Prisma wiring. None can be retrofitted cheaply. This is the architectural spine. + +Output: Scaffolded Next.js 16 app; Clerk proxy.ts; Prisma schema (Owner/Species/Breed/Pet) pushed to Supabase; tRPC wiring with pets.create/list/byId; minimal onboarding + /pets pages; ActivePetContext; Vitest config + failing test scaffolds. + + + +@T:/CC-Projekte/.claude/gsd-core/workflows/execute-plan.md +@T:/CC-Projekte/.claude/gsd-core/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/ROADMAP.md +@.planning/STATE.md +@.planning/phases/01-foundation/SKELETON.md +@.planning/phases/01-foundation/01-RESEARCH.md +@.planning/phases/01-foundation/01-UI-SPEC.md +@.planning/phases/01-foundation/01-VALIDATION.md + + + +This plan creates the following symbols consumed by Plans 02–04 and all later phases: +- `proxy.ts` default export (Clerk middleware) — auth gate +- `prisma` singleton (`src/lib/prisma.ts`) — DB access for all routers +- `getPresignedUploadUrl(key, contentType)` (`src/lib/r2.ts`) — used by Plan 04 media router +- `getOwnerId()` / Clerk `auth()` wrapper (`src/lib/auth.ts`) +- `createTRPCContext`, `router`, `publicProcedure`, `protectedProcedure` (`src/trpc/init.ts`) +- `appRouter` + `AppRouter` type (`src/trpc/routers/_app.ts`) +- `petsRouter` with `create`, `list`, `byId` (`src/trpc/routers/pets.ts`) — extended by Plan 03 (update/delete) and Plan 04 (setAvatar) +- `useTRPC` hook + `TRPCReactProvider` (`src/trpc/client.tsx`) +- `ActivePetProvider`, `useActivePet` (`src/context/ActivePetContext.tsx`, `src/hooks/useActivePet.ts`) — wired fully in Plan 04 +- Prisma models: `Owner`, `Species`, `Breed`, `Pet` +- Test scaffolds: `src/__tests__/{auth,pet-profile,media-upload}.test.ts`, `src/__tests__/helpers/prisma-mock.ts` + + + + + + Task 1: Scaffold project, install stack, configure Tailwind v4 + shadcn + Vitest test scaffold + package.json, next.config.ts, postcss.config.mjs, src/app/globals.css, src/app/layout.tsx, vitest.config.ts, src/__tests__/auth.test.ts, src/__tests__/pet-profile.test.ts, src/__tests__/media-upload.test.ts, src/__tests__/helpers/prisma-mock.ts, .env.example + + - .planning/phases/01-foundation/01-RESEARCH.md (Standard Stack table; Installation block; Pitfall 2 Tailwind v4; Pattern 5 Clerk orange; Wave 0 Gaps; Validation Architecture) + - .planning/phases/01-foundation/01-UI-SPEC.md (Design System; shadcn init command; Components Required; Color CSS variables) + - .planning/phases/01-foundation/01-VALIDATION.md (Wave 0 Requirements; Per-Task Verification Map) + + + Scaffold with `npx create-next-app@latest onlypets --typescript --eslint --app --turbopack --src-dir --tailwind` into the current repo (the project root is the existing OnlyPets directory — scaffold in place; do not nest a subfolder). Pin exact versions per RESEARCH.md Standard Stack: next 16.2.7, react/react-dom 19.2.7, typescript 6.0.3. + Install runtime deps: @clerk/nextjs@7.4.3, @trpc/server@11.17.0, @trpc/client@11.17.0, @trpc/tanstack-react-query@11.17.0, @tanstack/react-query@5.101.0, zod@4.4.3, prisma@7.8.0, @prisma/client@7.8.0, @prisma/extension-accelerate@3.0.1, @supabase/supabase-js@2.107.0, @aws-sdk/client-s3@3.1062.0, @aws-sdk/s3-request-presigner@3.1062.0, sonner@2.0.7, lucide-react@1.17.0, @upstash/redis@1.38.0, server-only, client-only. + Install dev deps: vitest, @vitest/coverage-v8, @vitejs/plugin-react. + Use @trpc/tanstack-react-query (NOT @trpc/react-query). Verify postcss.config.mjs uses `@tailwindcss/postcss` (NOT `tailwindcss`) and globals.css uses `@import "tailwindcss";` (NOT the three v3 `@tailwind` directives). If create-next-app emitted a `tailwind.config.ts`, delete it — Tailwind v4 has no JS config file. + In src/app/globals.css under `:root`, set shadcn CSS variables to the orange-500 design system per UI-SPEC: `--primary: 24.6 95% 53.1%;`, `--primary-foreground: 0 0% 100%;`, `--background: 0 0% 98%;`, `--muted: 240 4.8% 95.9%;`. Load Inter via `next/font/google` in src/app/layout.tsx and apply as `font-sans` on ``. + Run `npx shadcn@latest init` with preset default / base color neutral / CSS variables yes, then `npx shadcn@latest add button input form label textarea select avatar card dialog dropdown-menu sonner progress separator badge skeleton`. + Create vitest.config.ts with jsdom environment, @vitejs/plugin-react, and a `@` -> `./src` path alias matching tsconfig. + Create the Wave 0 test scaffolds with FAILING placeholder tests (use `it.todo` or `expect(...).toBe` against not-yet-implemented imports guarded so the file runs): + - src/__tests__/auth.test.ts — describe blocks for AUTH-01 (owner row created with Clerk id, no password in app DB) and AUTH-02 (email verification status readable). Mark as `it.todo` referencing the procedures Plan 02 will implement. + - src/__tests__/pet-profile.test.ts — describe blocks for PET-01 (create with valid input), PET-02 (update rejected for non-owner -> FORBIDDEN), PET-03 (delete by owner), PET-05 (adoption story persists). Mark `it.todo`. + - src/__tests__/media-upload.test.ts — describe block for presigned URL generation with correct ContentType. Mark `it.todo`. + - src/__tests__/helpers/prisma-mock.ts — export a typed mock PrismaClient (vi.fn-based) so unit tests never hit a real DB. + Create .env.example listing every env var from user_setup with placeholder values (DATABASE_URL, DIRECT_URL, NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEY, CF_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET_NAME, NEXT_PUBLIC_R2_PUBLIC_URL). + Do NOT install @trpc/react-query. Do NOT create middleware.ts (Next.js 16 uses proxy.ts — created in Task 2). + + + npx tsc --noEmit && npx vitest run --reporter=dot + + + - `npx tsc --noEmit` exits 0 + - `npx vitest run` runs (todos reported, no crash) and exits 0 + - `grep -v '^#' postcss.config.mjs | grep -c '@tailwindcss/postcss'` returns >= 1 + - No `tailwind.config.ts` file exists at repo root + - package.json lists @trpc/tanstack-react-query and does NOT list @trpc/react-query + - src/__tests__/pet-profile.test.ts and src/__tests__/media-upload.test.ts exist + + Project scaffolds, type-checks, Tailwind v4 + shadcn configured with orange primary, all stack deps installed at pinned versions, Vitest runs the failing/todo test scaffold green. + + + + Task 2: Wire Clerk proxy.ts, Prisma schema + singleton, tRPC stack, R2 client, ActivePetContext + proxy.ts, src/app/layout.tsx, src/lib/prisma.ts, src/lib/r2.ts, src/lib/auth.ts, prisma/schema.prisma, prisma/seed.ts, src/trpc/init.ts, src/trpc/query-client.ts, src/trpc/server.ts, src/trpc/client.tsx, src/trpc/routers/_app.ts, src/trpc/routers/pets.ts, src/app/api/trpc/[trpc]/route.ts, src/context/ActivePetContext.tsx, src/hooks/useActivePet.ts + + - .planning/phases/01-foundation/01-RESEARCH.md (Pattern 1 Two-Layer Identity; Pattern 2 Presigned R2; Pattern 3 proxy.ts; Pattern 4 Prisma Singleton; Pattern 6 Active Pet Context; Prisma Schema code example; tRPC Route Handler code example; Security Domain) + - src/app/globals.css (verify Inter + orange vars from Task 1) + + + Create proxy.ts at REPO ROOT (not src/) per RESEARCH Pattern 3: `clerkMiddleware` + `createRouteMatcher` with public routes `/sign-up(.*)`, `/log-in(.*)`, `/forgot-password(.*)`, `/reset-password(.*)`, `/verify-email(.*)`; call `await auth.protect()` for non-public routes; export the documented `config.matcher` array including `/(api|trpc)(.*)` and `/__clerk/(.*)`. + Wrap src/app/layout.tsx children in `` and mount ``, ``, and Sonner ``. + Create prisma/schema.prisma exactly per RESEARCH Prisma Schema example: datasource with `url=env("DATABASE_URL")` and `directUrl=env("DIRECT_URL")`; models Owner (id = Clerk userId String @id), Species (id, name @unique), Breed (id, name, speciesId FK, @@unique([speciesId, name])), Pet (id cuid, ownerId FK, speciesId FK, breedId String? FK, name, bio String?, adoptionStory String?, avatarKey String?, createdAt, updatedAt, @@index([ownerId])). + Create src/lib/prisma.ts as the global singleton with `withAccelerate()` per RESEARCH Pattern 4. + Create src/lib/r2.ts exporting `r2` S3Client (region 'auto', endpoint `https://${CF_ACCOUNT_ID}.r2.cloudflarestorage.com`) and `getPresignedUploadUrl(key, contentType)` with `expiresIn: 300` per RESEARCH Pattern 2. Mark file `import 'server-only'`. + Create src/lib/auth.ts exporting an async `getOwnerId()` that calls Clerk `auth()` and returns userId (or null). + Create src/trpc/init.ts: `createTRPCContext` reading `{ userId } = await auth()` and `prisma`; `protectedProcedure` throws `TRPCError UNAUTHORIZED` when no userId. Per RESEARCH Pattern 1. + Create src/trpc/routers/pets.ts `petsRouter` with: `create` (protected; Zod input name<=30, speciesId, breedId optional, bio<=150 optional, adoptionStory<=500 optional; upsert Owner row from ctx.userId then create Pet with ownerId=ctx.userId); `list` (protected; findMany where ownerId=ctx.userId); `byId` (protected; findUnique then assert pet.ownerId===ctx.userId else FORBIDDEN). Implement the ownership-assertion helper inline so Plan 03 reuses the pattern. + Create src/trpc/routers/_app.ts exporting `appRouter` ({ pets: petsRouter }) and `export type AppRouter = typeof appRouter`. + Create src/trpc/query-client.ts (makeQueryClient factory), src/trpc/server.ts (createCallerFactory for RSC), src/trpc/client.tsx (`TRPCReactProvider`, `useTRPC` via @trpc/tanstack-react-query), and src/app/api/trpc/[trpc]/route.ts per RESEARCH tRPC Route Handler example (`fetchRequestHandler`, export GET and POST). + Create src/context/ActivePetContext.tsx (`ActivePetProvider`, `useActivePet`) per RESEARCH Pattern 6 (localStorage-backed); src/hooks/useActivePet.ts re-exports the hook. + Create prisma/seed.ts that seeds Species (Dog, Cat, Bird) idempotently (Plan 03 extends it with breeds). Register `prisma.seed` in package.json. + SECURITY (T-1-02): never trust client-supplied pet ids — every pets mutation/scoped query asserts `pet.ownerId === ctx.userId`. SECURITY (T-1-03): R2 credentials live only in server-only modules; presigned URL generation only in tRPC procedures. + + + npx tsc --noEmit && npx prisma validate && npx vitest run --reporter=dot + + + - `npx prisma validate` exits 0 + - `npx tsc --noEmit` exits 0 + - `grep -c 'clerkMiddleware' proxy.ts` returns >= 1 and proxy.ts is at repo root + - `grep -c 'withAccelerate' src/lib/prisma.ts` returns >= 1 + - `grep -Ec 'pet\.ownerId === ctx\.userId|ownerId !== ctx\.userId' src/trpc/routers/pets.ts` returns >= 1 (ownership assertion present) + - src/trpc/routers/_app.ts exports `AppRouter` type + - No `middleware.ts` exists at repo root + + Clerk proxy gates routes; Prisma schema validates with Owner/Species/Breed/Pet; tRPC wired end-to-end with ownership-asserted pets router; R2 helper and ActivePetContext exist; species seed ready. + + + + Prisma schema (Owner, Species, Breed, Pet) and tRPC pets router are complete. The schema must now be pushed to the live Supabase PostgreSQL database before any verification can read or write pets. This is the mandatory [BLOCKING] schema push. + + 1. Confirm `.env.local` contains real `DATABASE_URL` (pooled, port 6543, `?pgbouncer=true`) and `DIRECT_URL` (direct, port 5432) from your Supabase project. If you have not created the Supabase project yet, create it now (supabase.com/dashboard -> New project) and copy both connection strings. + 2. Run: `npx prisma db push` (creates tables against Supabase). If running non-interactively/CI and a destructive prompt blocks, use `npx prisma db push --accept-data-loss`. + 3. Run: `npx prisma db seed` (seeds Dog/Cat/Bird species). + 4. Run: `npx prisma studio` and confirm the `Species` table has 3 rows and `Owner`/`Pet`/`Breed` tables exist and are empty. + 5. Confirm `npx prisma generate` ran (Prisma client types available). + + Type "pushed" once `prisma db push` succeeds and Species table shows 3 rows, or describe the error. + + + + + +## Trust Boundaries + +| Boundary | Description | +|----------|-------------| +| Browser → proxy.ts | Unauthenticated requests cross here; Clerk middleware must gate all non-public routes | +| Browser → tRPC API | Client-supplied input (pet fields, pet ids) is untrusted; Zod validation + ownership assertion required | +| API server → Supabase | Prisma queries scoped by owner_id; no raw client-supplied id trusted | +| Server env → client bundle | R2 + Clerk secret credentials must never reach the client bundle | + +## STRIDE Threat Register + +| Threat ID | Category | Component | Disposition | Mitigation Plan | +|-----------|----------|-----------|-------------|-----------------| +| T-1-01 | Spoofing | Auth / session | mitigate | Clerk-managed httpOnly JWT sessions; no hand-rolled auth; proxy.ts protects all non-public routes via `auth.protect()` | +| T-1-02 | Tampering / EoP | tRPC pets procedures | mitigate | `protectedProcedure` requires userId; every pet query/mutation asserts `pet.ownerId === ctx.userId`, throws FORBIDDEN otherwise (ASVS V4) | +| T-1-03 | Information Disclosure | R2 credentials | mitigate | R2 creds in server-only env vars; `src/lib/r2.ts` marked `server-only`; presigned URL generation only in tRPC procedures | +| T-1-04 | Tampering | Zod input validation | mitigate | All tRPC inputs validated with Zod (name<=30, bio<=150, adoptionStory<=500) per ASVS V5 | +| T-1-05 | Elevation of Privilege | Route access | mitigate | `createRouteMatcher` public allowlist; all other routes require auth via proxy.ts | +| T-1-SC | Tampering | npm installs | mitigate | All packages [VERIFIED: npm registry] in RESEARCH Package Legitimacy Audit; no [ASSUMED]/[SUS]/[SLOP] packages — no blocking checkpoint required | + + + +- `npx tsc --noEmit` clean +- `npx prisma validate` passes; `npx prisma db push` applied to Supabase (Task 3 checkpoint) +- `npx vitest run` green (scaffold) +- `npm run dev` starts; visiting `/pets` while logged out redirects to Clerk sign-in +- Species table seeded with Dog/Cat/Bird + + + +- Walking skeleton runs locally: signed-in owner can create a pet and see it in nav (full flow completed once Plan 02 auth pages + Plan 03 form land; skeleton wiring is in place here) +- Clerk auth gate enforced via proxy.ts +- Prisma schema pushed to Supabase; species seeded +- tRPC pets router (create/list/byId) with ownership assertion operational +- Vitest scaffold green; downstream tasks have test targets + + + +Create `.planning/phases/01-foundation/01-01-SUMMARY.md` when done + diff --git a/.planning/phases/01-foundation/01-02-PLAN.md b/.planning/phases/01-foundation/01-02-PLAN.md new file mode 100644 index 0000000..dfd9a24 --- /dev/null +++ b/.planning/phases/01-foundation/01-02-PLAN.md @@ -0,0 +1,222 @@ +--- +phase: 01-foundation +plan: 02 +type: execute +wave: 1 +depends_on: [01-01] +files_modified: + - src/app/(auth)/sign-up/[[...sign-up]]/page.tsx + - src/app/(auth)/log-in/[[...sign-in]]/page.tsx + - src/app/(auth)/forgot-password/page.tsx + - src/app/(auth)/reset-password/page.tsx + - src/app/(auth)/verify-email/page.tsx + - src/app/(auth)/layout.tsx + - src/app/(app)/layout.tsx + - src/app/(app)/onboarding/pet/page.tsx + - src/components/layout/Sidebar.tsx + - src/components/layout/MobileNav.tsx + - src/middleware.ts +autonomous: false +requirements: [AUTH-01, AUTH-02, AUTH-03, AUTH-04] +--- + + +Wire all Clerk-backed authentication screens and the protected app shell that houses every post-auth route in Phase 1. After this plan, an owner can sign up with email and password, verify their email, log in, and reset a forgotten password — all through Clerk-rendered UI customized to match the OnlyPets orange-500 design system. A signed-in owner who visits `/pets` sees the app shell (sidebar on desktop, bottom nav on mobile) and is redirected to `/onboarding/pet` when they have no pets yet. An unsigned-in owner who visits any protected route is redirected to `/log-in`. + +Purpose: AUTH-01 through AUTH-04 are the prerequisite gate that every downstream plan depends on. No content, no pet profile, no media pipeline can be used without a working auth flow. The app shell establishes the navigation context that Plans 03 and 04 populate with real content. + +Output: Five auth pages (sign-up, log-in, forgot-password, reset-password, verify-email) in the `(auth)` route group; a centered 448px auth layout; a protected `(app)` layout with desktop sidebar and mobile bottom nav; onboarding redirect logic; Inter font applied; Clerk appearance overridden to orange-500. + + + +@T:/CC-Projekte/.claude/gsd-core/workflows/execute-plan.md +@T:/CC-Projekte/.claude/gsd-core/templates/summary.md + + + +@.planning/PROJECT.md +@.planning/phases/01-foundation/SKELETON.md +@.planning/phases/01-foundation/01-RESEARCH.md +@.planning/phases/01-foundation/01-UI-SPEC.md +@.planning/phases/01-foundation/01-VALIDATION.md + + + +- `src/app/(auth)/layout.tsx` — centered 448px card layout for all auth pages +- `src/app/(auth)/sign-up/[[...sign-up]]/page.tsx` — Clerk `` with orange appearance +- `src/app/(auth)/log-in/[[...sign-in]]/page.tsx` — Clerk `` with orange appearance +- `src/app/(auth)/forgot-password/page.tsx` — Clerk forgot-password flow +- `src/app/(auth)/reset-password/page.tsx` — Clerk reset-password flow +- `src/app/(auth)/verify-email/page.tsx` — email verification pending screen +- `src/app/(app)/layout.tsx` — protected layout with sidebar + mobile nav; redirects no-pet owners to onboarding +- `src/components/layout/Sidebar.tsx` — 240px desktop sidebar consumed by all app routes +- `src/components/layout/MobileNav.tsx` — bottom tab bar for mobile (< 768px) +- `src/app/(app)/onboarding/pet/page.tsx` — landing page stub (form wired in Plan 03) + + + + + + Task 1: Auth layout and Clerk-rendered auth pages (sign-up, log-in, forgot-password, reset-password, verify-email) + src/app/(auth)/layout.tsx, src/app/(auth)/sign-up/[[...sign-up]]/page.tsx, src/app/(auth)/log-in/[[...sign-in]]/page.tsx, src/app/(auth)/forgot-password/page.tsx, src/app/(auth)/reset-password/page.tsx, src/app/(auth)/verify-email/page.tsx + + - .planning/phases/01-foundation/01-UI-SPEC.md (Auth Screens table; Auth Copy table; Spacing Scale; Color palette; Typography; Component Specifications — Primary CTA; Owner Identity Subordination) + - .planning/phases/01-foundation/01-RESEARCH.md (Pattern 3 proxy.ts — public route list; Pattern 5 Clerk Appearance; Standard Stack @clerk/nextjs 7.4.3) + + + Create `src/app/(auth)/layout.tsx`: a server component that renders a centered column with max-width 448px and horizontal padding md (16px) — `mx-auto max-w-[448px] px-4`. Apply `min-h-screen flex items-center justify-center bg-background` so auth cards are vertically centered. Render `{children}`. No sidebar, no nav — auth pages are standalone. + + Create `src/app/(auth)/sign-up/[[...sign-up]]/page.tsx` using Clerk's `` component from `@clerk/nextjs`. Pass `appearance` with `variables: { colorPrimary: '#F97316', colorBackground: '#FAFAFA', colorText: '#09090B' }` and `elements: { formButtonPrimary: 'bg-orange-500 hover:bg-orange-600 text-white text-sm' }` to match the design system. Set Clerk routing props: `path="/sign-up"`, `signInUrl="/log-in"`, `forceRedirectUrl="/onboarding/pet"`. Page heading (rendered by Clerk): "Create your account" — controlled via Clerk appearance `layout.logoPlacement: 'none'` and sign-up copy customization. Page is a server component (Clerk `` is a server-renderable component in Clerk 7). + + Create `src/app/(auth)/log-in/[[...sign-in]]/page.tsx` using Clerk's `` component. Same appearance overrides. Set `path="/log-in"`, `signUpUrl="/sign-up"`, `forceRedirectUrl="/pets"`. Clerk renders the "Welcome back" heading and "Log in" CTA automatically — no custom copy needed beyond what Clerk exposes. + + Create `src/app/(auth)/forgot-password/page.tsx`: Render a centered card (shadcn ``) with: + - Page heading: "Reset your password" (text-xl font-semibold) + - Single `` for email with `