📘 Documentazione tecnica
Dalla demo
all'applicazione reale
Guida completa per trasformare il prototipo ASSOCIAZIONE DEMO in un'applicazione web funzionante, sicura e scalabile.
Versione1.0.0
DataMaggio 2026
LivelloSviluppatore junior+
Tempo stimato4–8 settimane
01 · Panoramica

Cos'è questa applicazione

Il prototipo demo è costruito in HTML/React puro con dati fittizi. Per renderlo funzionante servono un backend, un database, un sistema di autenticazione e un'infrastruttura di deploy.

📱 Frontend (già pronto)

React + DM Sans, 9 sezioni, grafici SVG, ricerca globale, bilingue IT/EN, responsive. Da collegare a un backend reale.

⚙️ Backend (da costruire)

API REST che gestisce soci, quote, eventi, turni, documenti, bilancio, comunicazioni. Autenticazione con ruoli.

🗄️ Database (da configurare)

Schema relazionale con tabelle per soci, pagamenti, eventi, iscrizioni, turni, transazioni, documenti.

☁️ Infrastruttura (da scegliere)

Hosting, dominio, SSL, backup automatici, storage file, invio email transazionale.

💡
Il frontend React della demo è già ben strutturato e riutilizzabile. L'80% del lavoro sarà costruire il backend e collegarlo tramite chiamate API.

02 · Stack tecnologico

Stack consigliato

Stack moderno, open source, con ampia documentazione e community attiva. Ideale per team piccoli con budget limitato.

🖥️ Frontend

⚛️
React 18 + Vite
Già usato nel prototipo. Migrare da Babel CDN a build Vite per performance ottimali.
Frontend
🔷
TypeScript
Aggiunge tipizzazione statica, riduce i bug e migliora l'esperienza di sviluppo.
Consigliato
🌿
React Query (TanStack)
Gestione cache e sincronizzazione dati server-side. Sostituisce useState per i dati remoti.
State
🛣️
React Router v6
Routing client-side con URL leggibili (es. /soci/123), protetto da auth guard.
Routing

⚙️ Backend

🟢
Node.js + Express
Opzione A: leggero, flessibile, JavaScript ovunque. Ottimo per team che già conoscono JS.
Opzione A
🐍
Python + FastAPI
Opzione B: moderno, veloce, documentazione OpenAPI automatica. Ideale per funzionalità AI future.
Opzione B

🗄️ Database

🐘
PostgreSQL
Database relazionale robusto e gratuito. Supporta JSON, full-text search, trigger e molto altro.
Principale
🔴
Redis
Cache in-memory per sessioni utente, rate limiting e code di job per invio email.
Cache

☁️ Servizi cloud

📁
AWS S3 / Cloudflare R2
Storage documenti e allegati. R2 è più economico per piccole associazioni.
📧
Resend / SendGrid
Invio email transazionali (solleciti quote, conferme eventi, newsletter).
💳
Stripe
Pagamento quote online, donazioni, iscrizione eventi con carta o bonifico.

03 · Architettura

Struttura del progetto

Architettura monorepo con frontend e backend separati, comunicanti tramite API REST JSON.

Struttura cartelle
# Monorepo
associazione-app/
├── frontend/               # React + Vite
│   ├── src/
│   │   ├── components/     # Badge, Card, Modal, ecc.
│   │   ├── pages/          # Dashboard, Soci, Quote, ...
│   │   ├── hooks/          # useSoci, useEventi, ...
│   │   ├── api/            # client fetch, react-query
│   │   ├── i18n/           # traduzioni IT/EN
│   │   └── App.tsx
│   └── package.json
│
├── backend/                # Node.js + Express
│   ├── src/
│   │   ├── routes/         # /api/soci, /api/eventi, ...
│   │   ├── controllers/    # logica business
│   │   ├── models/         # schema Prisma/Sequelize
│   │   ├── middleware/     # auth, validazione, rate limit
│   │   ├── services/       # email, storage, pagamenti
│   │   └── app.js
│   └── package.json
│
├── database/
│   ├── migrations/         # versioni schema DB
│   └── seeds/              # dati iniziali demo
│
└── docker-compose.yml      # PostgreSQL + Redis locali

