diff --git a/CLAUDE.md b/CLAUDE.md index 6ff44c6..5992889 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -65,10 +65,11 @@ inspecting the response body and converted into `renderErrorPage()`'s HTML error 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. +- **Never query the database (or the Strapi CMS) 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(...)` or, for + Strapi-backed data, `strapiFetch(...)` from `src/lib/strapi-client.ts` (see `rosa-base.ts`, + `classifica-csi.ts`, `storico-match.ts`). 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, @@ -92,13 +93,20 @@ load-bearing, not style preferences: - 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 currently a **hardcoded placeholder** array in `src/lib/crapp-data.ts` - (`classifica`, `storicoMatch`), explicitly marked "(demo)" in the UI — no real sync exists yet, - this is planned/open work, not an existing pattern to copy. -- A scouted match result (`ScoutMatch`, from `scout.tsx` / `scout-store.ts`) is saved **only to - the scoring device's `localStorage`** (key `crapp-scout-v1`), never to Supabase — only the - in-progress resume state goes to the `scout_live` table. So today a match result is not shared - across devices/users at all. +- Player roster, CSI league standings and match history come from a self-hosted **Strapi CMS** + (`infra/strapi/`, its own Postgres database on the same cluster as Supabase) — editing happens + only in Strapi's own admin panel (`/cms/admin`), never in app UI. The app reads them read-only via + `src/lib/rosa-base.ts` / `classifica-csi.ts` / `storico-match.ts` (long `staleTime`, no polling — + same cloud-efficiency rules apply). Player identity is the stable `codice` field (`g1`, `g2`, …) + on the Strapi `giocatore` content type, **not** Strapi's own numeric id — every Supabase table + that references a player by id (`pagelle_voti`, `cacche_partita`, MVP votes, ball-duty turns, + presenze, scout actions) keys on that string, so it must never change for an existing player. +- A scouted match result (`ScoutMatch`, from `scout.tsx` / `scout-store.ts`) is saved to the + scoring device's `localStorage` (key `crapp-scout-v1`, still the source `useRosa`/ + `giocatoriConScout` read for stats) **and** pushed best-effort to Strapi's `scout-match-finale` + content type via `/api/public/scout-finale` at match end, so it becomes visible cross-device in + the admin panel — no retry if that POST fails, the local save already succeeded either way. The + in-progress resume state still goes only to the `scout_live` Supabase table, unrelated to Strapi. - Push notifications only for high-value events (convocations, training/match reminders, ball-duty turn, final result) — no chat/photo/video features. diff --git a/docs/PORTABILITA.md b/docs/PORTABILITA.md index 961e5d2..3234b14 100644 --- a/docs/PORTABILITA.md +++ b/docs/PORTABILITA.md @@ -15,6 +15,7 @@ senza dipendere da servizi esclusivi di Lovable Cloud. | Auth | Sì | GoTrue self-hosted oppure qualsiasi provider OIDC. | | `src/integrations/lovable/*` | Opzionale | Login social gestito da Lovable: **non importato da nessuna schermata**, rimovibile senza impatti. | | `@lovable.dev/vite-tanstack-config` | Solo build | Preset Vite; sostituibile con una config Vite/TanStack esplicita. | +| CMS Strapi (`infra/strapi/`) | Sì | Open source e self-hostable, Postgres come backend; l'app lo consuma solo via `src/lib/strapi-client.ts`. | ## Regole da rispettare nelle prossime modifiche diff --git a/mem/features/cloud-efficienza.md b/mem/features/cloud-efficienza.md index 66e449f..c51511e 100644 --- a/mem/features/cloud-efficienza.md +++ b/mem/features/cloud-efficienza.md @@ -8,7 +8,8 @@ type: feature - Dopo una mutazione aggiornare la cache con `setQueryData`, non `invalidateQueries` (evita riletture). - Scout live: scrive solo l'utente che segna; gli altri leggono dati già salvati. - Statistiche, badge e classifiche: "write once, read many" — calcolate e salvate una volta a fine partita, mai ricalcolate a ogni apertura pagina. -- Dati CSI: al momento è un array hardcoded in `src/lib/crapp-data.ts`, marcato "(demo)" in UI — nessun sync reale, da implementare. Anche il risultato di una partita scoutata (`ScoutMatch`) oggi vive solo nel `localStorage` del dispositivo di chi scouta, non su Supabase. +- Rosa giocatori, classifica CSI e storico partite vengono ora dal CMS Strapi (`infra/strapi/`, letto via `src/lib/rosa-base.ts`/`classifica-csi.ts`/`storico-match.ts`), non più da array hardcoded — editing solo dall'admin panel Strapi, l'app resta sola lettura (più una scrittura best-effort per lo scout finalizzato, vedi sotto). Cache lunga (staleTime 60 min): questi dati cambiano a stagione/giornata, non a sessione. +- Il risultato di una partita scoutata (`ScoutMatch`) resta salvato anzitutto nel `localStorage` del dispositivo di chi scouta (fonte usata da `useRosa`/`giocatoriConScout` per le statistiche), e viene *anche* inviato best-effort a Strapi (`scout-match-finale`, via `/api/public/scout-finale`) a fine partita per restare visibile cross-device nell'admin panel — nessun retry se il device non ha rete in quel momento. - Push solo per eventi importanti: convocazioni, promemoria allenamento/partita, turno palloni, esito finale. - Niente foto/video/chat o funzionalità pesanti. - Schema target: team_id, eventi, presenze, azioni_scout, statistiche_aggregate, classifica_csi, notifiche, con indici sui campi di filtro/relazione.