From a394ed9ad257e9b26a24f644ede38383e8da1723 Mon Sep 17 00:00:00 2001 From: Matteo Benedetto Date: Thu, 5 Jun 2025 16:00:58 +0200 Subject: [PATCH] Update documentation and database schema for meal reservation system - Enhanced README and idea documentation with detailed system architecture and operational flows. - Revised database schema to simplify table structures and improve data handling with JSONB. - Added state management for reservations in the schema. - Updated requirements file to include necessary dependencies. --- README.md | 114 +++++++++++++++++++++++ idea.md | 236 +++++++++++++++-------------------------------- requirements.txt | 7 ++ schema.sql | 11 +-- 4 files changed, 200 insertions(+), 168 deletions(-) create mode 100644 requirements.txt diff --git a/README.md b/README.md index e69de29..c7cc8f1 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,114 @@ +# Sistema di Prenotazione Mensa - Documentazione Tecnica + +## Abstract + +Il sistema di prenotazione mensa è una piattaforma web-based sviluppata, con FastAPI e PostgreSQL a livello backend e NiceGUI per le interfacce fullstack, 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 tr entità principali interconnesse: prenotazioni, pasti e pietanze, utilizzando campi JSON per semplificare le relazioni e migliorare le erformance. I dati utente sono forniti dal JWT auth bearer evittando la memorizzazione sul database di dati sensibili non necessari, sfruttando per questa funzionalità lo IAM Azure e l'account aziendale (o anche IAM self hosted Keycloak) + +## Architettura del Sistema + +### Stack Tecnologico + +- **Backend**: FastAPI (Python 3.8+) +- **Database**: PostgreSQL 13+ con supporto JSON/JSONB +- **Autenticazione**: JWT (JSON Web Tokens) / OpenID-Connect (provider Azure o self-hosted) +- **HMI**: webgui fullstack NiceGUI (Python 3.9+) + +## Database Design + +### Filosofia di Semplificazione + +Il database è stato progettato seguendo una filosofia di **massima semplificazione**, riducendo la complessità relazionale tradizionale attraverso l'uso strategico di campi JSONB di PostgreSQL al posto di tabelle intermedie per le relazioni N a N. Contestalmente alla semplicità dello scheme e alle potenti capacità di manipolazione di dati strutturati JSON di postgresql, questa scelta progettuale offre diversi vantaggi: + +- **Riduzione delle JOIN**: Eliminazione di tabelle di associazione complesse +- **Flessibilità**: Strutture dati dinamiche per allergeni, turni e selezioni delle pietanze +- **Performance**: Meno query multiple per operazioni comuni +- **Manutenibilità**: Schema più leggibile e modificabile + +### Struttura delle Tabelle + +#### Tabella `pietanze` +Gestisce le singole pietanze disponibili con: +- Informazioni base (nome, descrizione) +- Gestione allergeni tramite array JSON +- Controllo disponibilità e limiti di prenotazione + +#### Tabella `pasti` +Rappresenta i menu giornalieri con: +- **Portate JSONB**: Organizzazione flessibile delle pietanze per tipologia indicando la disponibilità massima di ciascuna +- **Turni JSONB**: Gestione dinamica degli orari e capacità (`{"12:45": 100, "13:30": 100}`) +- Vincolo di unicità per data e tipo pasto + +#### Tabella `prenotazioni` +Collega utenti e pasti con: +- Riferimento user_id estratto da JWT +- **Pietanze selezionate JSONB**: Array delle scelte dell'utente +- Gestione stati del ciclo di vita della prenotazione + +## Flussi Operativi + +### Flusso di Creazione Menu Giornaliero +1. **Inserimento Pietanze**: Caricamento delle pietanze disponibili per il giorno +2. **Composizione Pasto**: Associazione pietanze alle portate tramite JSON +3. **Configurazione Turni**: Definizione orari e capacità massima per turno +4. **Attivazione**: Abilitazione delle prenotazioni per gli utenti + +### Flusso di Prenotazione Utente +1. **Autenticazione**: Verifica JWT e estrazione user_id +2. **Visualizzazione Menu**: Recupero pasti disponibili per data +3. **Selezione Pietanze**: Scelta pietanze per ogni portata disponibile +4. **Validazione**: Controllo disponibilità e limiti di prenotazione +5. **Conferma**: Creazione record prenotazione con stato 'attiva' + +### Flusso di Servizio Mensa +1. **Consultazione Prenotazioni**: Visualizzazione prenotazioni per turno +2. **Erogazione Pasto**: Aggiornamento stato da 'attiva', 'servita', 'pagata', 'completata' +3. **Monitoraggio**: Tracking utilizzo e disponibilità residua + +### Flusso di Gestione Disponibilità +1. **Controllo Automatico**: Verifica limiti pietanze e turni +2. **Aggiornamento Dinamico**: Modifica disponibilità in tempo reale +3. **Notifiche**: Gestione comunicazioni per esaurimento posti +4. **Chiusura Prenotazioni**: Disabilitazione automatica al raggiungimento limiti + +## Scelte Architetturali: Logica di Business + +### Principio di Separazione delle Responsabilità + +In linea con la filosofia di semplificazione adottata per il design del database, **la logica di business complessa rimane interamente gestita a livello API (FastAPI)** piuttosto che essere delegata al database tramite stored procedures o funzioni PostgreSQL. + +#### Motivazioni della Scelta + +**Coerenza Architetturale**: Il sistema è progettato attorno a FastAPI come orchestratore centrale. Mantenere la logica di business nell'API garantisce un'architettura coerente e predicibile. + +**Manutenibilità e Testabilità**: Le funzioni Python sono intrinsecamente più facili da testare, debuggare e modificare rispetto alle stored procedures. Questo si allinea con l'approccio DevOps moderno e l'integrazione continua. + +**Flessibilità di Sviluppo**: La gestione della disponibilità, dei limiti di prenotazione e delle validazioni può evolvere rapidamente senza modifiche al schema database. + +#### Implementazione delle Verifiche di Disponibilità + +Le operazioni critiche come la verifica di disponibilità posti in un turno o di una pietanza vengono gestite tramite: +- **Query atomiche** per il recupero dati +- **Validazioni Python** per la logica di business +- **Transazioni asyncpg** per garantire consistenza +- **Pattern async/await** per performance ottimali + +### Scelta di asyncpg vs ORM + +Il sistema utilizza **asyncpg** come driver database principale invece di un ORM tradizionale come SQLAlchemy per diverse ragioni strategiche: + +#### Motivazioni Tecniche + +**Ottimizzazione Nativa PostgreSQL**: La progettazione è strettamente legata alle funzionalità specifiche di PostgreSQL (JSONB, operatori JSON, funzioni aggregate native). Asyncpg consente di sfruttare al massimo queste capacità senza astrazioni intermedie. + +**Performance Async Native**: Asyncpg è progettato specificamente per l'ecosistema async/await di Python, offrendo performance superiori rispetto agli adapter asincroni degli ORM tradizionali. + +**Controllo Granulare**: Le query SQL dirette permettono un controllo preciso delle operazioni JSONB, essenziali per la gestione delle portate, turni e selezioni pietanze. + +**Semplicità Architetturale**: Con solo tre tabelle e logica di business in Python, l'overhead di un ORM completo risulterebbe sproporzionato rispetto ai benefici. + +#### Implementazione Pratica + +- **Query ottimizzate** per operazioni JSONB specifiche +- **Pool di connessioni** gestito nativamente da asyncpg +- **Transazioni esplicite** per operazioni critiche di prenotazione +- **Prepared statements** per query ripetitive ad alta frequenza \ No newline at end of file diff --git a/idea.md b/idea.md index 6a4199f..572e4f7 100644 --- a/idea.md +++ b/idea.md @@ -2,7 +2,7 @@ ## 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. +Il sistema di prenotazione mensa è una piattaforma web-based sviluppata, con FastAPI e PostgreSQL a livello backend e NiceGUI per le interfacce fullstack, 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 tr entità principali interconnesse: prenotazioni, pasti e pietanze, utilizzando campi JSON per semplificare le relazioni e migliorare le erformance. I dati utente sono forniti dal JWT auth bearer evittando la memorizzazione sul database di dati sensibili non necessari, sfruttando per questa funzionalità lo IAM Azure e l'account aziendale (o anche IAM self hosted Keycloak) ## Architettura del Sistema @@ -13,168 +13,82 @@ Il sistema di prenotazione mensa è una piattaforma web-based sviluppata con Fas - **Autenticazione**: JWT (JSON Web Tokens) - **ORM**: SQLAlchemy -### Componenti Principali +## Database Design -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 +### Filosofia di Semplificazione -## Schema Database +Il database è stato progettato seguendo una filosofia di **massima semplificazione**, riducendo la complessità relazionale tradizionale attraverso l'uso strategico di campi JSONB di PostgreSQL al posto di tabelle intermedie per le relazioni N a N. Contestalmente alla semplicità dello scheme e alle potenti capacità di manipolazione di dati strutturati JSON di postgresql, questa scelta progettuale offre diversi vantaggi: + +- **Riduzione delle JOIN**: Eliminazione di tabelle di associazione complesse +- **Flessibilità**: Strutture dati dinamiche per allergeni, turni e selezioni delle pietanze +- **Performance**: Meno query multiple per operazioni comuni +- **Manutenibilità**: Schema più leggibile e modificabile ### 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 } - ] - } - ] - ``` +#### Tabella `pietanze` +Gestisce le singole pietanze disponibili con: +- Informazioni base (nome, descrizione) +- Gestione allergeni tramite array JSON +- Controllo disponibilità e limiti di prenotazione + +#### Tabella `pasti` +Rappresenta i menu giornalieri con: +- **Portate JSONB**: Organizzazione flessibile delle pietanze per tipologia indicando la disponibilità massima di ciascuna +- **Turni JSONB**: Gestione dinamica degli orari e capacità (`{"12:45": 100, "13:30": 100}`) +- Vincolo di unicità per data e tipo pasto + +#### Tabella `prenotazioni` +Collega utenti e pasti con: +- Riferimento user_id estratto da JWT +- **Pietanze selezionate JSONB**: Array delle scelte dell'utente +- Gestione stati del ciclo di vita della prenotazione + +## Flussi Operativi + +### Flusso di Creazione Menu Giornaliero +1. **Inserimento Pietanze**: Caricamento delle pietanze disponibili per il giorno +2. **Composizione Pasto**: Associazione pietanze alle portate tramite JSON +3. **Configurazione Turni**: Definizione orari e capacità massima per turno +4. **Attivazione**: Abilitazione delle prenotazioni per gli utenti + +### Flusso di Prenotazione Utente +1. **Autenticazione**: Verifica JWT e estrazione user_id +2. **Visualizzazione Menu**: Recupero pasti disponibili per data +3. **Selezione Pietanze**: Scelta pietanze per ogni portata disponibile +4. **Validazione**: Controllo disponibilità e limiti di prenotazione +5. **Conferma**: Creazione record prenotazione con stato 'attiva' + +### Flusso di Servizio Mensa +1. **Consultazione Prenotazioni**: Visualizzazione prenotazioni per turno +2. **Erogazione Pasto**: Aggiornamento stato da 'attiva' a 'servita' +3. **Gestione Pagamento**: Transizione finale a stato 'pagata' +4. **Monitoraggio**: Tracking utilizzo e disponibilità residua + +### Flusso di Gestione Disponibilità +1. **Controllo Automatico**: Verifica limiti pietanze e turni +2. **Aggiornamento Dinamico**: Modifica disponibilità in tempo reale +3. **Notifiche**: Gestione comunicazioni per esaurimento posti +4. **Chiusura Prenotazioni**: Disabilitazione automatica al raggiungimento limiti + +## Scelte Architetturali: Logica di Business + +### Principio di Separazione delle Responsabilità + +In linea con la filosofia di semplificazione adottata per il design del database, **la logica di business complessa rimane interamente gestita a livello API (FastAPI)** piuttosto che essere delegata al database tramite stored procedures o funzioni PostgreSQL. + +#### Motivazioni della Scelta + +**Coerenza Architetturale**: Il sistema è progettato attorno a FastAPI come orchestratore centrale. Mantenere la logica di business nell'API garantisce un'architettura coerente e predicibile. + +**Manutenibilità e Testabilità**: Le funzioni Python sono intrinsecamente più facili da testare, debuggare e modificare rispetto alle stored procedures. Questo si allinea con l'approccio DevOps moderno e l'integrazione continua. + +**Flessibilità di Sviluppo**: La gestione della disponibilità, dei limiti di prenotazione e delle validazioni può evolvere rapidamente senza modifiche al schema database. + +#### Implementazione delle Verifiche di Disponibilità + +Le operazioni critiche come la verifica di disponibilità posti in un turno o di una pietanza vengono gestite tramite: +- **Query atomiche** per il recupero dati +- **Validazioni Python** per la logica di business +- **Transazioni SQLAlchemy** per garantire consistenza +- **Pattern async/await** per performance ottimali \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..41fbf4e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +fastapi>=0.104.0 +uvicorn[standard]>=0.24.0 +sqlalchemy>=2.0.0 +psycopg2-binary>=2.9.0 +pydantic>=2.0.0 +python-jose[cryptography]>=3.3.0 +python-multipart>=0.0.6 diff --git a/schema.sql b/schema.sql index b3d566b..396b0a9 100644 --- a/schema.sql +++ b/schema.sql @@ -2,10 +2,6 @@ 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 @@ -14,9 +10,9 @@ CREATE TABLE pietanze ( CREATE TABLE pasti ( id SERIAL PRIMARY KEY, data_pasto DATE NOT NULL, - tipo_pasto VARCHAR(20) NOT NULL, -- colazione, pranzo, cena + portate JSONB, -- Lista di portate e relative pietanze con numero di prenotazioni massime (se 0 nessun limite): {"primo": {1: 100, 2: 50}, "secondo": {3: 100, 4: 50}, ...} disponibile BOOLEAN DEFAULT true, - turno VARCHAR(20) NOT NULL, + turni JSONB, -- Dizionario con i turni di prenotazione e posti massimi disponibili (se 0 nessun limite): {"12:45": 100, "13:00": 100, ...} created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(data_pasto, tipo_pasto) @@ -26,8 +22,9 @@ 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 + pietanze_selezionate JSONB, -- Lista di pietanze scelte per il pasto: [1, 2, 3] note TEXT, + stato VARCHAR(20) DEFAULT 'attiva', -- Stati: 'attiva', 'servita', 'pagata', 'annullata' created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(user_id, pasto_id)