feat: rimosso il token dalla risposta di login e aggiornati i modelli di dati

This commit is contained in:
2026-01-24 16:22:32 +01:00
parent 7895bde7ca
commit c214ded44b
8 changed files with 120 additions and 36 deletions

108
README.md
View File

@@ -62,13 +62,117 @@ Per dettagli tecnici, consulta la cartella `ai-prompts/`:
## 🔐 Credenziali Test ## 🔐 Credenziali Test
- **Badge Validatore:** `999999` - **Password Validatore:** `focolari`
- **Password:** `focolari` - **Badge Test:** Qualsiasi badge (es. `0008988288`, `0007399575`)
I badge di test con anagrafica sono documentati in `backend-mock/API_SPECIFICATION.md`.
## 🔍 Debug ## 🔍 Debug
Accedi a `/debug` per diagnostica RFID in tempo reale. Accedi a `/debug` per diagnostica RFID in tempo reale.
---
## 🏭 Build e Deploy in Produzione
### Compilazione Frontend
Il frontend React deve essere compilato in file statici prima del deploy.
```bash
# Build automatica (usa dev.sh)
./dev.sh build
# Oppure manualmente
cd frontend
npm install
npm run build
```
I file compilati vengono generati in `frontend/dist/`.
### Struttura Build Output
```
frontend/dist/
├── index.html
├── favicon.jpg
└── assets/
├── index-XXXXX.js # Bundle JS minificato
├── index-XXXXX.css # CSS minificato
└── FocolareMovLogo-XXXXX.jpg
```
### Deploy
#### Opzione 1: Backend Mock (test/demo)
Il backend mock Python serve automaticamente il frontend dalla cartella `frontend/dist/`:
```bash
./dev.sh server --host 0.0.0.0 --port 8000
```
L'applicazione completa sarà disponibile su `http://<IP>:8000/`.
#### Opzione 2: Backend Reale
Il backend di produzione deve:
1. **Implementare le API** secondo le specifiche in `backend-mock/API_SPECIFICATION.md`
2. **Servire i file statici** dalla cartella `frontend/dist/` sulla root `/`
3. **Configurare CORS** se frontend e backend sono su domini diversi
Esempio con un web server (nginx, Apache, etc.):
```nginx
server {
listen 80;
server_name voting.focolari.org;
# Frontend statico
location / {
root /var/www/focolari/frontend/dist;
try_files $uri $uri/ /index.html;
}
# API proxy verso backend
location /info-room { proxy_pass http://localhost:8080; }
location /login-validate { proxy_pass http://localhost:8080; }
location /anagrafica/ { proxy_pass http://localhost:8080; }
location /entry-request { proxy_pass http://localhost:8080; }
}
```
#### Opzione 3: Tutto-in-uno (consigliata)
Il backend reale serve direttamente i file statici:
```python
# Esempio FastAPI
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
app.mount("/assets", StaticFiles(directory="frontend/dist/assets"))
@app.get("/")
async def serve_frontend():
return FileResponse("frontend/dist/index.html")
```
### Variabili d'Ambiente
Il frontend non richiede variabili d'ambiente. Le API sono chiamate con path relativi (`/info-room`, etc.), quindi funziona automaticamente indipendentemente dal dominio o porta.
### Requisiti Sistema Produzione
- **Python 3.11+** con `pipenv` (per backend mock)
- **Node.js 18+** con `npm` (solo per build frontend)
- **Browser moderno** (Chrome, Safari, Firefox) sul tablet
- **Lettore RFID** configurato come tastiera HID
---
## 📄 Licenza ## 📄 Licenza
Progetto privato - Movimento dei Focolari Progetto privato - Movimento dei Focolari

View File

@@ -42,7 +42,7 @@ backend-mock/
- [x] `EntryRequest` - user_badge + validator_password - [x] `EntryRequest` - user_badge + validator_password
- [x] `UserResponse` - dati utente + warning opzionale - [x] `UserResponse` - dati utente + warning opzionale
- [x] `RoomInfoResponse` - nome sala + meeting_id + **server_start_time** - [x] `RoomInfoResponse` - nome sala + meeting_id + **server_start_time**
- [x] `LoginResponse` - success + message + token - [x] `LoginResponse` - success + message (senza token)
- [x] `EntryResponse` - success + message (SENZA welcome_message) - [x] `EntryResponse` - success + message (SENZA welcome_message)
- [x] Spostare modelli in file dedicato - [x] Spostare modelli in file dedicato

View File

@@ -34,10 +34,10 @@ Ottimizzata per tablet in orizzontale.
- [x] `RoomInfo` - info sala + **server_start_time** - [x] `RoomInfo` - info sala + **server_start_time**
- [x] `User` - dati utente - [x] `User` - dati utente
- [x] `LoginRequest/Response` - [x] `LoginRequest/Response` (senza token)
- [x] `EntryRequest/Response` (SENZA welcome_message) - [x] `EntryRequest/Response` (SENZA welcome_message)
- [x] `AppState` - stati applicazione - [x] `AppState` - stati applicazione
- [x] `ValidatorSession` - sessione validatore + **serverStartTime** - [x] `ValidatorSession` - sessione validatore (badge, password, serverStartTime)
- [x] `RFIDScannerState` - stato scanner - [x] `RFIDScannerState` - stato scanner
- [x] `RFIDScanResult` - risultato scan - [x] `RFIDScanResult` - risultato scan

