feat: aggiornamenti alla documentazione e miglioramenti UI/UX

This commit is contained in:
2026-01-20 00:24:16 +01:00
parent b467d4753d
commit 7895bde7ca
12 changed files with 403 additions and 81 deletions

View File

@@ -1,6 +1,7 @@
# 📄 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.
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
@@ -10,12 +11,15 @@ Questo documento descrive le specifiche che il backend reale deve implementare p
## 🌐 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.
@@ -24,15 +28,18 @@ 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
@@ -45,6 +52,7 @@ Questo garantisce che:
Restituisce informazioni sulla sala/meeting corrente e lo stato del server.
#### Response `200 OK`
```json
{
"room_name": "Sala Assemblea",
@@ -53,19 +61,21 @@ Restituisce informazioni sulla sala/meeting corrente e lo stato del server.
}
```
| Campo | Tipo | Descrizione |
|-------|------|-------------|
| `room_name` | string | Nome della sala visualizzato nell'header |
| `meeting_id` | string | Identificativo del meeting/votazione |
| 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.
Verifica le credenziali del validatore. **IMPORTANTE:** Qualsiasi badge può diventare un badge validatore se la password
è corretta.
#### Request Body
```json
{
"badge": "0007399575",
@@ -73,12 +83,20 @@ Verifica le credenziali del validatore. **IMPORTANTE:** Qualsiasi badge può div
}
```
| Campo | Tipo | Descrizione |
|-------|------|-------------|
| `badge` | string | Codice badge scansionato (numerico, senza sentinel) |
| `password` | string | Password inserita dall'utente |
| 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)
```json
{
"success": true,
@@ -87,14 +105,26 @@ Verifica le credenziali del validatore. **IMPORTANTE:** Qualsiasi badge può div
}
```
#### Response `401 Unauthorized` (Errore)
#### Response `401 Unauthorized` (Password errata)
```json
{
"detail": "Password non valida"
}
```
#### Response `403 Forbidden` (Badge non autorizzato - se implementato controllo badge)
```json
{
"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)
@@ -106,13 +136,23 @@ Verifica le credenziali del validatore. **IMPORTANTE:** Qualsiasi badge può div
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)
```json
{
"badge_code": "0008988288",
@@ -120,11 +160,18 @@ Gli zeri iniziali sono significativi: `"0008988288"` e `"8988288"` sono badge **
"cognome": "Bianchi",
"url_foto": "https://example.com/foto.jpg",
"ruolo": "Votante",
"ammesso": true # <-- utente ammesso all'ingresso
"ammesso": true
#
<--
utente
ammesso
all
'ingresso
}
```
#### Response `200 OK` (Utente trovato ma NON ammesso)
```json
{
"badge_code": "0000514162",
@@ -132,27 +179,35 @@ Gli zeri iniziali sono significativi: `"0008988288"` e `"8988288"` sono badge **
"cognome": "Verdi",
"url_foto": "https://example.com/foto.jpg",
"ruolo": "Tecnico",
"ammesso": false, #<-- utente NON ammesso all'ingresso
"ammesso": false,
#
<--
utente
NON
ammesso
all
'ingresso
"warning": "Utente non ammesso all'ingresso"
}
```
#### Response `404 Not Found` (Utente non trovato)
```json
{
"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` |
| 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` |
---
@@ -161,6 +216,7 @@ Gli zeri iniziali sono significativi: `"0008988288"` e `"8988288"` sono badge **
Registra l'ingresso di un utente. Richiede conferma del validatore.
#### Request Body
```json
{
"user_badge": "0008988288",
@@ -168,12 +224,13 @@ Registra l'ingresso di un utente. Richiede conferma del validatore.
}
```
| Campo | Tipo | Descrizione |
|-------|------|-------------|
| `user_badge` | string | Badge dell'utente che sta entrando |
| Campo | Tipo | Descrizione |
|----------------------|--------|---------------------------------------|
| `user_badge` | string | Badge dell'utente che sta entrando |
| `validator_password` | string | Password del validatore (ri-verifica) |
#### Response `200 OK` (Successo)
```json
{
"success": true,
@@ -182,6 +239,7 @@ Registra l'ingresso di un utente. Richiede conferma del validatore.
```
#### Response `401 Unauthorized` (Password errata)
```json
{
"detail": "Password validatore non valida"
@@ -189,6 +247,7 @@ Registra l'ingresso di un utente. Richiede conferma del validatore.
```
#### Response `403 Forbidden` (Utente non ammesso)
```json
{
"detail": "Utente non autorizzato all'ingresso"
@@ -196,6 +255,7 @@ Registra l'ingresso di un utente. Richiede conferma del validatore.
```
#### Response `404 Not Found` (Badge non trovato)
```json
{
"detail": "Badge utente non trovato"
@@ -203,7 +263,9 @@ Registra l'ingresso di un utente. Richiede conferma del validatore.
```
**IMPORTANTE - Sicurezza:**
Anche se il frontend non dovrebbe permettere di inviare entry-request per utenti non ammessi, il backend **DEVE** sempre verificare:
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`)
@@ -215,23 +277,28 @@ 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
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
@@ -240,32 +307,36 @@ Implementare rate limiting su:
## 📊 Struttura Dati Suggerita
### Database Utenti
```sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
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,
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);
CREATE INDEX idx_badge_code ON users (badge_code);
```
### Tabella Accessi (Audit Log)
```sql
CREATE TABLE access_log (
id SERIAL PRIMARY KEY,
user_badge VARCHAR(20) NOT NULL,
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)
room_id VARCHAR(50),
action VARCHAR(20) NOT NULL, -- 'entry', 'denied', 'not_found'
timestamp TIMESTAMP DEFAULT NOW(),
ip_address VARCHAR(45)
);
```
@@ -286,9 +357,10 @@ CREATE TABLE access_log (
9. **Entry badge inesistente** → 404 Not Found
### Badge di Test (Mock)
```
0008988288 - Marco Bianchi (Votante, ammesso)
0007399575 - Laura Rossi (Votante, ammessa)
0008988288 - Marco Bianchi (Convocato, ammesso)
0007399575 - Laura Rossi (Invitato, ammessa)
0000514162 - Giuseppe Verdi (Tecnico, NON ammesso)
0006478281 - NON nel database (per test 404)
```
@@ -298,9 +370,11 @@ CREATE TABLE access_log (
## 📝 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)
@@ -308,7 +382,9 @@ Tutte le richieste e risposte usano `application/json`.
- `500`: Errore interno server
### Formato Errori
Tutti gli errori devono restituire un JSON con campo `detail`:
```json
{
"detail": "Messaggio di errore descrittivo"
@@ -320,6 +396,7 @@ Tutti gli errori devono restituire un JSON con campo `detail`:
## 🔄 Changelog
### v1.0 (Gennaio 2026)
- Specifica iniziale
- Endpoint: `/info-room`, `/login-validate`, `/anagrafica/{badge}`, `/entry-request`
- Meccanismo invalidazione sessioni con `server_start_time`

View File

@@ -5,12 +5,20 @@
"meeting_id": "VOT-2024"
},
"users": [
{
"badge_code": "0008988288",
"nome": "Marco",
"cognome": "Bianchi",
"url_foto": "https://randomuser.me/api/portraits/men/1.jpg",
"ruolo": "Convocato",
"ammesso": true
},
{
"badge_code": "0007399575",
"nome": "Laura",
"cognome": "Rossi",
"url_foto": "https://randomuser.me/api/portraits/women/2.jpg",
"ruolo": "Votante",
"ruolo": "Invitato",
"ammesso": true
},
{

View File

@@ -10,7 +10,7 @@
"nome": "Test",
"cognome": "Ammesso",
"url_foto": "https://randomuser.me/api/portraits/lego/1.jpg",
"ruolo": "Votante",
"ruolo": "Convocato",
"ammesso": true
},
{
@@ -18,7 +18,7 @@
"nome": "Test",
"cognome": "NonAmmesso",
"url_foto": "https://randomuser.me/api/portraits/lego/2.jpg",
"ruolo": "Ospite",
"ruolo": "Invitato",
"ammesso": false
},
{