Webapp open source per lo scrutinio in diretta delle elezioni comunali: React sul frontend, API PHP + SQLite sul backend (gira su qualsiasi hosting PHP condiviso, nessun database MySQL da configurare).
📖 Guida utente — come si usa, dalla configurazione alla sera dello scrutinio, con tutti gli scenari.
🚀 Demo online — prova l'app senza installare nulla.
L'app è pensata per le elezioni di sindaco e consiglio comunale nei comuni italiani fino a 15.000 abitanti (sistema maggioritario, art. 71 TUEL):
- ogni candidato sindaco è collegato a una sola lista di candidati consiglieri;
- l'elettore vota la lista e può esprimere preferenze per i consiglieri (una; due con doppia preferenza di genere nei comuni sopra i 5.000 abitanti);
- è eletto sindaco chi prende più voti (maggioranza semplice, turno unico: il ballottaggio esiste solo in caso di parità assoluta);
- alla lista del sindaco eletto vanno 2/3 dei seggi del consiglio, i restanti alle altre liste in proporzione (i candidati sindaco sconfitti entrano in consiglio se la loro lista conquista almeno un seggio);
- i consiglieri sono eletti in base alle preferenze; a parità vale l'ordine di lista;
- con una lista unica, l'elezione è valida solo se vota almeno il 50% degli aventi diritto e la lista ottiene almeno il 50% dei voti dei votanti.
La dashboard applica queste regole in tempo reale: banner del candidato in vantaggio (o eletto, a scrutinio concluso), proiezione del riparto seggi con i nomi dei consiglieri eletti, e indicatore del quorum nel caso di lista unica. La proiezione è indicativa: non sostituisce i verbali ufficiali e non gestisce i casi particolari (ricorsi, ricalcoli, surroghe).
- Dashboard pubblica (
/) — risultati live per maxischermo o browser, aggiornati automaticamente ogni 4 secondi e divisi in tre schede alternabili durante la proiezione: Risultati (totali, affluenza, barra percentuale, tabella per sezione, banner del candidato in vantaggio), Preferenze (classifica dei candidati per lista) e Proiezione (vincitore in grande, riparto seggi con i nomi degli eletti, quorum lista unica). La scheda attiva è nell'URL (es./#proiezione), comodo per aprire il maxischermo sulla vista giusta. Tema chiaro/scuro con switch (default: segue il sistema). - Pagina operatore (
/s/<token>) — l'incaricato in ogni sezione, dal proprio smartphone, incrementa/decrementa i voti di lista, le preferenze ai candidati (nell'ordine di lista), bianche e nulle, e imposta elettori e votanti. Per le correzioni non serve premere +/− tante volte: un tocco sul numero (✎) apre la modifica diretta del totale. L'URL contiene un token segreto: solo chi riceve il link può modificare i dati della sua sezione. - Pannello admin (
/admin) — protetto da password. Al primo avvio parte un wizard di configurazione: dati dell'elezione, seggi del consiglio (tendina con i casi di legge, o valore manuale per le Regioni a Statuto speciale), numero variabile di sezioni, liste con numero ufficiale / candidato sindaco / colore / simbolo, candidati consiglieri con ordine di lista, e infine i link (con QR code) da distribuire agli operatori. In seguito: modifica della configurazione, rigenerazione token, flag "scrutinio concluso" (la proiezione diventa risultato), cambio password, azzeramento voti o reset completo, export CSV.
scrutiniolive/
├── api/ API REST in PHP (router unico in index.php, PDO SQLite)
├── data/ creata al primo avvio: database SQLite + simboli caricati (protetta)
├── frontend/ sorgente React (Vite + Tailwind)
├── dist/ build del frontend (generata da `npm run build`)
└── deploy/ template .htaccess per la root del sito
Servono PHP ≥ 8.1 (con estensioni pdo_sqlite e sqlite3, di solito incluse) e Node ≥ 20.
Dalla cartella del progetto:
# terminale 1 — API
php -S 127.0.0.1:8010 api/index.php
# terminale 2 — frontend (proxy /api → :8010 già configurato)
cd frontend
npm install
npm run devApri http://localhost:5173/admin e segui il wizard.
Nota — dati demo locali: non esiste una password "di default" dell'app; la password admin viene creata da te al primo avvio del wizard. Il database demo incluso in questo repo (
data/elezioni.sqlite, creato durante i test) usa però la passwordsegreta1. Per ripartire da zero con una password tua, eliminadata/elezioni.sqlitee ricarica/admin.
cd frontend && npm run build→ generadist/- Carica sul server, nella document root del sito:
- il contenuto di
dist/(index.html + assets/) - la cartella
api/così com'è deploy/htaccess-root.txtrinominato in.htaccess
- il contenuto di
- La cartella
data/viene creata automaticamente accanto adapi/al primo accesso e contiene già un.htaccessconRequire all denied; se la crei a mano, copia dentro quel file. Verifica che PHP possa scriverci (permessi 755/775 a seconda dell'hosting). - Apri
https://tuosito.it/admin, imposta la password e configura l'elezione.
Layout finale sul server:
public_html/
├── .htaccess (da deploy/htaccess-root.txt)
├── index.html (da dist/)
├── assets/ (da dist/)
├── api/ (.htaccess + index.php + src/)
└── data/ (creata da PHP: elezioni.sqlite, symbols/)
Se l'app non sta nella radice del sito ma in una sottocartella (es.
https://miosito.it/ScrutinioLive), segui gli stessi 4 passi qui sopra, con
due sole differenze:
-
al passo 1 la build va fatta indicando il percorso della sottocartella — altrimenti la pagina resta bianca, perché gli asset vengono cercati nella radice del sito:
cd frontend VITE_BASE=/ScrutinioLive/ npm run build -
al passo 2 carichi tutto dentro la sottocartella anziché nella document root:
public_html/ └── ScrutinioLive/ ├── .htaccess (da deploy/htaccess-root.txt) ├── index.html + assets/ (da dist/) ├── api/ └── data/ (creata da PHP)
L'app sarà su https://miosito.it/ScrutinioLive (admin:
https://miosito.it/ScrutinioLive/admin). Rotte, chiamate API e link QR degli
operatori si adattano da soli al percorso indicato nella build.
Consigli per la sera dello scrutinio:
- Usa HTTPS: i token di sezione viaggiano nell'URL.
- Fai una prova generale qualche giorno prima, poi "Strumenti → Azzera i voti".
- Backup = scaricare il file
data/elezioni.sqlite.
Due strade dal pannello, tab Strumenti:
- Azzera i voti — tiene sezioni, liste ed elettori, azzera solo i conteggi. Ideale dopo la prova generale.
- Azzera tutto — elimina sezioni, liste, candidati, voti, impostazioni e simboli (resta solo la password admin) e riapre il wizard di configurazione. Ideale per un'elezione completamente nuova.
In alternativa elimina data/elezioni.sqlite: riparte tutto da zero, password
compresa.
ScrutinioLive è distribuito con licenza MIT: puoi usarlo, modificarlo e ridistribuirlo liberamente, anche per scopi commerciali, a condizione di mantenere la nota di copyright e la licenza (i credits) in ogni copia o porzione sostanziale del software.
Il progetto è nato per lo scrutinio live delle elezioni comunali di Alessano (LE) del 2021 ed è stato riscritto e generalizzato nel 2026 per qualsiasi comune italiano fino a 15.000 abitanti.
Se lo usi per lo spoglio del tuo comune, un saluto o una segnalazione fa sempre piacere!