diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..a40d8bc --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,124 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +CrAPP — a mobile-first web app for managing an amateur volleyball team (CRAP Volley): attendance, +matches/trainings/events, live match scouting, player stats/badges, CSI league standings, push +notifications. Italian-language codebase (routes, variables, comments). Built with Lovable +(lovable.dev); pushes to `main` sync back into the Lovable editor — avoid rewriting published git +history (force-push, rebase/amend/squash of pushed commits). + +## Commands + +Package manager is **bun** (`bun.lock` is the lockfile; `package-lock.json` also exists but bun is +primary — see `bunfig.toml`). + +```sh +bun run dev # vite dev server +bun run build # production build (nitro/vite) +bun run build:dev # development-mode build +bun run preview # preview a build +bun run lint # eslint . +bun run format # prettier --write . +``` + +There is no test runner configured in this repo. + +Adding a dependency: `bunfig.toml` enforces a 24h supply-chain guard (`minimumReleaseAge`) on new +packages; only pre-listed `@lovable.dev/*` packages bypass it. Confirm with the user before adding +new bypass entries. + +## Architecture + +**Stack**: TanStack Start (React 19, file-based router) + Vite, styled with Tailwind v4 + +shadcn/radix components, data via `@supabase/supabase-js`, TanStack Query for client cache. + +### Routing + +File-based routing under `src/routes/` (see `src/routes/README.md`). One root layout, +`src/routes/__root.tsx`, wraps every page — preserve its ``. `$id.tsx` = dynamic segment, +`{-$category}.tsx` = optional segment, `$.tsx` = splat (`_splat` param). Do not hand-create +`src/pages/` or Next/Remix-style layout files. `src/routeTree.gen.ts` is auto-generated — never +edit it directly. + +Server-only HTTP endpoints live under `src/routes/api/public/*.ts` (e.g. push subscription, +palloni/presenze reminders) — plain HTTP handlers, not proprietary edge functions, so they can run +under any Node host or scheduler (system cron, pg_cron, etc). + +### Server entry / SSR error handling + +`src/start.ts` registers global middleware: `attachSupabaseAuth` (client-side function middleware +that attaches the Supabase bearer token to every server-fn RPC — see +`src/integrations/supabase/auth-attacher.ts`, which is **auto-generated**, do not hand-edit) and an +error middleware + explicit CSRF middleware (`createCsrfMiddleware`) for server functions. Defining +`src/start.ts` opts out of Start's automatic CSRF middleware, so this file must keep re-adding it. + +`src/server.ts` wraps the generated TanStack Start server entry and normalizes a specific h3 +failure mode: h3 swallows in-handler throws into a 500 JSON body +(`{"unhandled":true,"message":"HTTPError"}`) that a plain try/catch never sees, so it's detected by +inspecting the response body and converted into `renderErrorPage()`'s HTML error page. + +### Data layer — portability rule + +The project must remain deployable on plain Node.js + PostgreSQL, not locked into Lovable Cloud +(see `docs/PORTABILITA.md`). Concretely: + +- **Never query the database from components.** All data access goes through modules in + `src/lib/*.ts` (e.g. `palloni.ts`, `mvp-voti.ts`, `eventi.ts`, `presenze.ts`, `rosa.ts`, + `scout-*.ts`) — each exports TanStack Query hooks (`useX`) wrapping `supabase.from(...)`. This + keeps the backend swappable in one place. +- `src/integrations/lovable/*` (social login) is optional and unused by any screen — safe to + remove without impact. +- No provider-exclusive features: no edge functions, no Lovable-only auth as the sole login method, + no proprietary storage. Config only via standard env vars (`DATABASE_URL` / `SUPABASE_URL` + + keys, `VAPID_*`), never hardcoded. +- SQL migrations in `supabase/migrations/` must use standard PostgreSQL, no provider-exclusive + extensions. + +### Cloud-efficiency rules (small paid-tier budget) + +The Supabase/Lovable Cloud plan is metered (~20 credits/month, ~17 users), so these constraints are +load-bearing, not style preferences: + +- No polling (`refetchInterval`) against the database; prefer local sync via + BroadcastChannel/storage. +- Global QueryClient (`src/router.tsx`) is deliberately configured for infrequent refetching: + `staleTime` 5 min, `gcTime` 30 min, `refetchOnWindowFocus/Mount/Reconnect` all off, `retry: 1`. + Don't override this per-query without a reason. +- After a mutation, update the query cache with `setQueryData` (see `useAssegnaTurno` in + `src/lib/palloni.ts` for the pattern) rather than `invalidateQueries`, to avoid an extra read. +- Stats/badges/standings are "write once, read many": computed and persisted once (e.g. at match + end), never recomputed on every page open. +- Live match scouting: only the scoring user writes; everyone else reads already-saved data. +- CSI league data is synced periodically server-side into a local table; the app only ever reads + from the internal DB, never the CSI site directly. +- Push notifications only for high-value events (convocations, training/match reminders, ball-duty + turn, final result) — no chat/photo/video features. + +### Auth + +Supabase Auth (GoTrue), attached via middleware rather than per-request boilerplate — see +`auth-attacher.ts` / `auth-middleware.ts` above. Self-hostable; not tied to Lovable-proprietary +auth. + +## Project memory (`mem/`) + +`mem/index.md` indexes feature-level design notes (`mem/features/*.md`) — currently the portability +rule and the cloud-efficiency rules summarized above. Check there before adding a feature that +might conflict with either constraint. + +## Conventions + +- **Language: Italian.** Code comments and git commit messages must be written in Italian, matching + the rest of the codebase (routes, identifiers, existing comments/commits are already Italian). +- Path alias `@/*` → `src/*` (see `tsconfig.json`). +- Prettier: 100-char width, double quotes (`singleQuote: false`), trailing commas everywhere. +- TypeScript strict mode plus extra strictness: `noUncheckedIndexedAccess`, + `exactOptionalPropertyTypes`, `noImplicitReturns`, `noImplicitOverride`, + `noPropertyAccessFromIndexSignature`. +- `vite.config.ts` is intentionally minimal: `@lovable.dev/vite-tanstack-config` already bundles + TanStack devtools, `tanstackStart`, `viteReact`, `tailwindcss`, `tsConfigPaths`, nitro, env + injection, and the `@` alias — do not re-add any of those plugins manually or the app breaks with + duplicate plugins.