Nuova route server /api/public/scout-finale: proxy verso il content type scout-match-finale con un token Strapi di sola scrittura, mai esposto al client. Il salvataggio in localStorage (già chiamato da finePartita() in scout.tsx nel commit precedente) resta la fonte per le statistiche; questo invio è additivo e non bloccante, se fallisce la partita resta comunque salvata sul device come già accadeva prima. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
CrAPP — CRAP Volley Hub
App mobile-first per la gestione della squadra amatoriale di pallavolo CRAP Volley: presenze, partite/allenamenti/eventi, scouting live, statistiche giocatori, badge, classifica CSI, notifiche push.
Progetto avviato con Lovable: i push su main sincronizzano l'editor
Lovable, quindi si evita di riscrivere la history già pubblicata (niente force-push,
rebase/amend/squash di commit già pushati).
Live app: https://volley-cronos-app.lovable.app
Stack
- TanStack Start (React 19, routing file-based) + Vite
- Tailwind v4 + componenti shadcn/radix
- Supabase (
@supabase/supabase-js) per dati e auth - TanStack Query per la cache client
Funzionalità
- Presenze: RSVP rapido (presente / assente / forse / in ritardo / infortunato) su ogni evento
- Eventi: partite, allenamenti, eventi sociali, con calendario e lista
- Scouting live: registrazione azioni punto-per-punto durante la partita (riservato agli admin)
- Statistiche giocatori: presenze totali/consecutive, badge, obiettivi squadra, medie pagelle
- Votazioni post-partita: MVP, pagelle 1-10 tra compagni, voti "social"/goliardici
- Turno palloni: rotazione automatica di chi porta i palloni, con promemoria push
- Classifica CSI: al momento un dato demo hardcoded (vedi CLAUDE.md), sync reale ancora da implementare
- Notifiche push: convocazioni, promemoria allenamento/partita, turno palloni, esito finale
Sviluppo (locale)
Package manager: bun (installazione).
git clone https://github.com/ivancacciari1995-a11y/CRAPP.git
cd CRAPP
bun install
1. Avvia un backend Supabase
Serve un'istanza Supabase (cloud o self-hosted) a cui puntare. Per lavorare in locale senza
toccare dati reali, nel repo c'è uno stack self-hosted pronto in infra/supabase/docker/:
cd infra/supabase/docker
cp .env.example .env
sh utils/generate-keys.sh --update-env # genera JWT_SECRET, ANON_KEY, SERVICE_ROLE_KEY, ecc.
Poi avvia lo stack (con docker-compose.prod.yml si tengono su solo i servizi che CrAPP usa
davvero — vedi la sezione Produzione più sotto):
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
docker compose ps # verifica che tutti i container siano "healthy"
Applica le migrazioni del progetto al database appena creato:
cd ../../.. # torna alla root del repo
for f in supabase/migrations/*.sql; do
docker exec -i supabase-db psql -U postgres -d postgres -v ON_ERROR_STOP=1 < "$f"
done
2. Configura .env di CrAPP
Nella root del repo, crea .env con le chiavi lette da infra/supabase/docker/.env:
VITE_SUPABASE_URL=http://localhost:8000
VITE_SUPABASE_PUBLISHABLE_KEY=<ANON_KEY dello stack self-hosted>
SUPABASE_SERVICE_ROLE_KEY=<SERVICE_ROLE_KEY dello stack self-hosted>
Facoltative per testare le notifiche push (senza non si rompe nulla, semplicemente niente push):
VAPID_PUBLIC_KEY=...
VAPID_PRIVATE_KEY=...
VAPID_SUBJECT=mailto:tuamail@esempio.it
3. Avvia l'app
bun run dev # http://localhost:8080
Le tabelle sono vuote al primo avvio: crea un giocatore/evento dall'app stessa per avere dati di
test. Dashboard Supabase Studio raggiungibile su http://localhost:8000 (credenziali
DASHBOARD_USERNAME/DASHBOARD_PASSWORD in infra/supabase/docker/.env).
Altri comandi:
bun run build:dev # build in modalità development
bun run preview # anteprima di una build
bun run lint # eslint .
bun run format # prettier --write .
Non è configurato un test runner.
Produzione (self-hosted, Node + Docker)
bun run build usa Nitro (tramite @lovable.dev/vite-tanstack-config), che di default
compilerebbe per Cloudflare Workers — in vite.config.ts il preset è forzato a
node-server per generare un server Node standard, deployabile su qualunque host (coerente con
docs/PORTABILITA.md).
Passo passo, sul server di produzione:
- Dominio/DNS: un solo hostname pubblico basta —
Caddyfile.exampleinstrada/api/*verso il gateway Supabase (path stripped) e tutto il resto verso l'app, sullo stesso dominio.- Con un dominio vero (DNS proprio):
tuodominio.it. - Con un dominio gratuito No-IP (
ddns.net, ecc.): un hostname singolo basta e avanza (il piano free ne dà fino a 3, ma qui ne serve uno solo), es.crapp.ddns.net. - Serve un client DDNS attivo sul server (o supporto nel router) che aggiorni l'IP: gli hostname No-IP gratuiti scadono dopo ~30 giorni di inattività se non confermati.
- Verifica di non essere dietro CGNAT (IP pubblico condiviso dall'ISP): in quel caso nessuna porta è raggiungibile da internet e serve un tunnel (es. Cloudflare Tunnel) al posto dell'esposizione diretta.
- Con un dominio vero (DNS proprio):
- Stack Supabase self-hosted:
Modifica nel
cp infra/supabase/docker/.env.production.example infra/supabase/docker/.env cd infra/supabase/docker sh utils/generate-keys.sh --update-env # secret NUOVI, non riusare quelli di sviluppo.envappena creato:SUPABASE_PUBLIC_URL/API_EXTERNAL_URL(dominio del punto 0 +/api),SITE_URL(dominio del punto 0),DASHBOARD_PASSWORD, e l'SMTP se servono email vere. Poi avvia:docker compose -f docker-compose.yml -f docker-compose.prod.yml up -ddocker-compose.prod.ymlfa due cose, pensate anche per girare su hardware limitato (es. Raspberry Pi 4): non espone porte pubblicamente (solo127.0.0.1, dietro il reverse proxy — vediCaddyfile.examplenella stessa cartella), e disattiva i servizi Supabase che CrAPP non usa (Realtime, Storage, imgproxy, Edge Functions, pooler) — restano solodb,auth,rest,api-gw, piùstudio+metaper guardare/gestire il database via interfaccia grafica (raggiungibile su<dominio>/api, con le credenzialiDASHBOARD_USERNAME/DASHBOARD_PASSWORD). Da 11 container si scende a 6. - Migrazioni:
cd ../.. # root del repo for f in supabase/migrations/*.sql; do docker exec -i supabase-db psql -U postgres -d postgres -v ON_ERROR_STOP=1 < "$f" done - Stack Strapi (CMS admin per rosa, classifica, storico partite, scout finalizzato — vedi
infra/strapi/): usa lo stesso Postgres dello stack Supabase, in un database logico separato:Compila indocker exec -i supabase-db psql -U postgres -c "CREATE DATABASE strapi;" docker exec -i supabase-db psql -U postgres -c "CREATE USER strapi WITH PASSWORD '...';" docker exec -i supabase-db psql -U postgres -c "GRANT ALL PRIVILEGES ON DATABASE strapi TO strapi;" cp infra/strapi/.env.production.example infra/strapi/.envinfra/strapi/.envi secret (APP_KEYS,JWT_SECRET, ecc. — genera ognuno conopenssl rand -base64 32) eDATABASE_PASSWORD(la stessa scelta sopra), poi:Al primo accesso sucd infra/strapi docker compose up -d --build<dominio>/cms/admincrea l'utente amministratore Strapi. Da lì, un solo giro di setup manuale (nessuna automazione: i permessi Strapi si abilitano solo dall'admin UI): in Settings → Users & Permissions Plugin → Roles → Public abilitafind/findOneperGiocatore,Riga-classificaeMatch-storico; poi in Settings → API Tokens genera un token con permessocreatesolo suScout-match-finale(va inSTRAPI_WRITE_TOKENnell'env dell'app, punto 5). Infine inserisci a mano rosa/classifica/storico nelle rispettive collezioni (i valori di partenza sono nella cronologia git disrc/lib/crapp-data.ts, prima che venissero spostati qui). - Reverse proxy TLS: copia
infra/supabase/docker/Caddyfile.exampleinCaddyfile, sostituisci il dominio del punto 0, poicaddy run --config Caddyfile(o come container). Gestisce automaticamente il certificato Let's Encrypt. - Env dell'app:
Compila
cp .env.production.example .envVITE_SUPABASE_URL(dominio del punto 0 +/api),VITE_SUPABASE_PUBLISHABLE_KEY(=ANON_KEYdello stack),SUPABASE_SERVICE_ROLE_KEY(=SERVICE_ROLE_KEY),VITE_STRAPI_URL(dominio del punto 0 +/cms),STRAPI_WRITE_TOKEN(il token generato al punto 3), e le chiaviVAPID_*reali (npx web-push generate-vapid-keys). - Build e avvio:
Tienilo vivo con un process manager (pm2/systemd) — il Caddy del punto 4 lo espone via TLS sull'hostname app.
bun run build node .output/server/index.mjs # ascolta su PORT (default 3000) - Job pianificati — gli endpoint
src/routes/api/public/promemoria-palloni.tsesollecita-presenze.tsvanno richiamati periodicamente via HTTP POST da un cron di sistema opg_cron: non partono da soli.
Continuare da Lovable
Il progetto resta modificabile anche dall'editor Lovable:
le modifiche fatte lì vengono committate direttamente su questo repository, e viceversa i push
su main sincronizzano l'editor.
Portabilità
Il progetto è pensato per restare deployabile su un normale server Node.js + PostgreSQL, senza dipendenze esclusive da Lovable Cloud — vedi docs/PORTABILITA.md per lo stato attuale e le regole da rispettare.
Note per chi sviluppa con Claude Code
Vedi CLAUDE.md per architettura dettagliata, convenzioni del repo e vincoli di efficienza sul piano cloud a consumo.