Flusso dati

Browser → Frontend React
L'utente interagisce con l'interfaccia. React Query gestisce il fetching e la cache dei dati.
Frontend → API REST
Chiamate HTTP con JWT token nell'header Authorization. Es: GET /api/soci?stato=attivo
API → Database PostgreSQL
Il controller valida la richiesta, esegue la query SQL tramite ORM (Prisma) e restituisce JSON.
Servizi asincroni
Job in background (Redis/BullMQ) per email, PDF, solleciti automatici. Non bloccano la risposta API.

04 · Database

Schema del database

Schema PostgreSQL normalizzato. Le relazioni tra tabelle garantiscono integrità referenziale.

tabella: soci
campotiponote
idPKUUIDIdentificatore univoco
nomeVARCHAR(100)Nome completo
emailVARCHAR(200)Unique, usata per login
telefonoVARCHAR(20)Opzionale
tesseraVARCHAR(20)Auto-generata: YYYY-NNN
ruoloENUMordinario, volontario, direttivo, presidente
statoENUMattivo, inattivo, sospeso
data_iscrizioneDATEData prima iscrizione
created_atTIMESTAMPAuto-gestito dall'ORM
tabella: pagamenti
campotiponote
idPKUUID
socio_idFKUUID→ soci.id
annoINTEGERAnno di riferimento quota
importoDECIMAL(8,2)In euro
statoENUMda_pagare, pagato, scaduto
metodoENUMcontanti, bonifico, pos, stripe
data_pagamentoDATENULL se non ancora pagato
stripe_idVARCHAR(100)ID pagamento Stripe, opzionale
tabelle: eventi + iscrizioni_eventi
campotiponote
idPKUUIDEvento
titoloVARCHAR(200)
data_oraTIMESTAMPData e ora di inizio
luogoTEXTIndirizzo testuale
categoriaENUMvolontariato, formazione, sociale...
max_iscrittiINTEGERNULL = illimitato
— iscrizioni_eventi —tabella di join M:N
evento_idFKUUID→ eventi.id
socio_idFKUUID→ soci.id
statoENUMconfermata, in_attesa, annullata
🔗
Usare un ORM come Prisma (Node.js) o SQLAlchemy (Python) per gestire le migrazioni e non scrivere SQL grezzo. Le migrazioni versionate permettono di evolvere lo schema senza perdere dati.

05 · API REST

Endpoint principali

Tutte le API restituiscono JSON. Prefisso base: /api/v1. Autenticazione tramite Bearer token JWT.

MetodoEndpointDescrizioneAuth
GET/sociLista soci (filtri: stato, ruolo, search)
GET/soci/:idDettaglio singolo socio
POST/sociCrea nuovo socioAdmin
PUT/soci/:idAggiorna dati socioAdmin
GET/eventiLista eventi (filtri: data, categoria)
POST/eventi/:id/iscriviIscrivi socio a evento
GET/pagamentiLista pagamenti (filtri: anno, stato)Admin
POST/pagamenti/:id/registraSegna quota come pagataAdmin
GET/turniLista turni (filtri: data, stato)
POST/turni/:id/assegnaAssegna volontario a turnoAdmin
GET/bilancio/transazioniLista transazioni + saldoAdmin
POST/comunicazioni/inviaInvia email/newsletterAdmin
GET/documentiLista documenti
POST/documenti/uploadCarica nuovo documento (multipart)Admin
GET/dashboard/statsKPI aggregati per dashboardAdmin

Esempio di risposta

JSON
// GET /api/v1/soci?stato=attivo&page=1&limit=20
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716",
      "nome": "Marco Rossi",
      "email": "marco.rossi@email.it",
      "tessera": "2026-001",
      "ruolo": "volontario",
      "stato": "attivo",
      "quota_pagata": true
    }
  ],
  "meta": {
    "total": 8,
    "page": 1,
    "limit": 20,
    "pages": 1
  }
}

06 · Autenticazione

Sistema di accesso e ruoli

Autenticazione stateless con JWT (JSON Web Token). Tre livelli di accesso con permessi distinti.

👑 Amministratore

Accesso completo. Gestione soci, quote, bilancio, documenti, comunicazioni, impostazioni.

