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