Files
CRAPP/docs/ARCHITECTURE.md
T
davideandClaude Opus 5 26bacbf700 Registra DD-021 e DD-022 e allinea la documentazione
DD-021 (molle interrompibili con motion) e DD-022 (l'app è solo chiara)
motivano le due scelte che un domani sembreranno arbitrarie: perché è entrata
una libreria di animazione dopo averne tolte 45, e perché il tema scuro è
stato cancellato invece che completato.

DD-021 riporta il numero misurato e scomodo: il bundle client cresce da 267 a
308 KB gzip. Togliere dipendenze mai importate non lo riduce, perché il
tree-shaking già le escludeva; il guadagno è sulle 50 dipendenze dirette che
diventano 21.

ARCHITECTURE e README non descrivevano più lo stack reale (Radix/shadcn) e la
sezione UI ignorava la primitiva Card e il sistema di molle. Tolto anche
`hooks/` dall'albero del progetto: la cartella non esiste più.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-05 12:42:55 +02:00

7.0 KiB

Architettura del progetto

Come è fatta CrAPP: stack, organizzazione del codice, flusso di sviluppo. È il documento di riferimento tecnico — CLAUDE.md non ripete questi contenuti, li richiama.

Stack

Livello Tecnologie
Frontend React 19, TypeScript, TanStack Start (SSR), Vite 8, Tailwind CSS 4, motion, vaul
Backend Supabase (PostgreSQL, Auth, Storage)
Hosting Vercel
Versionamento Git, GitHub

Le dipendenze sono installate con bun (bun.lock, bunfig.toml). bunfig.toml impone minimumReleaseAge = 24h come guardia supply-chain: aggiungere un pacchetto a minimumReleaseAgeExcludes richiede conferma esplicita.

Struttura del progetto

src/
  components/   componenti condivisi (crapp/, ui/, motion/)
  routes/       routing file-based
  lib/          logica di dominio, un file per modulo
  integrations/ client Supabase e integrazioni esterne
  assets/
supabase/       migration SQL
test/           suite di test (unit, integration, end-to-end)
docs/           documentazione ufficiale

Punti fermi

  • Routing: file-based in src/routes/. src/routeTree.gen.ts è generato, non si modifica a mano.
  • Configurazione Vite: vite.config.ts usa @lovable.dev/vite-tanstack-config, che include già devtools, tanstackStart, viteReact, tailwind, tsconfig-paths, nitro e l'alias @src/. Non ri-aggiungere questi plugin: l'app si rompe.
  • Entry point server: src/server.ts avvolge l'entry di TanStack Start per intercettare gli errori SSR che h3 trasformerebbe in un 500 JSON silenzioso, e renderizza renderErrorPage(). src/start.ts registra i middleware globali (error handler, CSRF sui server functions, attachSupabaseAuth).
  • Supabase: src/integrations/supabase/client.ts (browser/SSR, chiave publishable — file generato) e client.server.ts (supabaseAdmin, solo server). types.ts è generato dallo schema; finché non viene rigenerato, le tabelle introdotte da M1/M2 si usano tramite client-nuove-tabelle.ts, con i tipi di riga dichiarati nei moduli di src/lib/.
  • Autenticazione: login Google via Supabase Auth (src/lib/auth.ts, DD-011). È l'unica strada di accesso: __root.tsx rimanda a /benvenuto chi non ha sessione, e l'identità del giocatore è lo slot di giocatori_squadra collegato all'account. I permessi di amministrazione arrivano solo da user_roles (src/lib/ruoli.ts).

Livello dati

Tutta la logica di dominio sta in src/lib/, un file per modulo (presenze, eventi, pagelle, mvp-voti, palloni, cacche, badges, scout-*, infortuni, …). Il pattern ricorrente:

  • ogni modulo esporta hook TanStack Query (useX); i default globali stanno in src/router.tsx (staleTime 5 min, gcTime 30 min, refetchOnWindowFocus/Mount/Reconnect disattivati, retry: 1);
  • dopo una mutazione la cache si aggiorna con setQueryData, non con invalidateQueries: invalidare provoca una rilettura e costa una query in più (unica eccezione oggi: scout-live.ts);
  • le funzioni pure di calcolo sono separate dagli hook (es. palloni-core.ts vs palloni.ts, mediePagelle() vs usePagelle());
  • src/lib/rosa.ts è l'aggregatore: compone tutti gli hook e restituisce la rosa completa con le statistiche derivate, senza query aggiuntive rispetto a quelle già in cache. Le route consumano useRosa(), non i singoli moduli.

Nessun accesso al database dai componenti: solo attraverso i moduli in src/lib/, così il backend resta sostituibile in un solo punto (DD-013, PORTABILITA.md).

Vincoli di efficienza cloud — niente polling, cache lunga, setQueryData invece di invalidateQueries — in EFFICIENZA_CLOUD.md.

Badge e statistiche sono calcolati a runtime dai dati, non persistiti (DD-007). La gamification deve restare equa tra ruoli (DD-008).

La rosa vive nella tabella giocatori_squadra, letta tramite useRosa()/useGiocatoriSquadra() (DD-015, DD-016). src/lib/crapp-data.ts (rosaCSI) resta solo come seed storico e fallback quando il database non risponde.

UI

Componenti condivisi in src/components/crapp/ (ui-bits.tsx per Card, PageHeader, Section, StatTile), animazioni in src/components/motion/. Mobile-first (DD-005): poche schermate, pochi click.

In src/components/ui/ restano solo le due primitive shadcn davvero usate, drawer (vaul) e sonner: le altre 43 non erano importate da nessuna parte (DD-021). Il resto dell'interfaccia è composto con Tailwind e la primitiva Card, che è l'unica definizione di raggio, sfondo e ombra delle superfici.

L'app è solo chiara (DD-022): non esiste un tema scuro e :root dichiara color-scheme: light.

Il movimento usa molle interrompibili di motion con i preset in src/lib/molla.ts (DD-021): molla.ui di default, molla.slancio solo dopo un gesto con inerzia, molla.foglio per drawer e cambi di vista. proietta() calcola dove finirebbe un elemento lanciato, così swipe come quello del calendario atterrano dove il gesto stava andando. src/lib/motion.ts conserva solo il rilevamento del movimento ridotto e i coriandoli.

Comandi

npm run dev       # vite dev su http://localhost:8080
npm run build     # build di produzione (nitro)
npm run lint      # eslint (include prettier come regola)
npm run format    # prettier --write .
npm run test      # test unit (veloci, senza rete né database)
npm run test:integration  # route server vere
npm run test:e2e          # percorsi sull'app servita
npm run test:all          # tutto

Database di sviluppo in locale (Docker), alternativo al progetto Supabase cloud:

npx supabase start   # avvia lo stack locale e applica tutte le migration
npx supabase stop    # spegne i container
npx supabase db reset # ricrea il database da zero: migration + supabase/seed.sql
npx supabase db push  # applica le migration al progetto cloud

supabase/seed.sql popola qualche profilo di prova e gira solo in locale. Serve perché il progetto cloud è uno solo, condiviso tra sviluppo e produzione: lo stack locale è il posto dove provare le migration distruttive senza toccare i dati veri.

Branch e flusso di sviluppo

  • main → produzione, deploy automatico su Vercel. È anche il branch di lavoro corrente.
  • develop → preview Vercel; oggi indietro rispetto a main, non rappresenta lo stato attuale.
  • feature/…, fix/…, refactor/… → lavori rischiosi o paralleli.

Su quale branch va un commit lo decide l'utente (DD-019): un assistente AI può consigliare un branch dedicato, non sceglierlo. Poiché si lavora su main, la rete di sicurezza sono i test, che vanno scritti insieme al codice e devono essere verdi (DD-020, test/README.md).