commit
60d21db3f2
4 changed files with 251 additions and 0 deletions
@ -0,0 +1,180 @@ |
|||||||
|
# Sistema di Prenotazione Mensa - Documentazione Tecnica |
||||||
|
|
||||||
|
## Abstract |
||||||
|
|
||||||
|
Il sistema di prenotazione mensa è una piattaforma web-based sviluppata con FastAPI e PostgreSQL che consente agli utenti di prenotare pasti giornalieri. L'architettura è basata su un'API RESTful con autenticazione JWT, garantendo sicurezza e scalabilità. Il sistema gestisce quattro entità principali interconnesse: prenotazioni, pasti, pietanze e ingredienti, utilizzando campi JSON per semplificare le relazioni e migliorare le performance. |
||||||
|
|
||||||
|
## Architettura del Sistema |
||||||
|
|
||||||
|
### Stack Tecnologico |
||||||
|
|
||||||
|
- **Backend**: FastAPI (Python 3.8+) |
||||||
|
- **Database**: PostgreSQL 13+ con supporto JSON/JSONB |
||||||
|
- **Autenticazione**: JWT (JSON Web Tokens) |
||||||
|
- **ORM**: SQLAlchemy |
||||||
|
|
||||||
|
### Componenti Principali |
||||||
|
|
||||||
|
1. **API Layer**: Gestione endpoint REST con FastAPI |
||||||
|
2. **Authentication Layer**: Middleware JWT per sicurezza |
||||||
|
3. **Business Logic Layer**: Logica di prenotazione e validazione |
||||||
|
4. **Data Access Layer**: SQLAlchemy ORM per accesso ai dati |
||||||
|
5. **Database Layer**: PostgreSQL con schema relazionale |
||||||
|
|
||||||
|
## Schema Database |
||||||
|
|
||||||
|
### Struttura delle Tabelle |
||||||
|
|
||||||
|
#### 1. Tabella `pietanze` |
||||||
|
```sql |
||||||
|
CREATE TABLE pietanze ( |
||||||
|
id SERIAL PRIMARY KEY, |
||||||
|
nome VARCHAR(150) NOT NULL, |
||||||
|
descrizione TEXT, |
||||||
|
categoria VARCHAR(50), -- primo, secondo, contorno, dolce |
||||||
|
prezzo DECIMAL(5,2), |
||||||
|
disponibile BOOLEAN DEFAULT true, |
||||||
|
ingredienti TEXT, -- Testo libero |
||||||
|
allergeni JSONB, -- Array di allergeni: ["glutine", "lattosio", ...] |
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP |
||||||
|
); |
||||||
|
``` |
||||||
|
|
||||||
|
#### 2. Tabella `pasti` |
||||||
|
```sql |
||||||
|
CREATE TABLE pasti ( |
||||||
|
id SERIAL PRIMARY KEY, |
||||||
|
data_pasto DATE NOT NULL, |
||||||
|
tipo_pasto VARCHAR(20) NOT NULL, -- colazione, pranzo, cena |
||||||
|
disponibile BOOLEAN DEFAULT true, |
||||||
|
turno VARCHAR(20) NOT NULL, |
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
||||||
|
UNIQUE(data_pasto, tipo_pasto) |
||||||
|
); |
||||||
|
``` |
||||||
|
|
||||||
|
#### 3. Tabella `prenotazioni` |
||||||
|
```sql |
||||||
|
CREATE TABLE prenotazioni ( |
||||||
|
id SERIAL PRIMARY KEY, |
||||||
|
user_id VARCHAR(100) NOT NULL, -- Estratto dal JWT |
||||||
|
pasto_id INTEGER REFERENCES pasti(id) ON DELETE CASCADE, |
||||||
|
pietanze_selezionate JSONB, -- Lista di pietanze |
||||||
|
note TEXT, |
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
||||||
|
UNIQUE(user_id, pasto_id) |
||||||
|
); |
||||||
|
``` |
||||||
|
|
||||||
|
## Endpoint API - Prenotazione Pasti |
||||||
|
|
||||||
|
### 1. Creazione di una prenotazione |
||||||
|
**POST /api/prenotazioni** |
||||||
|
|
||||||
|
- **Descrizione**: Crea una nuova prenotazione per un pasto specifico. |
||||||
|
- **Corpo della richiesta**: |
||||||
|
```json |
||||||
|
{ |
||||||
|
"pasto_id": 1, |
||||||
|
"pietanze_selezionate": [ |
||||||
|
2,86,89 |
||||||
|
], |
||||||
|
"note": "Senza glutine" |
||||||
|
} |
||||||
|
``` |
||||||
|
- **Risposta**: |
||||||
|
- **201 Created**: |
||||||
|
```json |
||||||
|
{ |
||||||
|
"id": 42, |
||||||
|
"user_id": "utente123", |
||||||
|
"pasto_id": 1, |
||||||
|
"stato": "attiva", |
||||||
|
"pietanze_selezionate": [ |
||||||
|
{ "id": 1, "quantita": 1 }, |
||||||
|
{ "id": 3, "quantita": 2 } |
||||||
|
], |
||||||
|
"note": "Senza glutine", |
||||||
|
"created_at": "2023-10-01T12:00:00Z", |
||||||
|
"updated_at": "2023-10-01T12:00:00Z" |
||||||
|
} |
||||||
|
``` |
||||||
|
- **400 Bad Request**: Errore di validazione o dati mancanti. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 2. Recupero delle prenotazioni di un utente |
||||||
|
**GET /api/prenotazioni** |
||||||
|
|
||||||
|
- **Descrizione**: Recupera tutte le prenotazioni dell'utente autenticato. |
||||||
|
- **Risposta**: |
||||||
|
- **200 OK**: |
||||||
|
```json |
||||||
|
[ |
||||||
|
{ |
||||||
|
"id": 42, |
||||||
|
"pasto_id": 1, |
||||||
|
"stato": "attiva", |
||||||
|
"pietanze_selezionate": [ |
||||||
|
{ "id": 1, "quantita": 1 }, |
||||||
|
{ "id": 3, "quantita": 2 } |
||||||
|
], |
||||||
|
"note": "Senza glutine", |
||||||
|
"created_at": "2023-10-01T12:00:00Z", |
||||||
|
"updated_at": "2023-10-01T12:00:00Z" |
||||||
|
} |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 3. Annullamento di una prenotazione |
||||||
|
**PUT /api/prenotazioni/{id}/annulla** |
||||||
|
|
||||||
|
- **Descrizione**: Annulla una prenotazione esistente. |
||||||
|
- **Risposta**: |
||||||
|
- **200 OK**: |
||||||
|
```json |
||||||
|
{ |
||||||
|
"id": 42, |
||||||
|
"stato": "cancellata", |
||||||
|
"updated_at": "2023-10-01T12:30:00Z" |
||||||
|
} |
||||||
|
``` |
||||||
|
- **404 Not Found**: Prenotazione non trovata. |
||||||
|
|
||||||
|
--- |
||||||
|
|
||||||
|
### 4. Recupero dei pasti disponibili |
||||||
|
**GET /api/pasti** |
||||||
|
|
||||||
|
- **Descrizione**: Recupera i pasti disponibili per la prenotazione. |
||||||
|
- **Parametri query**: |
||||||
|
- `data` (opzionale): Filtra per data specifica (formato YYYY-MM-DD) |
||||||
|
- `tipo_pasto` (opzionale): Filtra per tipo di pasto (colazione, pranzo, cena) |
||||||
|
- **Esempi**: |
||||||
|
- `GET /api/pasti` - Tutti i pasti disponibili |
||||||
|
- `GET /api/pasti?data=2023-10-02` - Pasti per il 2 ottobre 2023 |
||||||
|
- `GET /api/pasti?data=2023-10-02&tipo_pasto=pranzo` - Solo pranzi del 2 ottobre |
||||||
|
- **Risposta**: |
||||||
|
- **200 OK**: |
||||||
|
```json |
||||||
|
[ |
||||||
|
{ |
||||||
|
"id": 1, |
||||||
|
"data_pasto": "2023-10-02", |
||||||
|
"tipo_pasto": "pranzo", |
||||||
|
"turno": "12:00-14:00", |
||||||
|
"disponibile": true, |
||||||
|
"posti_totali": 100, |
||||||
|
"posti_prenotati": 20, |
||||||
|
"pietanze_disponibili": [ |
||||||
|
{ "id": 1, "nome": "Lasagna", "prezzo": 8.50 }, |
||||||
|
{ "id": 2, "nome": "Insalata", "prezzo": 5.00 } |
||||||
|
] |
||||||
|
} |
||||||
|
] |
||||||
|
``` |
||||||
@ -0,0 +1,34 @@ |
|||||||
|
CREATE TABLE pietanze ( |
||||||
|
id SERIAL PRIMARY KEY, |
||||||
|
nome VARCHAR(150) NOT NULL, |
||||||
|
descrizione TEXT, |
||||||
|
categoria VARCHAR(50), -- primo, secondo, contorno, dolce |
||||||
|
prezzo DECIMAL(5,2), |
||||||
|
disponibile BOOLEAN DEFAULT true, |
||||||
|
ingredienti TEXT, -- Testo libero |
||||||
|
allergeni JSONB, -- Array di allergeni: ["glutine", "lattosio", ...] |
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE pasti ( |
||||||
|
id SERIAL PRIMARY KEY, |
||||||
|
data_pasto DATE NOT NULL, |
||||||
|
tipo_pasto VARCHAR(20) NOT NULL, -- colazione, pranzo, cena |
||||||
|
disponibile BOOLEAN DEFAULT true, |
||||||
|
turno VARCHAR(20) NOT NULL, |
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
||||||
|
UNIQUE(data_pasto, tipo_pasto) |
||||||
|
); |
||||||
|
|
||||||
|
CREATE TABLE prenotazioni ( |
||||||
|
id SERIAL PRIMARY KEY, |
||||||
|
user_id VARCHAR(100) NOT NULL, -- Estratto dal JWT |
||||||
|
pasto_id INTEGER REFERENCES pasti(id) ON DELETE CASCADE, |
||||||
|
pietanze_selezionate JSONB, -- Lista di pietanze |
||||||
|
note TEXT, |
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
||||||
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, |
||||||
|
UNIQUE(user_id, pasto_id) |
||||||
|
); |
||||||
@ -0,0 +1,37 @@ |
|||||||
|
import psycopg2 |
||||||
|
|
||||||
|
def execute_sql_file(file_path, connection): |
||||||
|
with open(file_path, 'r') as file: |
||||||
|
sql = file.read() |
||||||
|
with connection.cursor() as cursor: |
||||||
|
cursor.execute(sql) |
||||||
|
connection.commit() |
||||||
|
|
||||||
|
def main(): |
||||||
|
# Configurazione del database |
||||||
|
db_config = { |
||||||
|
"dbname": "postgres", |
||||||
|
"user": "postgres", |
||||||
|
"password": "example", |
||||||
|
"host": "localhost", |
||||||
|
"port": 5432 |
||||||
|
} |
||||||
|
|
||||||
|
try: |
||||||
|
# Connessione al database |
||||||
|
connection = psycopg2.connect(**db_config) |
||||||
|
print("Connessione al database riuscita.") |
||||||
|
|
||||||
|
# Esecuzione dello script SQL |
||||||
|
execute_sql_file('schema.sql', connection) |
||||||
|
print("Script SQL eseguito con successo.") |
||||||
|
|
||||||
|
except Exception as e: |
||||||
|
print(f"Errore durante la configurazione del database: {e}") |
||||||
|
finally: |
||||||
|
if connection: |
||||||
|
connection.close() |
||||||
|
print("Connessione al database chiusa.") |
||||||
|
|
||||||
|
if __name__ == "__main__": |
||||||
|
main() |
||||||
Loading…
Reference in new issue