davideandClaude Sonnet 5 839db3d4ca Invio best-effort il risultato dello scout finalizzato a Strapi
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>
2026-08-28 15:39:46 +02:00
2026-08-06 08:36:47 +02:00
2026-08-06 08:36:47 +02:00
2026-08-06 08:36:47 +02:00

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:

  1. Dominio/DNS: un solo hostname pubblico basta — Caddyfile.example instrada /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.
  2. Stack Supabase self-hosted:
    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
    
    Modifica nel .env appena 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 -d
    
    docker-compose.prod.yml fa due cose, pensate anche per girare su hardware limitato (es. Raspberry Pi 4): non espone porte pubblicamente (solo 127.0.0.1, dietro il reverse proxy — vedi Caddyfile.example nella stessa cartella), e disattiva i servizi Supabase che CrAPP non usa (Realtime, Storage, imgproxy, Edge Functions, pooler) — restano solo db, auth, rest, api-gw, più studio+meta per guardare/gestire il database via interfaccia grafica (raggiungibile su <dominio>/api, con le credenziali DASHBOARD_USERNAME/ DASHBOARD_PASSWORD). Da 11 container si scende a 6.
  3. 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
    
  4. 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:
    docker 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/.env
    
    Compila in infra/strapi/.env i secret (APP_KEYS, JWT_SECRET, ecc. — genera ognuno con openssl rand -base64 32) e DATABASE_PASSWORD (la stessa scelta sopra), poi:
    cd infra/strapi
    docker compose up -d --build
    
    Al primo accesso su <dominio>/cms/admin crea 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 abilita find/findOne per Giocatore, Riga-classifica e Match-storico; poi in Settings → API Tokens genera un token con permesso create solo su Scout-match-finale (va in STRAPI_WRITE_TOKEN nell'env dell'app, punto 5). Infine inserisci a mano rosa/classifica/storico nelle rispettive collezioni (i valori di partenza sono nella cronologia git di src/lib/crapp-data.ts, prima che venissero spostati qui).
  5. Reverse proxy TLS: copia infra/supabase/docker/Caddyfile.example in Caddyfile, sostituisci il dominio del punto 0, poi caddy run --config Caddyfile (o come container). Gestisce automaticamente il certificato Let's Encrypt.
  6. Env dell'app:
    cp .env.production.example .env
    
    Compila VITE_SUPABASE_URL (dominio del punto 0 + /api), VITE_SUPABASE_PUBLISHABLE_KEY (= ANON_KEY dello 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 chiavi VAPID_* reali (npx web-push generate-vapid-keys).
  7. Build e avvio:
    bun run build
    node .output/server/index.mjs   # ascolta su PORT (default 3000)
    
    Tienilo vivo con un process manager (pm2/systemd) — il Caddy del punto 4 lo espone via TLS sull'hostname app.
  8. Job pianificati — gli endpoint src/routes/api/public/promemoria-palloni.ts e sollecita-presenze.ts vanno richiamati periodicamente via HTTP POST da un cron di sistema o pg_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.

S
Description
App del CRAP, ottimizzazione di sporteasy adattata alle esigenze della squadra, campionato e extra
https://crapp-iv11.vercel.app
Readme
2.3 MiB
Languages
TypeScript 94.4%
PLpgSQL 3.5%
CSS 1.8%
JavaScript 0.3%