🧑‍💼 Direttivo

Vede tutto tranne il bilancio dettagliato. Può creare eventi e gestire i turni.

🙋 Socio / Volontario

Vede solo i propri dati, eventi pubblici, turni assegnati. Può iscriversi agli eventi.

Flusso di login

Node.js + JWT
// POST /api/v1/auth/login
const login = async (req, res) => {
  const { email, password } = req.body;
  
  // 1. Trova utente nel DB
  const utente = await prisma.soci.findUnique({ where: { email } });
  if (!utente) return res.status(401).json({ error: "Credenziali non valide" });
  
  // 2. Verifica password con bcrypt
  const ok = await bcrypt.compare(password, utente.password_hash);
  if (!ok) return res.status(401).json({ error: "Credenziali non valide" });
  
  // 3. Genera JWT (scade in 7 giorni)
  const token = jwt.sign(
    { id: utente.id, ruolo: utente.ruolo },
    process.env.JWT_SECRET,
    { expiresIn: "7d" }
  );
  
  res.json({ token, utente: { id: utente.id, nome: utente.nome, ruolo: utente.ruolo } });
};
⚠️
Mai salvare la password in chiaro. Usare bcrypt con salt round ≥ 12. Il JWT secret deve essere una stringa random lunga 64+ caratteri, salvata in variabile d'ambiente.

07 · Moduli funzionali

Come implementare ogni sezione

👥 Gestione Soci

💳 Quote e Pagamenti

📅 Eventi e Iscrizioni

📁 Documenti

💰 Bilancio


08 · Notifiche & Email

Sistema di comunicazioni automatiche

🔔 Notifiche in-app

Usare WebSocket (Socket.io) o Server-Sent Events per notifiche real-time. Oppure polling ogni 30 secondi per semplicità iniziale.

📧 Email transazionali

Servizi consigliati: Resend (gratis fino a 3.000 email/mese) o SendGrid. Configurare SPF, DKIM, DMARC per evitare lo spam.

Job schedulati (cron)

node-cron
import cron from 'node-cron';

// Ogni giorno alle 9:00 — sollecito quote scadute
cron.schedule('0 9 * * *', async () => {
  const morosi = await prisma.pagamenti.findMany({
    where: { stato: 'da_pagare', anno: new Date().getFullYear() }
  });
  for (const p of morosi) {
    await sendEmail(p.socio.email, 'sollecito-quota', { anno: p.anno });
  }
});

// Ogni giorno alle 8:00 — reminder evento domani
cron.schedule('0 8 * * *', async () => {
  const domani = new Date();
  domani.setDate(domani.getDate() + 1);
  const eventi = await prisma.eventi.findMany({
    where: { data_ora: { gte: domani, lt: addDays(domani, 1) } },
    include: { iscrizioni: { include: { socio: true } } }
  });
  // invia reminder a ogni iscritto...
});

09 · Deploy

Mettere online l'applicazione

Due opzioni principali: soluzione fully managed (più semplice) o VPS self-hosted (più economica nel lungo periodo).

Opzione A — Fully managed (consigliato per iniziare)

Frontend → Vercel

Deploy automatico da GitHub. CDN globale, SSL incluso, preview per ogni PR. Piano gratuito sufficiente.

Backend → Railway / Render

Hosting Node.js con PostgreSQL e Redis inclusi. ~€7–15/mese. Deploy da Git push.

Storage → Cloudflare R2

10 GB gratuiti, poi ~€0.015/GB. Nessun costo di egress. Compatibile S3.

Email → Resend

3.000 email/mese gratuite. API semplice, template React Email, webhook delivery.

Opzione B — VPS self-hosted (per budget molto limitati)

Docker Compose
# docker-compose.prod.yml
services:
  nginx:
    image: nginx:alpine
    ports: ["80:80", "443:443"]
    volumes: ["./nginx.conf:/etc/nginx/nginx.conf"]

  backend:
    build: ./backend
    environment:
      DATABASE_URL: postgres://user:pass@db:5432/associazione
      JWT_SECRET: "your-64-char-random-secret"
      RESEND_API_KEY: "re_..."

  db:
    image: postgres:16-alpine
    volumes: ["pgdata:/var/lib/postgresql/data"]
    environment:
      POSTGRES_DB: associazione
      POSTGRES_PASSWORD: "strong-password-here"

  redis:
    image: redis:7-alpine

