Introduce lo stack Strapi dockerizzato (infra/strapi/), sullo stesso Postgres dello stack Supabase con un database logico separato, dietro Caddy su /cms/*. L'editing dei dati avviene solo nel pannello admin nativo di Strapi. 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.