View File

@@ -100,8 +100,7 @@ Verifica le credenziali del validatore. **IMPORTANTE:** Qualsiasi badge può div
```json ```json
{ {
"success": true, "success": true,
"message": "Login effettuato con successo", "message": "Login effettuato con successo"
"token": "optional-jwt-token"
} }
``` ```
@@ -123,11 +122,9 @@ Verifica le credenziali del validatore. **IMPORTANTE:** Qualsiasi badge può div
**Note:** Il frontend gestisce entrambi i codici di errore (401 e 403) mostrando il messaggio ricevuto nel campo **Note:** Il frontend gestisce entrambi i codici di errore (401 e 403) mostrando il messaggio ricevuto nel campo
`detail`. `detail`.
**Note:**
- La password è l'unico fattore di autenticazione - La password è l'unico fattore di autenticazione
- Il badge viene memorizzato dal frontend come "badge validatore" per conferme successive - Il badge viene memorizzato dal frontend come "badge validatore" per conferme successive
- Il token è opzionale (per future implementazioni di autenticazione JWT)
--- ---
@@ -144,8 +141,9 @@ Il badge è una **stringa**, non un numero. Va confrontato **esattamente** carat
Gli zeri iniziali sono significativi: `"0008988288"` e `"8988288"` sono badge **diversi**. Gli zeri iniziali sono significativi: `"0008988288"` e `"8988288"` sono badge **diversi**.
**Ruoli Ammessi:** **Ruoli Ammessi:**
| Ruolo | Descrizione | | Ruolo | Descrizione |
|-------|-------------| |-------------|-------------------------|
| `Convocato` | Con diritto di voto | | `Convocato` | Con diritto di voto |
| `Invitato` | Senza diritto di voto | | `Invitato` | Senza diritto di voto |
| `Tecnico` | Staff tecnico | | `Tecnico` | Staff tecnico |
@@ -160,13 +158,7 @@ Gli zeri iniziali sono significativi: `"0008988288"` e `"8988288"` sono badge **
"cognome": "Bianchi", "cognome": "Bianchi",
"url_foto": "https://example.com/foto.jpg", "url_foto": "https://example.com/foto.jpg",
"ruolo": "Votante", "ruolo": "Votante",
"ammesso": true "ammesso": true # <-- utente ammesso all 'ingresso
#
<--
utente
ammesso
all
'ingresso
} }
``` ```
@@ -179,14 +171,7 @@ Gli zeri iniziali sono significativi: `"0008988288"` e `"8988288"` sono badge **
"cognome": "Verdi", "cognome": "Verdi",
"url_foto": "https://example.com/foto.jpg", "url_foto": "https://example.com/foto.jpg",
"ruolo": "Tecnico", "ruolo": "Tecnico",
"ammesso": false, "ammesso": false, # <-- utente NON ammesso all 'ingresso
#
<--
utente
NON
ammesso
all
'ingresso
"warning": "Utente non ammesso all'ingresso" "warning": "Utente non ammesso all'ingresso"
} }
``` ```

View File

@@ -87,8 +87,7 @@ async def login_validate(request: LoginRequest):
return LoginResponse( return LoginResponse(
success=True, success=True,
message="Login validatore effettuato con successo", message="Login validatore effettuato con successo"
token=f"focolare-token-{clean}"
) )

View File

@@ -41,7 +41,6 @@ class LoginResponse(BaseModel):
"""Risposta login""" """Risposta login"""
success: bool success: bool
message: str message: str
token: Optional[str] = None
class EntryResponse(BaseModel): class EntryResponse(BaseModel):

View File

@@ -240,7 +240,6 @@ function App() {
const session: ValidatorSession = { const session: ValidatorSession = {
badge: pendingValidatorBadge, badge: pendingValidatorBadge,
password: password, // Salvo la password per le conferme ingresso password: password, // Salvo la password per le conferme ingresso
token: response.token || '',
loginTime: Date.now(), loginTime: Date.now(),
expiresAt: Date.now() + SESSION_DURATION_MS, expiresAt: Date.now() + SESSION_DURATION_MS,
serverStartTime: roomInfo.server_start_time, // Per invalidare se server riparte serverStartTime: roomInfo.server_start_time, // Per invalidare se server riparte

View File

@@ -25,7 +25,6 @@ export interface User {
export interface LoginResponse { export interface LoginResponse {
success: boolean; success: boolean;
message: string; message: string;
token?: string;
} }
export interface EntryResponse { export interface EntryResponse {
@@ -63,7 +62,6 @@ export type AppState =
export interface ValidatorSession { export interface ValidatorSession {
badge: string; badge: string;
password: string; password: string;
token: string;
loginTime: number; loginTime: number;
expiresAt: number; expiresAt: number;
serverStartTime: number; // Per invalidare se il server riparte serverStartTime: number; // Per invalidare se il server riparte