volumes:
  pgdata:
💰
Un VPS da €5/mese (Hetzner CX22, 4GB RAM) regge tranquillamente fino a 500 soci e 1.000 richieste/giorno. Usare Caddy come reverse proxy per SSL automatico gratuito con Let's Encrypt.

Passi per il primo deploy

Registra dominio
Acquista un dominio (es. gestioneassociazione.it) su Aruba, Register.it o Namecheap (~€15/anno).
Crea repository Git
Inizializza un repo GitHub privato con il codice frontend + backend. Aggiungi .gitignore per escludere .env.
Configura variabili d'ambiente
Su Railway/Render, aggiungi DATABASE_URL, JWT_SECRET, RESEND_API_KEY, CLOUDFLARE_R2_KEY nel pannello secrets.
Esegui le migrazioni DB
npx prisma migrate deploy per creare le tabelle. Poi npx prisma db seed per i dati iniziali.
Deploy frontend su Vercel
Collega il repo GitHub, imposta VITE_API_URL=https://api.tuo-dominio.it. Deploy automatico a ogni push su main.
Configura DNS
Punta il dominio a Vercel (frontend) e al server backend. Aggiungi record MX/SPF/DKIM per le email.

10 · Sicurezza

Best practice di sicurezza

⚖️
GDPR: i dati dei soci sono dati personali. Servono: informativa privacy, consenso al trattamento, diritto alla cancellazione, registro trattamenti. Consulta un legale o usa un template per APS/ODV italiane.

11 · Manutenzione

Gestione nel tempo

Monitoraggio

📊 Uptime monitoring

UptimeRobot (gratuito) per notifiche se il server va down. Controlla ogni 5 minuti e avvisa via email/Telegram.

🐛 Error tracking

Sentry (piano free sufficiente) per tracciare errori JS frontend e eccezioni backend con stack trace completo.

Aggiornamenti annuali

Gennaio — Rinnovo quote
Il job automatico crea i record quota per il nuovo anno. Verificare che tutti i soci ricevano l'email di invito al rinnovo.
Febbraio/Marzo — Bilancio consuntivo
Esportare il bilancio dell'anno precedente in XLSX, generare il verbale di approvazione, archiviarlo nella sezione Documenti.
Ogni 3 mesi — Aggiornamenti dipendenze
Eseguire npm audit e aggiornare le librerie con vulnerabilità note. Testare in staging prima di deployare.
Ogni anno — Rinnovo SSL e dominio
Let's Encrypt si rinnova automaticamente. Verificare la scadenza del dominio e rinnovarlo con anticipo.

12 · Roadmap

Fasi di sviluppo consigliate

FaseDurataObiettiviCosto est.
Fase 1 — MVP 2–3 settimane Login, CRUD soci, quote manuali, documenti base €0–200
Fase 2 — Core 2–3 settimane Eventi + iscrizioni, turni, bilancio, email automatiche €100–500
Fase 3 — Avanzata 2–4 settimane Stripe, newsletter, PDF, export, ruoli granulari €200–800
Fase 4 — Ops 1–2 settimane Monitoring, backup, GDPR, documentazione utente €0–200
🚀
Consiglio: inizia dalla Fase 1 e mettila in produzione il prima possibile con utenti reali. Il feedback early è più prezioso della perfezione tecnica. Puoi sempre aggiungere funzionalità in seguito.

Alternative pronte all'uso

Se il budget di sviluppo è limitato, considera soluzioni SaaS esistenti già configurate per associazioni italiane:

🏛️ Asso.it / GestAss

Software italiano specifico per APS/ODV. Già conformi GDPR e normativa fiscale. ~€15–50/mese.

🌐 Wild Apricot / Raklet

SaaS internazionale per gestione associazioni. Potente ma in inglese. Piano free fino a 50 soci.

Pronto per iniziare?
Il frontend della demo è già scritto. Inizia dal backend e collega le API una sezione alla volta.
1. Setup DB + Prisma 2. API soci + auth 3. Collega frontend 4. Deploy