10 KiB
📄 Specifiche API Backend - Focolari Voting System
Questo documento descrive le specifiche che il backend reale deve implementare per funzionare correttamente con il frontend del sistema di controllo accessi.
Versione: 1.0
Data: Gennaio 2026
🌐 Configurazione Server
CORS
Il server deve abilitare CORS con le seguenti impostazioni:
- Origins:
*(o lista specifica di domini autorizzati) - Methods:
GET, POST, OPTIONS - Headers:
Content-Type, Authorization
Serving Frontend
Il backend dovrebbe servire il frontend buildato (file statici) dalla root /.
Questo permette di avere un unico endpoint per frontend e API.
🔑 Meccanismo di Invalidazione Sessioni
Server Start Time
All'avvio, il server deve generare un timestamp univoco (es. Unix timestamp in secondi).
Questo valore viene restituito nell'endpoint /info-room e serve al frontend per invalidare sessioni obsolete.
Comportamento:
- Il frontend salva
server_start_timenella sessione locale - Al caricamento successivo, confronta il valore salvato con quello attuale
- Se differiscono, la sessione viene invalidata (il server è stato riavviato)
Questo garantisce che:
- Un riavvio del server forza il re-login di tutti i validatori
- Sessioni zombie non rimangono attive dopo manutenzione
📡 Endpoint API
1. GET /info-room
Restituisce informazioni sulla sala/meeting corrente e lo stato del server.
Response 200 OK
{
"room_name": "Sala Assemblea",
"meeting_id": "VOT-2024",
"server_start_time": 1737100800
}
| Campo | Tipo | Descrizione |
|---|---|---|
room_name |
string | Nome della sala visualizzato nell'header |
meeting_id |
string | Identificativo del meeting/votazione |
server_start_time |
integer | Unix timestamp dell'avvio server (per invalidazione sessioni) |
2. POST /login-validate
Verifica le credenziali del validatore. IMPORTANTE: Qualsiasi badge può diventare un badge validatore se la password è corretta.
Request Body
{
"badge": "0007399575",
"password": "focolari"
}
| Campo | Tipo | Descrizione |
|---|---|---|
badge |
string | Codice badge scansionato (numerico, senza sentinel) - opzionale per validazione |
password |
string | Password inserita dall'utente |
Logica di Validazione:
- Il backend DEVE verificare la password
- Il backend PUÒ opzionalmente verificare anche il badge (lista whitelist di badge abilitati come validatori)
- Se verifica solo password: qualsiasi badge può diventare validatore con la password corretta
- Se verifica anche badge: solo badge nella whitelist possono diventare validatori
Response 200 OK (Successo)
{
"success": true,
"message": "Login effettuato con successo",
"token": "optional-jwt-token"
}
Response 401 Unauthorized (Password errata)
{
"detail": "Password non valida"
}
Response 403 Forbidden (Badge non autorizzato - se implementato controllo badge)
{
"detail": "Badge non autorizzato come validatore"
}
Note: Il frontend gestisce entrambi i codici di errore (401 e 403) mostrando il messaggio ricevuto nel campo
detail.
Note:
- La password è l'unico fattore di autenticazione
- Il badge viene memorizzato dal frontend come "badge validatore" per conferme successive
- Il token è opzionale (per future implementazioni di autenticazione JWT)
3. GET /anagrafica/{badge_code}
Recupera i dati anagrafici di un utente dato il suo codice badge.
Path Parameters
badge_code: Codice badge (stringa, es. "0008988288")
IMPORTANTE - Confronto Badge:
Il badge è una stringa, non un numero. Va confrontato esattamente carattere per carattere.
Gli zeri iniziali sono significativi: "0008988288" e "8988288" sono badge diversi.
Ruoli Ammessi:
| Ruolo | Descrizione |
|---|---|
Convocato |
Con diritto di voto |
Invitato |
Senza diritto di voto |
Tecnico |
Staff tecnico |
Staff |
Personale organizzativo |
Response 200 OK (Utente trovato e ammesso)
{
"badge_code": "0008988288",
"nome": "Marco",
"cognome": "Bianchi",
"url_foto": "https://example.com/foto.jpg",
"ruolo": "Votante",
"ammesso": true
#
<--
utente
ammesso
all
'ingresso
}
Response 200 OK (Utente trovato ma NON ammesso)
{
"badge_code": "0000514162",
"nome": "Giuseppe",
"cognome": "Verdi",
"url_foto": "https://example.com/foto.jpg",
"ruolo": "Tecnico",
"ammesso": false,
#
<--
utente
NON
ammesso
all
'ingresso
"warning": "Utente non ammesso all'ingresso"
}
Response 404 Not Found (Utente non trovato)
{
"detail": "Badge non trovato nel sistema"
}
| Campo Response | Tipo | Descrizione |
|---|---|---|
badge_code |
string | Codice badge |
nome |
string | Nome dell'utente |
cognome |
string | Cognome dell'utente |
url_foto |
string | URL immagine profilo (può essere placeholder) |
ruolo |
string | Ruolo dell'utente (es. "Votante", "Tecnico", "Ospite") |
ammesso |
boolean | true se autorizzato all'ingresso |
warning |
string? | Opzionale, presente se ammesso: false |
4. POST /entry-request
Registra l'ingresso di un utente. Richiede conferma del validatore.
Request Body
{
"user_badge": "0008988288",
"validator_password": "focolari"
}
| Campo | Tipo | Descrizione |
|---|---|---|
user_badge |
string | Badge dell'utente che sta entrando |
validator_password |
string | Password del validatore (ri-verifica) |
Response 200 OK (Successo)
{
"success": true,
"message": "Ingresso registrato con successo"
}
Response 401 Unauthorized (Password errata)
{
"detail": "Password validatore non valida"
}
Response 403 Forbidden (Utente non ammesso)
{
"detail": "Utente non autorizzato all'ingresso"
}
Response 404 Not Found (Badge non trovato)
{
"detail": "Badge utente non trovato"
}
IMPORTANTE - Sicurezza: Anche se il frontend non dovrebbe permettere di inviare entry-request per utenti non ammessi, il backend DEVE sempre verificare:
- Che la password validatore sia corretta
- Che l'utente esista
- Che l'utente sia ammesso (
ammesso: true)
Non fidarsi mai del frontend per la validazione!
🔒 Considerazioni di Sicurezza
Validazione Lato Backend
Il backend deve sempre eseguire tutte le validazioni, indipendentemente da cosa fa il frontend:
- Login: Verificare che la password sia corretta
- Entry:
- Verificare password validatore
- Verificare che utente esista
- Verificare che utente sia ammesso
- Loggare l'operazione per audit
Logging e Audit
Si raccomanda di loggare:
- Ogni tentativo di login (successo/fallimento)
- Ogni registrazione di ingresso
- Badge non trovati (potenziale tentativo di accesso non autorizzato)
Protezione Rate Limiting
Implementare rate limiting su:
/login-validate: max 5 tentativi/minuto per IP/entry-request: max 30 richieste/minuto per IP
📊 Struttura Dati Suggerita
Database Utenti
CREATE TABLE users
(
id SERIAL PRIMARY KEY,
badge_code VARCHAR(20) UNIQUE NOT NULL,
nome VARCHAR(100) NOT NULL,
cognome VARCHAR(100) NOT NULL,
url_foto VARCHAR(500),
ruolo VARCHAR(50) NOT NULL,
ammesso BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_badge_code ON users (badge_code);
Tabella Accessi (Audit Log)
CREATE TABLE access_log
(
id SERIAL PRIMARY KEY,
user_badge VARCHAR(20) NOT NULL,
validator_badge VARCHAR(20) NOT NULL,
room_id VARCHAR(50),
action VARCHAR(20) NOT NULL, -- 'entry', 'denied', 'not_found'
timestamp TIMESTAMP DEFAULT NOW(),
ip_address VARCHAR(45)
);
🧪 Test e Validazione
Casi di Test Minimi
- Login con password corretta → 200 OK
- Login con password errata → 401 Unauthorized
- Anagrafica badge esistente ammesso → 200 OK con
ammesso: true - Anagrafica badge esistente non ammesso → 200 OK con
ammesso: false+ warning - Anagrafica badge inesistente → 404 Not Found
- Entry utente ammesso con password corretta → 200 OK
- Entry utente ammesso con password errata → 401 Unauthorized
- Entry utente NON ammesso → 403 Forbidden (anche se password corretta!)
- Entry badge inesistente → 404 Not Found
Badge di Test (Mock)
0008988288 - Marco Bianchi (Convocato, ammesso)
0007399575 - Laura Rossi (Invitato, ammessa)
0000514162 - Giuseppe Verdi (Tecnico, NON ammesso)
0006478281 - NON nel database (per test 404)
📝 Note Implementative
Content-Type
Tutte le richieste e risposte usano application/json.
Codici Errore HTTP
200: Successo401: Non autorizzato (password errata)403: Vietato (utente non ammesso)404: Risorsa non trovata500: Errore interno server
Formato Errori
Tutti gli errori devono restituire un JSON con campo detail:
{
"detail": "Messaggio di errore descrittivo"
}
🔄 Changelog
v1.0 (Gennaio 2026)
- Specifica iniziale
- Endpoint:
/info-room,/login-validate,/anagrafica/{badge},/entry-request - Meccanismo invalidazione sessioni con
server_start_time