first commit
This commit is contained in:
@@ -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 }
|
||||
]
|
||||
}
|
||||
]
|
||||
```
|
||||
+34
@@ -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)
|
||||
);
|
||||
+37
@@ -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()
|
||||
Reference in New Issue
Block a user