Files
Focolari-Voting-System/backend-mock/API_SPECIFICATION.md

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:

  1. Il frontend salva server_start_time nella sessione locale
  2. Al caricamento successivo, confronta il valore salvato con quello attuale
  3. 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:

  1. Che la password validatore sia corretta
  2. Che l'utente esista
  3. 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:

  1. Login: Verificare che la password sia corretta
  2. 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

  1. Login con password corretta → 200 OK
  2. Login con password errata → 401 Unauthorized
  3. Anagrafica badge esistente ammesso → 200 OK con ammesso: true
  4. Anagrafica badge esistente non ammesso → 200 OK con ammesso: false + warning
  5. Anagrafica badge inesistente → 404 Not Found
  6. Entry utente ammesso con password corretta → 200 OK
  7. Entry utente ammesso con password errata → 401 Unauthorized
  8. Entry utente NON ammesso → 403 Forbidden (anche se password corretta!)
  9. 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: Successo
  • 401: Non autorizzato (password errata)
  • 403: Vietato (utente non ammesso)
  • 404: Risorsa non trovata
  • 500: 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