Captures stack shape, common commands (with Windows-friendly --prefix/--project forms), backend feature-folder layout, JWT + SignalR auth flow, and required .env keys. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
5.4 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Overview
YesChef is a family shopping list and recipe app. Single-tenant per deployment, gated by a shared FAMILY_CODE invite phrase at registration. Real-time list collaboration is delivered over SignalR.
The repo is a small monorepo with two deployables plus an e2e harness at the root:
src/backend/YesChef.Api/— ASP.NET Core (net10.0) minimal API + EF Core (Npgsql) + SignalRsrc/frontend/— SvelteKit 2 (Svelte 5 runes) + TypeScript + Tailwind v4, deployed via@sveltejs/adapter-nodedocker-compose.yml(root) — production-style stack: Postgres 17 + backend + frontend, fronted by Traefik (TLS via Let's Encrypt). Frontend and backend share the sameDOMAIN; Traefik routes/api,/hubs, and/healthto the backend, everything else to the frontend.test-e2e.mjs/test-e2e-multiuser.mjs— Playwright scripts run againsthttp://localhost:5173(Vite dev) hitting a local backend.
Common commands
Frontend (run from src/frontend, use npm --prefix src/frontend <cmd> to avoid cd):
npm --prefix src/frontend install
npm --prefix src/frontend run dev # Vite dev server on :5173
npm --prefix src/frontend run build # adapter-node build → src/frontend/build
npm --prefix src/frontend run check # svelte-kit sync + svelte-check (type/lint check)
Backend (use dotnet --project to avoid cd):
dotnet run --project src/backend/YesChef.Api # listens per launchSettings.json
dotnet build src/backend/YesChef.Api/YesChef.Api.csproj
dotnet ef migrations add <Name> --project src/backend/YesChef.Api
dotnet ef database update --project src/backend/YesChef.Api
Note: Program.cs calls db.Database.MigrateAsync() on startup, so running the API auto-applies pending migrations against the configured ConnectionStrings:DefaultConnection.
Full stack via Docker (requires .env populated from .env.example):
docker compose up -d --build
docker compose logs -f backend
E2E (requires frontend running on :5173 and backend reachable):
node test-e2e.mjs
node test-e2e-multiuser.mjs
There is no backend test project and no test runner configured in the root package.json — npm test is a no-op stub.
Architecture
Backend — feature-folder minimal API
Program.cs is the composition root. It wires EF Core (YesChefDb), JWT bearer auth, SignalR, runs migrations, then maps endpoints by feature folder:
Auth/—/api/authregister/login/me. Registration requires theFamilyCodeconfig value (envFamilyCode). Passwords usePasswordHasher<User>. JWTs are signed with HS256 fromJwt:Secret; issuer/audience are NOT validated. TheOnMessageReceivedevent also accepts?access_token=for the/hubs/*SignalR paths.Features/Stores/,Features/ShoppingLists/,Features/Recipes/— each exposes a staticMap…Endpoints(this RouteGroupBuilder)extension. All are mapped underRequireAuthorization().Features/ShoppingLists/ShoppingListHub.cs— SignalR hub at/hubs/shopping-listfor live list updates.Data/YesChefDb.cs— singleDbContext. Notable model rules:User.NameandStore.Nameare unique;ShoppingList → Itemscascade-deletes;ShoppingListItem.CheckedByUserandShoppingListItem.Recipeset null on delete;Recipe → Ingredientscascades.Auth/ClaimsPrincipalExtensions.cs—GetUserId()/GetUserName()helpers used by endpoints to scope writes.Migrations/— EF Core migrations. Add new ones withdotnet ef migrations add(see commands above).
When adding a feature: create Features/<Name>/<Name>Endpoints.cs with a Map<Name>Endpoints extension, register the group in Program.cs, and add any new entities to Entities/ plus configuration in YesChefDb.OnModelCreating.
Frontend — SvelteKit with runes
svelte.config.jsforcesrunes: truefor all non-node_modulesfiles. Use Svelte 5 runes ($state,$derived,$effect); do not use legacy reactive$:syntax.src/lib/api.ts—api<T>(path, opts)helper. Stores the JWT inlocalStorageundertoken, attachesAuthorization: Bearer …, and on 401 it clears the token andgoto('/login').src/lib/auth.svelte.ts— runes-based auth state.src/lib/signalr.ts— SignalR client wiring (passes the JWT via the?access_token=query string the backend'sOnMessageReceivedhandler expects).src/routes/— file-based routes:/login,/lists,/lists/[id],/recipes,/recipes/new,/recipes/[id],/stores.src/service-worker.ts— PWA service worker.$libis aliased tosrc/lib(seesvelte.config.js).- The frontend calls relative paths like
/api/...; in production Traefik routes those to the backend on the same host. For local dev against a backend on a different port, configure a Vite proxy or run the backend behind the same origin.
Configuration & secrets
.env.example documents the four required environment variables for the Docker stack: POSTGRES_PASSWORD, JWT_SECRET, FAMILY_CODE, DOMAIN. The backend reads Jwt:Secret, FamilyCode, and ConnectionStrings:DefaultConnection via IConfiguration — these can come from appsettings.Development.json for local runs or from environment variables (double-underscore form, e.g. ConnectionStrings__DefaultConnection) in containers.