-
-
-
-
-
6. Deploy & Run with Docker Compose
-
7. Deploy & Run with Local Microservices and Dockerized PostgreSQL
-
-
10. Health Checks, Logs and Basic Diagnostics
-
Il sistema è una piattaforma di flight monitoring orientata ai microservizi che consente di gestire utenti, aeroporti di interesse e dati di volo relativi ad arrivi e partenze. L’obiettivo principale è fornire a un client esterno un insieme di API coerenti, stabili e facilmente integrabili per:
-
registrare e gestire utenti identificati univocamente tramite indirizzo e‑mail;
-
associare a ciascun utente uno o più aeroporti di interesse;
-
raccogliere periodicamente da una sorgente esterna autorevole (OpenSky Network) i dati di volo in arrivo e in partenza per tali aeroporti;
-
memorizzare i dati di volo in un database relazionale per consentire interrogazioni efficienti;
-
esporre API dedicate a interrogazioni di tipo operativo e analitico, ad esempio:
- ultimo volo in arrivo o in partenza per un aeroporto;
- interrogazioni su intervalli temporali arbitrari.
L’architettura è pensata per essere modulare e estendibile: ciascun microservizio è owner del proprio sottodominio e del relativo schema dati, e le interazioni tra componenti avvengono esclusivamente tramite interfacce pubbliche ben definite (REST e gRPC). Questo approccio riduce l’accoppiamento, facilita l’evoluzione indipendente dei servizi e prepara il sistema a possibili estensioni future, come l’aggiunta di nuove fonti dati o nuove tipologie di interrogazioni.
L’applicazione è suddivisa in due microservizi Spring Boot autonomi ma cooperanti, ciascuno responsabile di un sottoinsieme chiaro del dominio applicativo:
- lo User Manager Service governa il ciclo di vita degli utenti e la loro validazione;
- il Data Collector Service si occupa della gestione degli aeroporti, degli interessi utente–aeroporto, della raccolta periodica dei dati di volo e della loro interrogazione.
Ogni microservizio:
- utilizza un proprio schema logico all’interno di un’istanza PostgreSQL condivisa;
- espone API REST JSON over HTTP per l’interazione con client esterni;
- impiega Spring Data JPA e Flyway per la gestione del livello di persistenza e delle migrazioni;
- incapsula la propria logica applicativa in servizi dedicati, separando il livello di esposizione delle API dal livello di dominio.
La cooperazione tra i due servizi avviene tramite una chiamata gRPC dallo Data Collector Service allo User Manager Service per la validazione dell’utente, in modo da evitare dipendenze dirette sul database di utenti e mantenere bounded contexts nettamente separati.
Lo User Manager Service gestisce il sottodominio utente e fornisce funzionalità di registrazione, consultazione e cancellazione. Le responsabilità principali sono:
- registrare un nuovo utente a partire da una richiesta contenente almeno e‑mail e nome;
- garantire l’unicità dell’utente tramite vincoli a livello di dominio e di database (chiave primaria sull’indirizzo e‑mail);
- rendere disponibili endpoint per la consultazione dei dati di un utente e, se necessario, per la sua eliminazione;
- esporre un servizio gRPC dedicato alla validazione dell’esistenza di un utente, utilizzato internamente dal Data Collector Service.
Il modello dati ruota attorno all’entità User, persistita nella tabella users dello schema dedicato (User DB). L’identificatore primario è il campo email, affiancato da attributi descrittivi (ad esempio il nome) e da metadati come la data di creazione (created_at).
Per garantire una semantica di tipo at‑most‑once nella registrazione, la logica applicativa:
- verifica l’eventuale esistenza preventiva dell’utente con la stessa e‑mail;
- solleva eccezioni di dominio specifiche in caso di duplicato;
- si appoggia sui vincoli di unicità del database come ulteriore linea di difesa.
L’esposizione tramite REST adotta convenzioni HTTP standard (codici di stato espressivi, payload JSON strutturati tramite DTO) e un exception handler centralizzato, in modo da restituire risposte coerenti e facilmente consumabili da client esterni.
Il Data Collector Service è responsabile del sottodominio aeroporti–interessi–voli e rappresenta il cuore della logica di raccolta e interrogazione dei dati di volo. Le sue responsabilità principali includono:
-
gestire il catalogo degli aeroporti monitorati dal sistema, modellati tramite l’entità
Airport(tabellaairports); -
gestire le relazioni di interesse tra utenti e aeroporti attraverso l’entità
UserAirportInterest(tabellauser_airport_interest), che collega l’e‑mail dell’utente a uno specifico aeroporto e registra la data di creazione dell’interesse; -
raccogliere periodicamente, tramite uno scheduler interno, i dati di volo (arrivi e partenze) per tutti gli aeroporti attualmente associati ad almeno un interesse utente;
-
mappare e salvare i dati di volo raccolti nell’entità
FlightRecord(tabellaflight_records), che rappresenta l’unità informativa di base per le interrogazioni successive; -
mettere a disposizione API REST per interrogare i voli, con particolare attenzione a:
- ultimo volo in arrivo o partenza per un aeroporto;
- ricerca di voli all’interno di intervalli temporali specificati dal client.
Prima di registrare un nuovo interesse utente–aeroporto, il servizio invoca il gRPC esposto dallo User Manager Service per verificare che l’utente esista effettivamente, evitando così di creare riferimenti inconsistenti. L’associazione tra utente e aeroporto è resa univoca da un vincolo sul pair (user_email, airport_id), che impedisce la duplicazione degli interessi.
Lo scheduler, configurato per eseguire la raccolta a intervalli regolari, calcola una finestra temporale di riferimento (ad esempio le ultime 24 ore) e, per ciascun aeroporto di interesse, interroga l’API OpenSky per arrivi e partenze. I dati grezzi vengono trasformati in FlightRecord e salvati nel Data DB, in modo che le interrogazioni successive possano lavorare su dati consolidati e omogenei, indipendenti dalla disponibilità istantanea del servizio esterno.
Il sistema si appoggia su due componenti esterni fondamentali: la piattaforma OpenSky Network, che costituisce la sorgente autorevole dei dati di volo, e un’istanza PostgreSQL utilizzata come livello di persistenza condiviso. Entrambi i componenti sono integrati in modo da preservare la separazione dei domini applicativi e consentire al contempo una gestione uniforme della configurazione.
Le OpenSky Network API rappresentano la fonte dati esterna da cui il sistema estrae le informazioni sui voli in arrivo e in partenza. L’integrazione è realizzata tramite un client dedicato (OpenSkyClient) che incapsula:
- l’autenticazione OAuth2 Client Credentials, effettuata verso un endpoint di authorization configurabile;
- la gestione dell’access token (ottenimento, caching in memoria, gestione della scadenza tramite
expires_ine instant di validità); - le invocazioni HTTP verso gli endpoint REST di OpenSky per estrarre i voli relativi a un particolare aeroporto e intervallo temporale.
Il client costruisce richieste HTTP con intestazioni adeguate (in particolare l’header Authorization: Bearer <token>), interpreta le risposte JSON mappandole in DTO (OpenSkyFlightDto) e converte tali DTO in entità di dominio FlightRecord. I parametri chiave, come gli URL base per l’autenticazione e per le API, sono esternalizzati tramite proprietà applicative e variabili d’ambiente, così da poter essere modificati senza necessità di ricompilare né ridistribuire il codice.
Il sistema utilizza una singola istanza PostgreSQL come motore di persistenza, all’interno della quale vengono creati due database logici separati:
userdb, dedicato al dominio utenti;datadb, dedicato al dominio aeroporti–interessi–voli.
La creazione dei database avviene tramite uno script di inizializzazione montato nel container (./docker/db/init/01-create-databases.sql), mentre la struttura delle tabelle è gestita a livello di ciascun microservizio tramite Flyway. In questo modo ogni servizio mantiene pieno controllo sul proprio schema, pur condividendo la stessa istanza PostgreSQL, e l’evoluzione del modello dati risulta tracciata e riproducibile.
I parametri di connessione fondamentali (host, porta, nome dei database, credenziali) sono definiti in un file di configurazione condiviso (docker/env/postgres.env per l’istanza e docker/env/services.env per i servizi), e iniettati nei microservizi tramite variabili d’ambiente. Questa scelta consente di:
- separare in modo netto la configurazione dalla logica applicativa;
- facilitare la portabilità del sistema tra ambienti diversi (development, test, staging, production);
- uniformare la gestione delle credenziali di accesso al database.
La repository include una documentazione di supporto che integra le informazioni operative di questo README con una descrizione più ampia dell’architettura, del modello dati e dei principali flussi applicativi. Tali materiali sono organizzati in modo da risultare facilmente accessibili a chiunque debba comprendere o manutenere il sistema.
La relazione tecnica descritta nel file documentation/written_report.pdf fornisce una visione di insieme dettagliata del sistema dal punto di vista architetturale e concettuale. In particolare, il documento illustra:
- i requisiti funzionali e non funzionali che hanno guidato le scelte progettuali;
- la scomposizione del dominio nei due microservizi principali e nei corrispondenti bounded contexts;
- il modello concettuale dei dati e le motivazioni alla base della suddivisione in due database logici;
- i principali flussi applicativi, con l’indicazione dei punti in cui intervengono i servizi esterni e i meccanismi di error handling e fault tolerance.
Questa relazione rappresenta il riferimento principale per comprendere le scelte di design sottostanti al codice e alle istruzioni di build e deploy fornite in questo README.
All’interno della cartella documentation/diagram_screenshots/ sono presenti diversi diagrammi architetturali e di sequenza che supportano la comprensione dei flussi chiave del sistema. Fra i più rilevanti:
-
un diagramma architetturale complessivo, che mostra i microservizi, il database PostgreSQL, le OpenSky Network API e le principali relazioni fra questi elementi;
-
diagrammi di sequenza che descrivono, passo dopo passo, flussi centrali quali:
- la registrazione di un nuovo utente con garanzia di semantica at‑most‑once;
- la registrazione di un interesse utente–aeroporto con validazione via gRPC;
- la raccolta periodica dei voli tramite lo scheduler del Data Collector Service e le API OpenSky;
- le interrogazioni dei dati di volo da parte di un client esterno.
Questi diagrammi costituiscono un complemento visivo al codice e alle API, facilitando l’analisi delle dipendenze e dei passi eseguiti in ciascun caso d’uso.
Nella stessa cartella è presente un diagramma Entity–Relationship (ER) che rappresenta lo schema logico dei due database userdb e datadb. Il diagramma evidenzia:
- l’entità
Usere i relativi attributi nel User DB; - le entità
Airport,UserAirportInteresteFlightRecordnel Data DB; - le chiavi primarie, i vincoli di unicità (in particolare sul pair
(user_email, airport_id)), le chiavi esterne e le principali cardinalità tra le entità.
Questo schema costituisce la base per la progettazione del livello di persistenza implementato tramite JPA e Flyway e permette di verificare rapidamente la coerenza tra modello concettuale, modello logico e implementazione effettiva nel codice.
Nella directory radice sono presenti le cartelle e i file necessari per comprendere rapidamente i componenti principali del sistema e per avviare la piattaforma tramite Docker o in modalità ibrida. A livello logico, la root contiene:
- le directory dei due microservizi (
user-manager-service/edata-collector-service/), ciascuna con il proprio codice applicativo e la propria configurazione; - la directory
docker/, che raccoglie i file di orchestrazione e configurazione dell’infrastruttura (PostgreSQL e servizi); - la directory
documentation/, che contiene la relazione tecnica e i diagrammi di supporto; - la directory
postman/, che include le collection pronte all’uso per verificare rapidamente le API esposte dai servizi; - i file di supporto generali, come ad esempio il
README.md(questo documento) e gli eventuali file di configurazione per il versionamento.
Questa impostazione consente a chiunque acceda per la prima volta al repository di individuare immediatamente dove risiedono il codice dei servizi, l’infrastruttura containerizzata e la documentazione tecnica.
La struttura delle cartelle segue un modello service-oriented e separa in modo netto il codice applicativo, la configurazione infrastrutturale e gli artefatti di documentazione.
-
user-manager-service/Contiene l’implementazione completa dello User Manager Service basato su Spring Boot. Al suo interno sono presenti:- il codice sorgente Java/Kotlin organizzato secondo i package applicativi (controller REST, servizi, repository JPA, client gRPC);
- le risorse di configurazione applicativa (ad esempio
application.ymle gli eventuali fileapplication-*.ymlper i profili); - i file di migrazione Flyway per lo schema dati relativo al dominio utente;
- il file
pom.xmlcon le dipendenze e le configurazioni di build Maven; - il
Dockerfileutilizzato per costruire l’immagine container del microservizio.
-
data-collector-service/Contiene l’implementazione del Data Collector Service. La struttura interna rispecchia quella dello User Manager Service e comprende:- il codice sorgente organizzato in layer (controller REST, servizi di dominio, client verso OpenSky, repository JPA, componenti scheduler);
- i file di configurazione Spring Boot per la connessione al Data DB e ai servizi esterni (OpenSky, gRPC verso User Manager);
- le migrazioni Flyway dedicate alla creazione e all’evoluzione delle tabelle
airports,user_airport_interesteflight_records; - il
pom.xmlper la gestione delle dipendenze e del processo di build; - il
Dockerfileper creare l’immagine container del servizio.
-
docker/Raccoglie tutti gli artefatti relativi all’infrastruttura containerizzata:- il file
docker-compose.yml, che definisce i servizi Docker (PostgreSQL, User Manager Service, Data Collector Service), le reti, i volumi e le dipendenze; - la sottocartella
env/, che contiene i file di variabili d’ambiente condivisi (postgres.envper il database,services.envper i microservizi), utilizzati per parametrizzare le immagini senza esporre valori sensibili nel codice sorgente; - la sottocartella
db/init/, che ospita gli script SQL di inizializzazione del database (ad esempio la creazione dei database logiciuserdbedatadb).
- il file
-
documentation/Contiene la documentazione di supporto alla comprensione dell’architettura e del modello dati:- il file
written_report.pdf, che rappresenta la relazione tecnica di progetto; - la sottocartella
diagram_screenshots/, che include gli screenshot dei diagrammi architetturali, dei diagrammi di sequenza e del diagramma ER.
- il file
-
postman/Contiene le Postman collections utilizzate per testare e dimostrare le funzionalità esposte dai microservizi. Tipicamente sono presenti due file JSON principali, ad esempio:- una collection per le API dello User Manager Service (registrazione, consultazione e cancellazione utente);
- una collection per le API del Data Collector Service (gestione aeroporti, interessi utente–aeroporto, interrogazioni dei voli).
Questa articolazione permette di isolare le responsabilità e di identificare rapidamente dove intervenire in caso di modifiche al codice applicativo, alla configurazione dell’infrastruttura o alla documentazione.
Alcuni file del repository rivestono un ruolo centrale nelle procedure di build e deploy e meritano una menzione esplicita.
-
docker/docker-compose.ymlDefinisce l’orchestrazione completa dell’ambiente di esecuzione containerizzato. In questo file sono specificati:- i servizi Docker (
postgres,user-manager-service,data-collector-service); - le immagini da utilizzare o generare, i build context e i
Dockerfileassociati; - i volumi per la persistenza dei dati PostgreSQL e per eventuali mount di configurazione;
- le reti interne utilizzate per la comunicazione tra i container;
- le dipendenze di avvio tra i servizi, in modo che il database sia disponibile prima dei microservizi.
- i servizi Docker (
-
docker/env/postgres.envContiene le variabili d’ambiente utilizzate per configurare l’istanza PostgreSQL (nome utente, password, porta, nome dei database). Questo file consente di centralizzare la configurazione del database ed evitare la duplicazione di parametri nei vari servizi. -
docker/env/services.envRaccoglie le variabili d’ambiente comuni ai microservizi, tra cui i parametri di connessione al database, gli URL di OpenSky e le impostazioni di base per l’esposizione delle API. I microservizi leggono tali valori all’avvio, rendendo agevole l’adattamento del sistema a diversi ambienti. -
user-manager-service/Dockerfileedata-collector-service/DockerfileDescrivono il processo di build delle immagini Docker per i due microservizi. Entrambi utilizzano una strategia multi-stage che prevede una prima fase di build con Maven e una seconda fase di runtime più leggera basata su una immagine JDK/JRE minimal. -
user-manager-service/pom.xmledata-collector-service/pom.xmlDefiniscono le dipendenze, i plugin e le configurazioni necessarie per compilare, testare e packagizzare i microservizi. Questi file sono fondamentali per eseguire build locali senza Docker e per integrare il progetto in pipeline CI/CD. -
Script SQL di inizializzazione in
docker/db/init/Comprendono gli script per la creazione dei database logici e di eventuali oggetti di supporto. Sono eseguiti automaticamente all’avvio del container PostgreSQL e garantiscono che l’ambiente sia correttamente predisposto prima dell’esecuzione delle migrazioni applicative.
Nel complesso, questi file costituiscono il nucleo operativo necessario per configurare, buildare e distribuire il sistema in modo riproducibile e controllato in diversi contesti di esecuzione.
Il sistema è progettato per essere eseguito su una macchina in grado di eseguire Docker e, opzionalmente, una toolchain Java locale per la build e il run dei microservizi al di fuori dei container. Sono raccomandate le seguenti caratteristiche minime:
- CPU: almeno 2 core fisici (4 thread consigliati) per evitare contenention eccessiva fra i container;
- RAM: almeno 8 GB di memoria, con 16 GB consigliati per lavorare in modo agevole con Docker, IDE e altri strumenti aperti in parallelo;
- Storage: almeno 5–10 GB di spazio libero dedicato ai container Docker, alle immagini e ai log applicativi.
Per quanto riguarda il sistema operativo, il progetto è stato pensato per ambienti moderni e supportati:
- Linux (distribuzioni recenti come Ubuntu, Debian, Fedora, ecc.);
- macOS (versioni con supporto ufficiale per Docker Desktop);
- Windows 10/11 a 64 bit, preferibilmente con Docker Desktop installato.
È importante che il sistema operativo consenta l’esecuzione di Docker in modalità Linux container e che l’utente disponga dei permessi necessari per avviare e gestire i container.
Il funzionamento completo della piattaforma richiede un insieme di strumenti software. Alcuni sono obbligatori per l’esecuzione standard tramite Docker, altri sono opzionali ma raccomandati per la build e il run locale dei servizi.
Docker è il requisito principale per l’esecuzione containerizzata dell’intero sistema (PostgreSQL + microservizi). Si raccomanda l’installazione di una versione recente, ad esempio:
- Docker Engine / Docker Desktop 20.x o superiore.
La presenza di Docker consente di:
- avviare l’istanza PostgreSQL con la configurazione prevista;
- eseguire i microservizi all’interno di container isolati;
- riprodurre con facilità l’ambiente di esecuzione su macchine differenti.
Il progetto utilizza Docker Compose per orchestrare l’avvio congiunto dei servizi. In base alla versione di Docker installata, Docker Compose può essere integrato come sottocomando (docker compose) o come binario separato (docker-compose).
È consigliato l’utilizzo della sintassi moderna:
docker compose versionUna versione recente di Docker Desktop include già Docker Compose v2.x, sufficiente per eseguire il file docker/docker-compose.yml fornito nella repository.
Per chi desidera eseguire i microservizi localmente (senza containerizzarli), è necessario disporre di un Java Development Kit (JDK) compatibile con la versione di Spring Boot utilizzata. Si raccomanda:
- JDK 21 (LTS) oppure una versione JDK 17+ compatibile.
È importante che il comando java punti al JDK e non a un JRE obsoleto, in modo da garantire il corretto funzionamento dei plugin Maven e delle applicazioni Spring Boot.
La build dei microservizi in modalità non containerizzata richiede Apache Maven. È sufficiente una versione recente, ad esempio:
- Maven 3.8.x o superiore.
Maven viene utilizzato per:
- compilare il codice sorgente dei microservizi;
- risolvere e scaricare le dipendenze dal repository Maven centrale;
- eseguire i test (se configurati);
- creare i fat jar eseguibili o avviare direttamente le applicazioni Spring Boot tramite il plugin dedicato.
Il sistema integra i dati di volo tramite le OpenSky Network API, che richiedono un’apposita registrazione e l’ottenimento di credenziali.
Per utilizzare le API, è necessario disporre di un account OpenSky valido. Il processo tipico prevede:
- la creazione di un account sul portale OpenSky;
- l’eventuale abilitazione alle API e la consultazione della documentazione ufficiale per i dettagli sui limiti e sulle policy di utilizzo;
- la verifica delle condizioni d’uso per garantire la conformità alle norme previste.
Le credenziali associate all’account saranno utilizzate per ottenere un access token OAuth2 mediante il flusso Client Credentials.
L’integrazione con OpenSky è basata su OAuth2 Client Credentials, che richiede la definizione di una client application sul lato OpenSky con relativa coppia client id / client secret. Una volta ottenute tali credenziali, devono essere configurate come variabili d’ambiente o inserite nei file env previsti (ad esempio docker/env/services.env), in modo che il Data Collector Service possa:
- richiedere un access token al servidor di authorization configurato;
- riutilizzare il token fino alla scadenza (
expires_in), con successivo rinnovo automatico.
Per motivi di sicurezza, è fondamentale non committare client id e client secret all’interno del repository. Nel progetto sono previsti placeholder che il deployer deve sostituire con valori reali in fase di configurazione.
Prima di procedere con la build e il deploy, è opportuno verificare che tutti i prerequisiti software siano installati e correttamente configurati.
Per controllare la versione di Docker:
docker --versionPer verificare la presenza di Docker Compose (sintassi moderna):
docker compose versionPer verificare l’installazione del JDK:
java -versionL’output dovrebbe indicare una versione 17 o 21 (o superiore compatibile), con riferimento a un JDK.
Per controllare la versione di Maven:
mvn -vÈ opportuno infine validare che le variabili d’ambiente relative a OpenSky (client id, client secret, endpoint di authorization e API base URL) siano configurate correttamente nel contesto in cui verrà eseguito docker compose o i microservizi in locale. Un semplice metodo consiste nel verificare, dal terminale, che le variabili risultino valorizzate, ad esempio:
echo "$OPEN_SKY_CLIENT_ID"
echo "$OPEN_SKY_CLIENT_SECRET"In assenza di valori o in presenza di placeholder, è necessario aggiornare i file env o le variabili d’ambiente di sistema prima di procedere con i passi di build e deploy.
La configurazione del sistema è basata su un approccio env-based, in cui i parametri sensibili o dipendenti dall’ambiente (host, porte, credenziali, URL di servizi esterni) vengono veicolati tramite variabili d’ambiente e file .env, mentre i file di configurazione Spring Boot (application-*.yml) si limitano a referenziarli. Questa strategia consente di:
- separare in modo netto il codice applicativo dai valori di configurazione;
- utilizzare la stessa immagine container in ambienti diversi (sviluppo, test, produzione) variando soltanto i file
.envo le variabili di runtime; - evitare l’hardcoding di credenziali e URL all’interno dei sorgenti.
A livello infrastrutturale, il file docker/docker-compose.yml carica i file .env presenti in docker/env/ e li espone come variabili d’ambiente nei container. Sul lato applicativo, i microservizi leggono tali variabili tramite le property Spring (ad esempio ${DB_HOST}, ${OPEN_SKY_CLIENT_ID}, ecc.).
La gestione centralizzata delle variabili d’ambiente avviene principalmente tramite la cartella docker/env/. I file .env definiti in questa cartella vengono montati nei container al momento dell’avvio tramite Docker Compose.
I file .env principali sono:
docker/env/postgres.env: definisce i parametri di inizializzazione dell’istanza PostgreSQL;docker/env/services.env: fornisce ai microservizi i parametri comuni di connessione al database e i riferimenti alle OpenSky Network API.
Un esempio semplificato di postgres.env può essere:
POSTGRES_USER=user
POSTGRES_PASSWORD=password
POSTGRES_DB=postgres
USER_DB_NAME=userdb
DATA_DB_NAME=datadbIn questo file vengono configurati:
- l’utente e la password amministrativi di PostgreSQL (
POSTGRES_USER,POSTGRES_PASSWORD); - il database predefinito (
POSTGRES_DB) utilizzato come contesto iniziale per l’esecuzione degli script di bootstrap; - i nomi dei due database logici dedicati ai microservizi (
USER_DB_NAME,DATA_DB_NAME), che saranno creati dallo script di inizializzazione.
Un esempio di services.env può essere:
DB_HOST=postgres
DB_PORT=5432
DB_USERNAME=user
DB_PASSWORD=password
USER_DB_NAME=userdb
DATA_DB_NAME=datadb
OPEN_SKY_AUTH_BASE_URL=https://auth.opensky-network.org/auth/realms/opensky-network/protocol/openid-connect/token
OPEN_SKY_API_BASE_URL=https://opensky-network.org/api
OPEN_SKY_CLIENT_ID=your_client_id
OPEN_SKY_CLIENT_SECRET=your_client_secretQueste variabili permettono ai microservizi di:
- connettersi al database PostgreSQL tramite host e porta logici (
DB_HOST,DB_PORT), riutilizzando gli stessi nomi per entrambi i servizi; - accedere ai database corretti (
USER_DB_NAME,DATA_DB_NAME) pur condividendo la stessa istanza PostgreSQL; - ottenere le credenziali e gli endpoint necessari per interagire con le OpenSky Network API.
Il file services.env viene referenziato nel docker-compose.yml per i container dei microservizi, in modo che le variabili siano disponibili al runtime delle applicazioni Spring.
Oltre ai file .env gestiti a livello di Docker, è possibile definire ulteriori file di configurazione esterni o variabili d’ambiente specifiche per ogni microservizio, ad esempio:
- variabili dedicate a parametri di logging (livello di log, formati);
- variabili per controllare l’intervallo di esecuzione dello scheduler (ad esempio
FLIGHT_COLLECTION_CRONoFLIGHT_COLLECTION_INTERVAL_SECONDS).
Nel caso in cui si decida di utilizzare file .env separati per i singoli servizi, è opportuno mantenere una convenzione chiara (ad esempio user-manager.env, data-collector.env) e documentarne il contenuto in modo analogo a quanto fatto per postgres.env e services.env, assicurandosi che Docker Compose o l’ambiente di esecuzione li carichino esplicitamente.
La configurazione del database è incapsulata nella combinazione di:
- variabili d’ambiente fornite dai file
.env; - script SQL di inizializzazione;
- configurazioni Spring Boot nei microservizi.
I parametri di connessione fondamentali sono:
- host del database (ad esempio
postgresnella rete Docker); - porta di ascolto (tipicamente
5432); - nome utente e password per l’autenticazione;
- nome del database logico a cui connettersi.
Nei file application-docker.yml dei microservizi, la URL JDBC viene costruita a partire dalle variabili d’ambiente, ad esempio:
spring:
datasource:
url: jdbc:postgresql://${DB_HOST:postgres}:${DB_PORT:5432}/${USER_DB_NAME:userdb}
username: ${DB_USERNAME:user}
password: ${DB_PASSWORD:password}per lo User Manager Service, e in modo analogo per il Data Collector Service:
spring:
datasource:
url: jdbc:postgresql://${DB_HOST:postgres}:${DB_PORT:5432}/${DATA_DB_NAME:datadb}
username: ${DB_USERNAME:user}
password: ${DB_PASSWORD:password}In questo modo i microservizi non hanno conoscenza diretta di host, porte o credenziali, ma delegano l’intero set di parametri alle variabili d’ambiente fornite dall’infrastruttura.
La separazione tra User DB e Data DB è realizzata attraverso due database logici distinti (userdb e datadb) all’interno della stessa istanza PostgreSQL. Lo script docker/db/init/01-create-databases.sql utilizza i nomi definiti in postgres.env per creare i due database al bootstrap del container.
Ogni microservizio si connette esclusivamente al proprio database logico e gestisce lo schema tramite Flyway, con migrazioni collocate in:
user-manager-service/src/main/resources/db/migration/per lo schema utenti;data-collector-service/src/main/resources/db/migration/per lo schema aeroporti–interessi–voli.
Questo approccio garantisce un isolamento netto dei domain model, pur mantenendo una infrastruttura di persistenza condivisa e facilmente gestibile.
Le credenziali per l’accesso alle OpenSky Network API sono fornite tramite variabili d’ambiente, in modo da evitare la loro inclusione diretta nei sorgenti o nei file di configurazione versionati.
Gli elementi minimi necessari per l’autenticazione OAuth2 Client Credentials sono:
OPEN_SKY_AUTH_BASE_URL: URL base del server di authorization;OPEN_SKY_API_BASE_URL: URL base delle API di volo;OPEN_SKY_CLIENT_ID: identificativo della client application registrata presso OpenSky;OPEN_SKY_CLIENT_SECRET: secret associato alla client application.
Nel Data Collector Service, tali variabili vengono mappate nelle property applicative, ad esempio:
opensky:
auth-url: ${OPENSKY_AUTH_URL}
api-base-url: ${OPENSKY_API_URL}
client-id: ${OPENSKY_CLIENT_ID}
client-secret: ${OPENSKY_CLIENT_SECRET}Il client dedicato (OpenSkyClient) utilizza queste proprietà per:
- richiedere un access token valido al server di authorization;
- invocare gli endpoint delle API con l’header
Authorization: Bearer <token>; - gestire la scadenza del token sulla base del campo
expires_in.
All’interno del repository, i file .env di esempio e le proprietà applicative devono contenere placeholder (ad esempio your_client_id, your_client_secret) e non valori reali. Le credenziali effettive vanno:
- inserite localmente nei file
.envnon versionati (ad esempio mantenuti comedocker/env/services.envesclusi dal VCS, se richiesto); - oppure configurate tramite variabili d’ambiente del sistema o del servizio di orchestrazione.
È opportuno garantire che:
- i file contenenti valori reali non vengano committati nel repository remoto;
- l’accesso a tali file sia limitato agli operatori che necessitano di eseguire il sistema.
La configurazione dei microservizi è incentrata su un unico file application.yml per ciascun servizio, integrato con variabili d’ambiente fornite dall’infrastruttura (Docker e file .env). In assenza di profili espliciti, Spring Boot utilizza il profilo di default, che nel progetto è già predisposto per l’esecuzione in scenari tipici quali:
- microservizi in esecuzione locale con database PostgreSQL dockerizzato su
localhost:5432; - microservizi containerizzati che leggono host, porte e credenziali dal layer di configurazione basato su variabili d’ambiente.
In questo modello, il file application.yml funge da singola sorgente di verità per la configurazione applicativa, mentre gli aspetti ambiente‑specifici (host, credenziali, URL esterni) sono demandati alle variabili d’ambiente illustrate nelle sezioni precedenti.
Il profilo di default di Spring Boot è sufficiente per la maggior parte degli scenari supportati dal progetto. In particolare:
- i parametri relativi al datasource (URL JDBC, utente, password) sono definiti in
application.ymlin forma generica, assumendolocalhoste la porta standard5432come configurazione di base; - i parametri relativi ai servizi esterni (endpoint OpenSky, credenziali OAuth2, configurazione gRPC) sono referenziati tramite placeholder e risolti al runtime utilizzando le variabili d’ambiente (
OPEN_SKY_AUTH_BASE_URL,OPEN_SKY_API_BASE_URL,OPEN_SKY_CLIENT_ID,OPEN_SKY_CLIENT_SECRET, ecc.).
Quando l’applicazione viene eseguita:
- in locale, i microservizi si connettono al database Dockerizzato esposto su
localhost:5432, come descritto nel Capitolo 7; - in container, gli stessi placeholder vengono risolti rispetto alle variabili d’ambiente iniettate da Docker Compose (ad esempio
DB_HOST=postgres,DB_PORT=5432), mantenendo invariata la configurazione applicativa.
Questo approccio riduce la necessità di gestire molteplici file application-*.yml per ciascun ambiente e privilegia un modello in cui il comportamento dell’applicazione è governato principalmente dal contesto di esecuzione (ambiente) anziché da configurazioni duplicate.
Qualora in futuro si rendesse necessario introdurre una differenziazione più marcata tra ambienti (ad esempio sviluppo, test, produzione), è possibile estendere il modello attuale definendo profili Spring Boot dedicati, ad esempio:
application-dev.ymlper configurazioni specifiche di sviluppo (logging più verboso, feature flag, parametri di scheduler meno aggressivi);application-prod.ymlper parametri più conservativi, time‑out più stringenti, livelli di log più restrittivi.
L’attivazione di tali profili potrà avvenire tramite:
-
variabile d’ambiente
SPRING_PROFILES_ACTIVE(ad esempioSPRING_PROFILES_ACTIVE=prod); -
oppure parametro da riga di comando, ad esempio:
java -jar data-collector-service.jar --spring.profiles.active=prod
Nel contesto attuale, tuttavia, l’utilizzo del profilo di default combinato con la configurazione env‑based descritta nelle sezioni precedenti è sufficiente e rappresenta la modalità consigliata per build & deploy del sistema.
La modalità di build raccomandata prevede l’utilizzo di Docker e Docker Compose per costruire le immagini dei microservizi e del database ed eseguire l’intero sistema in ambiente containerizzato.
Dopo aver clonato la repository, è necessario posizionarsi nella cartella docker/, che contiene il file docker-compose.yml e i file .env utilizzati per la configurazione:
cd dockerTutti i comandi di build ed esecuzione tramite Docker Compose indicati in questo documento presuppongono che la directory corrente sia docker/.
Per costruire le immagini Docker dei due microservizi a partire dai rispettivi Dockerfile è possibile utilizzare Docker Compose in uno dei seguenti modi.
Build esplicita delle immagini, senza avviare i container:
docker compose buildQuesto comando:
- analizza il file
docker-compose.yml; - esegue la build delle immagini per i servizi che la richiedono (tipicamente
user-manager-serviceedata-collector-service); - effettua il pull dell’immagine di PostgreSQL, se non già presente in locale.
In alternativa, è possibile combinare build e avvio dei servizi utilizzando l’opzione --build:
docker compose up --buildIn questo caso Docker Compose:
- ricostruisce le immagini se il contesto di build è cambiato (modifiche al codice sorgente, al
pom.xmlo alDockerfile); - avvia i container nella foreground, mostrando i log in tempo reale.
Per eseguire il sistema in background, mantenendo comunque la fase di build automatica, è possibile usare:
docker compose up --build -dDopo la prima esecuzione, se il codice non è cambiato, è sufficiente utilizzare:
docker compose up -dper riavviare i servizi senza ricostruire le immagini.
Ciascun microservizio dispone di un proprio Dockerfile alla radice della rispettiva cartella (user-manager-service/Dockerfile e data-collector-service/Dockerfile). Entrambi adottano una strategia di multi-stage build con l’obiettivo di:
- separare la fase di build Maven dall’immagine runtime;
- produrre immagini finali più leggere e sicure, contenenti solo il necessario per l’esecuzione.
Lo schema tipico di un Dockerfile multi-stage per un microservizio Spring Boot è il seguente:
-
Stage di build:
- utilizza un’immagine base con Maven e JDK (ad esempio una immagine ufficiale Maven basata su OpenJDK);
- copia il file
pom.xmle scarica le dipendenze (per sfruttare la cache Docker); - copia il sorgente (
src/) e lancia il comandomvn clean packageper produrre l’artefatto eseguibile (jar Spring Boot).
-
Stage runtime:
-
utilizza una immagine base JRE o JDK ridotta (ad esempio una variante slim o distroless compatibile);
-
copia dal primo stage il jar già costruito in una directory di destinazione (ad esempio
/app/app.jar); -
definisce il comando di avvio, tipicamente:
ENTRYPOINT ["java", "-jar", "/app/app.jar"]
-
In docker-compose.yml, ogni servizio referenzia il proprio Dockerfile indicando il contesto di build e il valore di Dockerfile, ad esempio:
services:
user-manager-service:
build:
context: ../user-manager-service
dockerfile: Dockerfile
# ...
data-collector-service:
build:
context: ../data-collector-service
dockerfile: Dockerfile
# ...Questa configurazione permette di mantenere i microservizi indipendenti, garantendo al contempo una pipeline di build coerente e ripetibile.
È possibile costruire i microservizi anche in modalità non containerizzata, utilizzando direttamente Maven. Questa modalità è utile durante lo sviluppo, per l’esecuzione da IDE o per scenari di debug approfondito, mantenendo comunque una pipeline di build allineata a quella utilizzata negli image Docker.
Per compilare e pacchettizzare lo User Manager Service senza utilizzare Docker è sufficiente eseguire:
cd user-manager-service
mvn clean packageIl comando:
- rimuove eventuali artefatti di build precedenti (
clean); - compila il sorgente ed esegue i test configurati (se presenti);
- genera un jar eseguibile in
target/.
Al termine, nella directory target/ sarà disponibile un artefatto del tipo:
target/user-manager-service-<version>.jar
Il jar utilizza la configurazione definita in application.yml, che prevede — nella configurazione predefinita — una connessione al database userdb esposto da PostgreSQL su localhost:5432. Eventuali parametri (host, porta, credenziali) possono essere sovrascritti all’avvio tramite variabili d’ambiente o property passate da riga di comando, se necessario.
La procedura per il Data Collector Service è del tutto analoga:
cd data-collector-service
mvn clean packageAnche in questo caso Maven:
-
risolve le dipendenze dichiarate nel
pom.xml; -
compila il codice (inclusi scheduler, client gRPC e integrazione con OpenSky);
-
esegue gli eventuali test;
-
produce un jar eseguibile in
target/, ad esempio:target/data-collector-service-<version>.jar
Il jar utilizza application.yml come sorgente di configurazione di default, puntando al database datadb su localhost:5432 e al servizio gRPC dello User Manager Service sull’host e porta configurati (tipicamente localhost:9090). Anche in questo caso, è possibile sovrascrivere tali valori tramite variabili d’ambiente o argomenti a riga di comando.
La build locale presenta alcune differenze sostanziali rispetto alla build basata su Docker:
-
richiede che JDK e Maven siano installati sulla macchina host;
-
produce jar eseguibili anziché immagini container;
-
demanda all’operatore la responsabilità di:
- avviare e configurare il database PostgreSQL (ad esempio tramite Docker, come descritto nel Capitolo 7);
- impostare correttamente le variabili d’ambiente (ad esempio credenziali OpenSky, host DB) qualora si discostino dai valori di default in
application.yml; - evitare conflitti di porte fra i servizi locali e altri processi in esecuzione.
La modalità Docker-based, al contrario, incapsula le dipendenze runtime e le configurazioni infrastrutturali all’interno di un ambiente controllato, semplificando la riproduzione dello stesso scenario di esecuzione su macchine differenti.
Prima di avviare lo stack applicativo è necessario verificare che i file di configurazione env-based siano presenti e correttamente valorizzati nella cartella docker/env/.
-
Posizionarsi nella cartella
docker/della repository:cd docker -
Verificare la presenza dei file richiesti:
ls env/
Devono essere presenti almeno:
postgres.envper la configurazione dell’istanza PostgreSQL;services.envper la configurazione dei microservizi.
-
Aprire
env/postgres.enve impostare, se necessario, i valori desiderati per:POSTGRES_USERePOSTGRES_PASSWORD;POSTGRES_DB(database di bootstrap);USER_DB_NAMEeDATA_DB_NAME(database logici dei due domini).
-
Aprire
env/services.enve impostare:- i parametri di connessione al database (
DB_HOST,DB_PORT,DB_USERNAME,DB_PASSWORD,USER_DB_NAME,DATA_DB_NAME); - gli endpoint e le credenziali per l’integrazione con OpenSky (
OPEN_SKY_AUTH_BASE_URL,OPEN_SKY_API_BASE_URL,OPEN_SKY_CLIENT_ID,OPEN_SKY_CLIENT_SECRET).
- i parametri di connessione al database (
È consigliabile utilizzare valori di default significativi per l’ambiente di sviluppo e sostituire solo i placeholder sensibili (ad esempio le credenziali di accesso e le chiavi OpenSky) prima del primo avvio.
Una volta preparati i file .env, è possibile avviare l’intero sistema tramite Docker Compose.
Per eseguire una prima build delle immagini e avviare i container in foreground, con log aggregati:
docker compose up --buildQuesto comando:
- costruisce o aggiorna le immagini dei microservizi sulla base dei rispettivi
Dockerfile; - scarica l’immagine PostgreSQL se non è già presente in locale;
- avvia i servizi definiti nel
docker-compose.yml(database e microservizi).
Per avviare il sistema in background, lasciando i container attivi ma senza mantenere il terminale bloccato, è possibile usare:
docker compose up --build -dDopo la prima esecuzione, se non sono intervenute modifiche al codice o ai Dockerfile, è sufficiente:
docker compose up -dper riavviare i servizi utilizzando le immagini già costruite.
Durante il primo avvio è normale che il servizio PostgreSQL impieghi alcuni secondi per completare l’inizializzazione, compresa l’esecuzione degli script SQL in db/init/ e la preparazione dei database logici. I microservizi si connetteranno al database una volta che questo sarà operativo.
Dopo l’avvio, è opportuno verificare che tutti i servizi previsti siano effettivamente in esecuzione.
Per elencare i container attivi associati allo stack:
docker compose psL’output deve riportare, con stato running, almeno:
- il container dell’istanza PostgreSQL (ad esempio
postgreso nome equivalente configurato neldocker-compose.yml); - il container del User Manager Service;
- il container del Data Collector Service.
Per esaminare rapidamente i log complessivi:
docker compose logso, per seguire i log in tempo reale:
docker compose logs -fÈ utile verificare nei log dei microservizi che:
- la connessione al database venga stabilita correttamente;
- le migrazioni Flyway siano applicate senza errori;
- gli endpoint REST risultino esposti sulle porte attese (come configurate nel
docker-compose.yml).
Per arrestare tutti i servizi e rilasciare le risorse allocate è possibile utilizzare, dalla cartella docker/:
docker compose downIl comando interrompe i container associati allo stack e rimuove le relative definizioni di rete, mantenendo però intatti i volumi di persistenza (ad esempio quelli associati a PostgreSQL), così che i dati restino disponibili ai successivi riavvii.
In alternativa, se si preferisce fermare temporaneamente i container senza rimuoverli, è possibile ricorrere a:
docker compose stopche sospende l’esecuzione dei container, lasciando invariata la loro configurazione e il loro stato sul disco.
In alcuni scenari può essere necessario ripartire da uno stato completamente pulito (ad esempio per ripetere da zero l’inizializzazione dei database o per cancellare dati di test). In questo caso è possibile utilizzare l’opzione --volumes:
docker compose down --volumesQuesto comando rimuove, oltre ai container e alle reti, anche i volumi associati allo stack, eliminando di fatto tutti i dati persistiti da PostgreSQL. Al successivo docker compose up, il database verrà ricreato da zero eseguendo nuovamente gli script di inizializzazione e le migrazioni applicative.
L’uso di --volumes deve essere valutato con attenzione, poiché comporta la perdita definitiva dei dati memorizzati nei volumi coinvolti.
Per analizzare nel dettaglio il comportamento di un singolo servizio è possibile utilizzare il comando logs specificando il nome del servizio definito in docker-compose.yml. Ad esempio:
docker compose logs user-manager-servicedocker compose logs data-collector-serviceÈ possibile aggiungere l’opzione -f per seguire i log in streaming:
docker compose logs -f data-collector-servicePer accedere alla shell di un container in esecuzione (ad esempio per effettuare verifiche puntuali o consultare file interni), è possibile utilizzare docker exec. Dalla cartella docker/:
docker compose exec postgres bashAll’interno della shell del container PostgreSQL è ad esempio possibile utilizzare il client psql per ispezionare i database, le tabelle o gli schemi creati dalle migrazioni applicative.
In modo analogo, si può accedere alla shell dei container dei microservizi (se l’immagine lo consente) per effettuare verifiche aggiuntive.
Per verificare le porte esposte dai container verso l’host si può utilizzare il comando standard Docker:
docker psLa colonna PORTS mostra le associazioni del tipo host_port:container_port per ciascun servizio. Le porte host riportate in questa colonna sono quelle da utilizzare per accedere alle API REST dai client esterni (browser, Postman, sistemi di integrazione).
Qualora si modifichino le mappature delle porte nel file docker-compose.yml, è necessario rieseguire il ciclo di:
docker compose downseguito da
docker compose up --build -dper applicare le modifiche alla configurazione dell’ambiente di esecuzione.
Per eseguire i microservizi in locale mantenendo PostgreSQL in Docker, è necessario avviare esclusivamente il servizio del database definito nel file docker/docker-compose.yml.
-
Aprire un terminale e posizionarsi nella cartella
docker/della repository:cd docker -
Avviare il solo servizio PostgreSQL in modalità detached (in background). Se nel
docker-compose.ymlil servizio è denominato, ad esempio,postgres, il comando sarà:docker compose up -d postgres
In alternativa, se il servizio è esposto con un diverso nome logico, è sufficiente sostituire
postgrescon il nome configurato nel filedocker-compose.yml.
Il comando avvia il container del database utilizzando i parametri definiti in env/postgres.env e monta gli script di inizializzazione in db/init/.
Per verificare che il database sia correttamente inizializzato e in esecuzione:
-
controllare lo stato del servizio:
docker compose ps
Il container associato a PostgreSQL deve risultare in stato
running. -
consultare i log del container per verificare l’esecuzione degli script di bootstrap e l’assenza di errori:
docker compose logs postgres
Se la configurazione prevede l’uso di volumi persistenti, al primo avvio verranno creati i database logici (userdb, datadb) e gli oggetti iniziali; agli avvii successivi PostgreSQL riutilizzerà i dati già presenti nei volumi.
Quando i microservizi vengono eseguiti in locale (al di fuori dei container), la connessione al database PostgreSQL avviene tramite la porta pubblicata dal container sull’host. La configurazione di default fornita dal progetto è già orientata a questo scenario e si basa sul file application.yml di ciascun servizio.
Per lo User Manager Service, application.yml definisce una configurazione del datasource analoga alla seguente:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/userdb
username: user
password: password
driver-class-name: org.postgresql.DriverPer il Data Collector Service la configurazione è simile, puntando al database logico datadb:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/datadb
username: user
password: password
driver-class-name: org.postgresql.DriverQueste impostazioni presuppongono che:
- il container PostgreSQL esposto da Docker pubblichi la porta 5432 sull’host (
5432:5432neldocker-compose.yml); - l’utente e la password configurati in
docker/env/postgres.envcoincidano con quelli utilizzati inapplication.yml.
Se si modificano i valori in postgres.env (ad esempio nome utente, password o porta esterna), è necessario:
- aggiornare i corrispondenti parametri in
application.yml; oppure - sovrascrivere le proprietà Spring Boot tramite variabili d’ambiente (
SPRING_DATASOURCE_URL,SPRING_DATASOURCE_USERNAME,SPRING_DATASOURCE_PASSWORD) nel contesto di esecuzione locale dei microservizi.
In questo modo la logica applicativa rimane invariata, mentre la configurazione può essere adattata con facilità a diversi ambienti mantenendo application.yml come base unica e coerente.
Una volta avviato il container PostgreSQL, la connettività può essere verificata indipendentemente dai microservizi:
- utilizzando un client PostgreSQL esterno (
psqlo client grafico) per connettersi alocalhost:5432con l’utente e la password configurati; - controllando che i database logici
userdbedatadbsiano effettivamente presenti e accessibili.
Dopo l’avvio dei microservizi in locale, i log di Spring Boot devono mostrare:
- la creazione del pool di connessioni verso
jdbc:postgresql://localhost:5432/...; - l’esecuzione delle migrazioni Flyway sul database corretto;
- l’assenza di eccezioni di tipo connection refused, authentication failed o database does not exist.
Eventuali errori di connessione indicano tipicamente uno dei seguenti problemi:
- container PostgreSQL non avviato o terminato inaspettatamente;
- porta diversa da
5432o non esposta correttamente sull’host; - credenziali in
application.ymlnon allineate con quelle effettive del database.
L’esecuzione locale dei microservizi può avvenire tramite Maven o tramite l’IDE utilizzato per lo sviluppo. In entrambi i casi, in assenza di profili espliciti, Spring Boot utilizza il profilo di default e le impostazioni definite in application.yml, già predisposte per l’utilizzo del database Dockerizzato su localhost:5432 e per la comunicazione gRPC tra i servizi.
Per avviare lo User Manager Service in locale tramite Maven:
cd user-manager-service
mvn spring-boot:runIl comando:
- compila il codice (se necessario);
- avvia l’applicazione Spring Boot utilizzando
application.ymlcome configurazione di riferimento; - espone le API REST sulla porta configurata (ad esempio
8081); - avvia il server gRPC sulla porta configurata (ad esempio
9090).
Per il Data Collector Service la procedura è analoga:
cd data-collector-service
mvn spring-boot:runIn questo caso l’applicazione:
- utilizza
application.ymlper connettersi al databasedatadbsulocalhost:5432; - configura il client gRPC verso lo User Manager Service all’indirizzo e porta definiti in configurazione (tipicamente
localhost:9090); - attiva lo scheduler per la raccolta periodica dei dati di volo, se abilitato.
È possibile avviare i due servizi in due terminali distinti, mantenendo in esecuzione il container PostgreSQL lanciato in precedenza.
Per l’avvio da IDE è sufficiente:
- importare ciascun microservizio come progetto Maven;
- creare una configurazione di esecuzione che punti alla classe
maindell’applicazione Spring Boot (UserManagerServiceApplicationeDataCollectorServiceApplication); - assicurarsi che non siano impostate variabili o parametri che attivino profili non desiderati (ad esempio
SPRING_PROFILES_ACTIVE), lasciando che l’applicazione utilizzi la configurazione predefinita inapplication.yml.
Se la configurazione è corretta, l’IDE mostrerà nei log di avvio:
- la connessione al database
localhost:5432; - l’applicazione delle migrazioni Flyway;
- l’apertura delle porte HTTP/gRPC previste.
A questo punto i microservizi saranno pronti per essere interrogati tramite browser, curl o Postman, come descritto nelle sezioni dedicate all’accesso ai servizi e ai flussi di validazione.
Una volta che PostgreSQL è in esecuzione in Docker e i microservizi sono attivi in locale, il sistema opera in modalità ibrida: il database è containerizzato, mentre le applicazioni sono eseguite direttamente sulla macchina host.
È opportuno verificare che le porte locali configurate per i microservizi non siano occupate da altri processi. Ad esempio, se lo User Manager Service espone le API REST su localhost:8081 e il Data Collector Service su localhost:8082, è possibile controllare rapidamente la raggiungibilità tramite un browser o comandi curl, ad esempio:
curl http://localhost:8081/actuator/health
curl http://localhost:8082/actuator/health(ammesso che gli endpoint di health siano abilitati). In assenza di actuator, è possibile utilizzare qualsiasi endpoint REST pubblico definito dai servizi.
Per validare il corretto funzionamento del sistema in modalità ibrida è possibile utilizzare le collection disponibili nella cartella postman/, configurando come base URL gli indirizzi locali dei microservizi. Alcuni esempi di smoke test includono:
- chiamare le API dello User Manager Service per registrare un nuovo utente e verificarne la persistenza nel
userdb; - utilizzare le API del Data Collector Service per registrare un aeroporto e associare un interesse utente–aeroporto;
- invocare gli endpoint di interrogazione dei voli (dopo che lo scheduler ha effettuato almeno un ciclo di raccolta) per verificare che i dati vengano correttamente estratti dal
datadb.
Questi test permettono di accertare che i microservizi locali comunichino correttamente con il database Dockerizzato, che le configurazioni di rete siano adeguate e che la logica applicativa operi come previsto in uno scenario di esecuzione ibrido.
Lo User Manager Service espone un set di API REST orientate alla gestione del ciclo di vita degli utenti, utilizzando l’e‑mail come identificatore univoco. Tutte le operazioni prevedono scambi in formato JSON su HTTP e seguono le convenzioni sui codici di stato descritte nelle sezioni precedenti.
In un ambiente standard, il servizio è esposto tramite un endpoint HTTP configurabile. I casi più comuni sono:
-
Esecuzione in locale:
- Base URL:
http://localhost:8080/api/users
- Base URL:
-
Esecuzione in Docker:
- All’interno della rete Docker:
http://user-manager-service:8080/api/users - Dall’host, tramite port‑mapping:
http://localhost:<HOST_PORT>/api/users(dove<HOST_PORT>è il valore configurato neldocker-compose.yml, tipicamente8080).
- All’interno della rete Docker:
Tutti gli endpoint dello User Manager Service derivano da questa base URL, aggiungendo eventuali path e parametri.
Le operazioni principali sono:
Registrazione di un nuovo utente (idempotente)
-
Metodo:
POST -
URL:
/api/users -
Body (JSON), esempio:
{ "email": "alice@example.com", "name": "Alice Doe" } -
Vincoli di validazione:
emailobbligatoria, in formato e‑mail valido;nameobbligatorio, con lunghezza entro i limiti previsti.
-
Semantica:
- se l’utente non esiste, viene creato un nuovo record e restituito con timestamp di creazione;
- se l’utente esiste già con la stessa e‑mail, l’operazione è idempotente e restituisce la rappresentazione dell’utente esistente senza creare duplicati.
Lettura di un utente per e‑mail
-
Metodo:
GET -
URL:
/api/users/{email} -
Path variable:
email: indirizzo e‑mail dell’utente da recuperare (deve rispettare i vincoli di formato).
-
Semantica:
- se l’utente esiste, viene restituita la sua rappresentazione completa (e‑mail, nome,
createdAt); - se l’utente non esiste, viene restituito un errore strutturato che segnala la risorsa mancante.
- se l’utente esiste, viene restituita la sua rappresentazione completa (e‑mail, nome,
Cancellazione di un utente
-
Metodo:
DELETE -
URL:
/api/users/{email} -
Path variable:
email: indirizzo e‑mail dell’utente da cancellare.
-
Semantica:
- in caso di successo, il record viene rimosso dal User DB;
- eventuali interessi associati nel Data DB rimangono a carico del Data Collector Service secondo le politiche applicative adottate.
Tutte le API REST dello User Manager Service espongono risposte in formato JSON, inclusi i casi di errore (ad esempio campi mancanti, formato non valido, risorse non trovate), secondo il modello di errore standard del sistema.
Per le operazioni esposte dallo User Manager Service valgono le seguenti convenzioni:
-
201 Created – registrazione di un nuovo utente (
POST /api/users) quando viene effettivamente creato un record:{ "email": "alice@example.com", "name": "Alice Doe", "createdAt": "2025-11-30T15:40:00Z" } -
200 OK – lettura riuscita o registrazione idempotente:
- risposta di
GET /api/users/{email}con un utente esistente; - risposta di
POST /api/usersquando l’utente era già presente e viene restituita la rappresentazione esistente.
- risposta di
-
204 No Content – cancellazione riuscita tramite
DELETE /api/users/{email}, senza body in risposta. -
400 Bad Request – input non valido:
- payload JSON non conforme (campi mancanti);
- e‑mail malformata nel body o nel path;
- violazioni di vincoli di validazione sui campi.
-
404 Not Found – risorsa non trovata:
- utente inesistente per
GEToDELETE /api/users/{email}.
- utente inesistente per
-
409 Conflict (eventuale) – violazione di vincoli di unicità non assorbita dalla logica di idempotenza.
-
5xx – errori interni non previsti o malfunzionamenti infrastrutturali; vengono comunque mappati in una risposta JSON strutturata con i campi standard (
timestamp,status,error,errorCode,message,path).
Il Data Collector Service espone API REST dedicate alla gestione degli interessi utente–aeroporto e all’interrogazione dei dati di volo raccolti tramite OpenSky. Tutte le operazioni seguono le stesse convenzioni di formato JSON e codici HTTP adottate per lo User Manager Service.
In un ambiente standard, il servizio è accessibile tramite:
-
Esecuzione in locale:
- Base URL per la gestione degli interessi:
http://localhost:8081/api/interests - Base URL per le interrogazioni sui voli:
http://localhost:8081/api/flights
- Base URL per la gestione degli interessi:
-
Esecuzione in Docker:
-
All’interno della rete Docker:
http://data-collector-service:8081/api/interestshttp://data-collector-service:8081/api/flights
-
Dall’host, tramite port‑mapping:
http://localhost:<HOST_PORT_INTERESTS>/api/interestshttp://localhost:<HOST_PORT_FLIGHTS>/api/flights
-
Tutti gli endpoint descritti nelle sottosezioni successive derivano da queste base URL.
La relazione tra utenti e aeroporti viene modellata tramite interessi utente–aeroporto, gestiti dalle API esposte sul path /api/interests. Ogni interesse collega un utente (identificato dall’e‑mail) a un aeroporto (identificato dal codice IATA/ICAO configurato nel catalogo).
Registrazione di un interesse utente–aeroporto
-
Metodo:
POST -
URL:
/api/interests -
Body (JSON), esempio:
{ "userEmail": "alice@example.com", "airportCode": "LIRF" } -
Semantica:
- validazione sintattica del payload;
- validazione dell’utente via gRPC verso lo User Manager Service;
- verifica dell’esistenza dell’aeroporto nel catalogo del Data Collector;
- verifica dell’assenza di un interesse duplicato per la coppia (
userEmail,airportCode); - creazione del nuovo interesse oppure restituzione idempotente di quello esistente.
-
Risposte principali:
201 Createdcon il DTO dell’interesse se viene creato un nuovo record;200 OKcon il DTO dell’interesse esistente se la coppia era già presente;400 Bad Requestin caso di payload non valido;404 Not Foundse l’utente non esiste o se l’aeroporto non è presente nel catalogo;409 Conflictin caso di violazione di vincoli di unicità non assorbita dalla logica applicativa.
Rimozione di un interesse
-
Metodo:
DELETE -
URL:
/api/interests -
Query parameters:
userEmail: e‑mail dell’utente;airportCode: codice dell’aeroporto.
-
Esempio di richiesta:
DELETE /api/interests?userEmail=alice@example.com&airportCode=LIRF -
Risposte principali:
204 No Contentin caso di rimozione riuscita;404 Not Foundse non esiste alcun interesse per la coppia indicata (a seconda della semantica scelta);400 Bad Requestse i parametri sono mancanti o non validi.
Elenco degli interessi per utente
-
Metodo:
GET -
URL:
/api/interests -
Query parameters:
userEmail: e‑mail dell’utente (obbligatorio).
-
Esempio di richiesta:
GET /api/interests?userEmail=alice@example.com -
Risposte principali:
200 OKcon una lista JSON di interessi presenti per l’utente; la lista può essere vuота se non sono registrati interessi;400 Bad Requestse l’e‑mail è mancante o non valida;404 Not Foundopzionale, se si decide di segnalare esplicitamente il caso di utente inesistente.
Il catalogo degli aeroporti utilizzato da queste API è gestito a livello di Data DB e viene popolato tramite gli script e le migrazioni del microservizio. Le API sugli interessi assumono che i codici aeroporto utilizzati nelle richieste siano coerenti con tale catalogo.
Le interrogazioni sui voli si appoggiano sul path /api/flights e sulle relative varianti. Gli endpoint operano sui dati storici memorizzati nella tabella flight_records, alimentata dallo scheduler interno che integra i dati forniti da OpenSky.
Ultimo volo in arrivo o partenza per aeroporto/direzione
-
Metodo:
GET -
URL:
/api/flights/last -
Query parameters:
airportCode– codice dell’aeroporto (obbligatorio);direction– direzione del volo, ad esempioARRIVALoDEPARTURE(obbligatorio).
-
Esempio di richiesta:
GET /api/flights/last?airportCode=LIRF&direction=ARRIVAL -
Risposte principali:
-
200 OKcon un oggetto JSON che descrive l’ultimo volo registrato per l’aeroporto/direzione indicati (campi tipici:flightNumber,actualTime,scheduledTime,status,delayMinutes,collectedAt); -
400 Bad Requestsedirectionnon è ammessa o se i parametri sono mancanti/non validi; -
404 Not Foundse:- non esistono voli registrati per la combinazione indicata;
- l’aeroporto non è presente nel catalogo.
-
Media dei voli sugli ultimi N giorni
-
Metodo:
GET -
URL:
/api/flights/average -
Query parameters:
airportCode– codice dell’aeroporto (obbligatorio);direction–ARRIVALoDEPARTURE(obbligatorio);days– numero di giorni da considerare a ritroso rispetto all’istante corrente (obbligatorio, intero > 0).
-
Esempio di richiesta:
GET /api/flights/average?airportCode=LIRF&direction=DEPARTURE&days=7 -
Semantica:
- il servizio calcola l’intervallo
[now − days, now]; - conta i flight records corrispondenti a aeroporto/direzione nell’intervallo;
- restituisce il numero totale di voli e la media giornaliera (
totalFlights / days).
- il servizio calcola l’intervallo
-
Risposte principali:
200 OKcon un oggetto JSON che include, tra gli altri, i campiairportCode,direction,days,totalFlights,averagePerDay,from,to;400 Bad Requestsedays <= 0, se i parametri sono mancanti o se gli intervalli temporali risultano mal formati;404 Not Foundse l’aeroporto non è presente nel catalogo.
Interrogazioni su intervalli temporali arbitrari
-
Metodo:
GET -
URL:
/api/flights -
Query parameters:
airportCode– codice dell’aeroporto (obbligatorio);direction–ARRIVALoDEPARTURE(obbligatorio);from– istante di inizio intervallo, in formato ISO‑8601 (opzionale);to– istante di fine intervallo, in formato ISO‑8601 (opzionale).
In assenza di parametri temporali, il servizio può applicare una finestra temporale di default (ad esempio le ultime N ore) per evitare interrogazioni non limitate nel tempo.
-
Esempio di richiesta:
GET /api/flights?airportCode=LIRF&direction=ARRIVAL&from=2025-11-29T00:00:00Z&to=2025-11-30T00:00:00Z -
Risposte principali:
200 OKcon una lista JSON di voli che soddisfano i criteri indicati; la lista può essere vuota se nell’intervallo specificato non sono presenti voli;400 Bad Requestse i parametri temporali sono mal formati o sefrom > to, oppure sedirectionha un valore non ammesso;404 Not Foundse l’aeroporto non è presente nel catalogo.
Gli endpoint di interrogazione applicano un pattern uniforme di validazione → risoluzione aeroporto → query sul Data DB → mapping del risultato in DTO di risposta, garantendo coerenza semantica e prevedibilità per il client.
L’interfaccia gRPC di validazione utente costituisce il canale di comunicazione service‑to‑service tra Data Collector Service e User Manager Service. Questo canale è interno all’architettura e non è esposto direttamente verso client esterni.
Lo User Manager Service espone un servizio gRPC denominato, a livello concettuale, UserValidationService, definito in un file .proto dedicato. La firma principale è:
service UserValidationService {
rpc CheckUserExists (UserValidationRequest)
returns (UserValidationResponse);
}
message UserValidationRequest {
string email = 1;
}
message UserValidationResponse {
bool exists = 1;
}Elementi chiave dell’interfaccia:
- Servizio gRPC:
UserValidationService, responsabile della validazione dell’esistenza di un utente a partire dall’e‑mail. - Request:
UserValidationRequest, contenente il campoemailda verificare. - Response:
UserValidationResponse, contenente il campo booleanoexistsche indica se l’utente è presente nel dominio dello User Manager Service.
Sul lato User Manager, l’implementazione server del servizio (ad esempio UserValidationGrpcService) riceve la richiesta, interroga il User DB e restituisce una risposta coerente con lo stato corrente del sistema.
A livello di trasporto, il servizio gRPC è tipicamente esposto sulla stessa macchina del User Manager Service, su una porta dedicata (configurabile tramite proprietà applicative), con serializzazione Protobuf e supporto a connessioni sicure qualora richiesto dall’ambiente di esecuzione.
Il Data Collector Service utilizza un client gRPC generato a partire dalla stessa definizione .proto (ad esempio UserValidationGrpcClient) per validare gli utenti prima di creare nuovi interessi utente–aeroporto.
Il flusso tipico di utilizzo è il seguente:
- il client REST invoca
POST /api/interestssul Data Collector Service fornendouserEmaileairportCode; - il Data Collector costruisce una richiesta gRPC
UserValidationRequestcon il campoemailvalorizzato auserEmail; - il client gRPC chiama
CheckUserExistssullo User Manager Service; - se
UserValidationResponse.existsètrue, il Data Collector prosegue con la verifica dell’aeroporto e la creazione dell’interesse; - se
existsèfalse, il Data Collector traduce la condizione in un errore applicativo, tipicamente404 Not Foundcon codice di erroreUSER_NOT_FOUND.
L’interfaccia gRPC non richiede configurazione da parte dei consumatori finali del sistema, ma è rilevante in ottica di integrazione e manutenzione, poiché consente di mantenere separati i domini applicativi (utenti vs. dati di volo) evitando accessi diretti incrociati ai rispettivi database.
Le Postman collections fornite nel repository consentono di esercitare in modo rapido e controllato le API esposte dai due microservizi. Tutti i file necessari sono collocati nella cartella:
postman/
All’interno di questa directory sono presenti, in particolare:
- un file JSON dedicato alle API dello User Manager Service (ad esempio
user-manager-api.postman_collection.json); - un file JSON dedicato alle API del Data Collector Service (ad esempio
data-collector-api.postman_collection.json).
Ogni collection contiene richieste preconfigurate con path, metodi HTTP, header e payload di esempio. Le uniche informazioni che richiedono un adattamento al contesto di esecuzione sono gli indirizzi host, le porte e, ove necessario, i token o gli identificativi di ambiente.
L’utilizzo delle collection parte dal loro import in Postman, che può avvenire sia tramite interfaccia grafica sia trascinando i file JSON nell’applicazione.
- Avviare Postman.
- Selezionare la voce Import.
- Scegliere l’opzione File e selezionare i file JSON nella cartella
postman/. - Confermare l’import: le collection compariranno nella sezione Collections con il nome definito nel file.
Una volta importate, le richieste possono essere eseguite singolarmente oppure organizzate in folder logici all’interno di ogni collection, riflettendo i diversi gruppi di API (gestione utenti, interessi, interrogazioni voli).
La collection dedicata allo User Manager Service contiene le richieste fondamentali per gestire il ciclo di vita dell’utente. Tipicamente include:
- Create / Register User – richiesta
POSTverso/api/userscon body JSON di esempio; - Get User by Email – richiesta
GETverso/api/users/{email}; - Delete User – richiesta
DELETEverso/api/users/{email}.
Ogni richiesta è preconfigurata con:
- metodo HTTP corretto;
- path relativo dell’endpoint;
- header standard (ad esempio
Content-Type: application/jsonper le richieste con body); - payload di esempio, modificabile per simulare diversi scenari.
La base URL viene normalmente parametrizzata tramite una variabile di ambiente Postman (ad esempio {{user_manager_base_url}}), in modo che il passaggio da esecuzione locale a esecuzione in Docker richieda soltanto la modifica del valore di tale variabile.
La collection dedicata al Data Collector Service copre i principali casi d’uso relativi agli interessi utente–aeroporto e alle interrogazioni sui voli. Le richieste tipiche includono:
- Create Interest – richiesta
POSTverso/api/interestscon body contenenteuserEmaileairportCode; - List Interests for User – richiesta
GETverso/api/interestscon query parameteruserEmail; - Delete Interest – richiesta
DELETEverso/api/interestscon query parameteruserEmaileairportCode; - Get Last Flight – richiesta
GETverso/api/flights/lastcon parametriairportCodeedirection; - Get Average Flights over Last N Days – richiesta
GETverso/api/flights/averagecon parametriairportCode,direction,days; - Query Flights by Time Interval – richiesta
GETverso/api/flightscon parametriairportCode,direction,from,to.
Anche in questo caso, le richieste utilizzano in genere una variabile di ambiente Postman per la base URL (ad esempio {{data_collector_base_url}}), consentendo di cambiare velocemente host e porta senza modificare manualmente ogni singola richiesta.
Per poter eseguire le richieste contro un’istanza specifica del sistema (locale o Docker), è opportuno definire in Postman uno o più Environment dedicati, in cui parametrizzare host, porta e base URL. Una configurazione tipica prevede:
-
variabile
user_manager_base_url, ad esempio:http://localhost:8080in esecuzione locale;http://localhost:<HOST_PORT_UMS>in esecuzione Docker con port‑mapping;
-
variabile
data_collector_base_url, ad esempio:http://localhost:8081in esecuzione locale;http://localhost:<HOST_PORT_DCS>in esecuzione Docker;
-
eventuali variabili aggiuntive, come:
default_user_emailper simulare uno specifico utente;default_airport_codeper impostare un aeroporto di interesse di riferimento.
Procedura consigliata per la configurazione:
-
In Postman, aprire la sezione Environments.
-
Creare un nuovo environment, ad esempio chiamato
Flight Monitoring Local. -
Aggiungere le variabili desiderate, ad esempio:
Key Value user_manager_base_urlhttp://localhost:8080data_collector_base_urlhttp://localhost:8081default_user_emailalice@example.comdefault_airport_codeLIRF -
Selezionare l’environment appena creato dal menu a tendina in alto a destra in Postman.
All’interno delle collection, le richieste faranno riferimento a queste variabili tramite la sintassi {{user_manager_base_url}}, {{data_collector_base_url}}, {{default_user_email}} e così via. Questo approccio rende semplice:
- utilizzare la stessa collection contro ambienti diversi (sviluppo, test, produzione);
- modificare host e porta da un unico punto di configurazione.
Le collection sono progettate per supportare scenari end-to-end che attraversano entrambi i microservizi, simulando il comportamento di un client applicativo reale. Le sezioni seguenti descrivono alcuni flussi tipici che possono essere eseguiti direttamente da Postman.
-
Assicurarsi che:
- lo User Manager Service sia in esecuzione e raggiungibile all’URL indicato da
{{user_manager_base_url}}; - il database PostgreSQL sia correttamente inizializzato.
- lo User Manager Service sia in esecuzione e raggiungibile all’URL indicato da
-
Aprire nella collection User Manager API la richiesta Create / Register User.
-
Verificare il body JSON, ad esempio:
{ "email": "alice@example.com", "name": "Alice Doe" } -
Inviare la richiesta e verificare la risposta:
201 Createdse l’utente è stato creato ex novo;200 OKse l’utente era già presente ed è gestita la semantica idempotente.
-
Facoltativamente, eseguire la richiesta Get User by Email per confermare la persistenza del record.
-
Verificare che l’utente da utilizzare (ad esempio
{{default_user_email}}) sia stato registrato tramite lo scenario precedente. -
Assicurarsi che il Data Collector Service sia in esecuzione e che
{{data_collector_base_url}}punti correttamente al servizio. -
Aprire nella collection Data Collector API la richiesta Create Interest.
-
Configurare il body JSON, ad esempio:
{ "userEmail": "alice@example.com", "airportCode": "LIRF" } -
Inviare la richiesta e osservare la risposta:
201 Createdin caso di creazione di un nuovo interesse;200 OKse l’interesse era già presente ed è gestita la semantica idempotente;404 Not Foundse l’utente non esiste (Data Collector non riesce a validarlo via gRPC) o se l’aeroporto non è presente nel catalogo.
-
Utilizzare la richiesta List Interests for User per verificare che l’interesse sia stato correttamente registrato.
Per poter interrogare lo stato dei voli è necessario che lo scheduler del Data Collector Service abbia già eseguito almeno un ciclo di raccolta tramite OpenSky, popolando la tabella flight_records nel Data DB.
-
Verificare, tramite i log del Data Collector Service, che la raccolta periodica dei voli sia attiva e che non siano presenti errori nell’interazione con le OpenSky Network API.
-
In Postman, aprire la richiesta Get Last Flight nella collection Data Collector API.
-
Impostare i parametri di query, ad esempio:
airportCode=LIRF direction=ARRIVAL -
Inviare la richiesta e verificare la risposta
200 OKcon i dettagli dell’ultimo volo registrato per la combinazione aeroporto/direzione indicata. -
Utilizzare poi la richiesta Get Average Flights over Last N Days, configurando parametri come:
airportCode=LIRF direction=DEPARTURE days=7e verificare la restituzione di
totalFlightseaveragePerDaynel JSON di risposta. -
Infine, esercitare la richiesta Query Flights by Time Interval impostando i parametri
frometo(in formato ISO‑8601) per analizzare uno specifico intervallo temporale, ad esempio:from=2025-11-29T00:00:00Z to=2025-11-30T00:00:00Ze verificare che la lista di voli restituita sia coerente con i dati attesi.
Questi scenari, combinati, permettono di validare l’intero flusso: dalla registrazione dell’utente alla definizione degli interessi sugli aeroporti, fino alla consultazione dei dati di volo raccolti e storicizzati dal sistema.
La prima forma di diagnostica consiste nel verificare che i microservizi siano effettivamente raggiungibili e che stiano esponendo le API previste sulle porte attese.
Un controllo preliminare può essere effettuato direttamente dal terminale utilizzando curl oppure tramite browser o strumenti come Postman.
-
Verifica della raggiungibilità dello User Manager Service (esempio esecuzione locale):
curl -i http://localhost:8080/
-
Verifica della raggiungibilità del Data Collector Service (esempio esecuzione locale):
curl -i http://localhost:8081/
La risposta non deve necessariamente contenere un payload specifico; è sufficiente che il server risponda con un codice 2xx o 3xx per confermare che il processo sia in ascolto sulla porta indicata. Risposte 5xx o errori di connessione (ad esempio connection refused o timeout) indicano un problema a livello di avvio del servizio, configurazione della porta o connettività.
In ambiente Docker, la verifica avviene analogamente utilizzando il mapping delle porte configurato nel docker-compose.yml, ad esempio:
curl -i http://localhost:<HOST_PORT_UMS>/
curl -i http://localhost:<HOST_PORT_DCS>/Se gli endpoint di health (ad esempio basati su Spring Boot Actuator) sono abilitati, rappresentano il metodo preferenziale per verificare lo stato interno del servizio.
Esempio di chiamata ad un endpoint di health standard:
curl -i http://localhost:8080/actuator/healthUna risposta tipica, in caso di servizio UP, può essere del tipo:
{
"status": "UP"
}Endpoint analoghi possono essere esposti anche dal Data Collector Service, ad esempio:
curl -i http://localhost:8081/actuator/healthSe gli endpoint di health non sono disponibili o non risultano abilitati, è possibile utilizzare un semplice ping applicativo verso un endpoint REST funzionale noto, ad esempio una richiesta di lettura con parametri controllati:
-
per lo User Manager Service:
curl -i "http://localhost:8080/api/users/{emailDiTest}" -
per il Data Collector Service:
curl -i "http://localhost:8081/api/interests?userEmail={emailDiTest}"
In questo caso, anche una risposta 4xx (ad esempio 404 Not Found per utente inesistente) può essere considerata un segnale positivo, in quanto indica che il servizio è attivo e sta elaborando correttamente la richiesta.
I log applicativi costituiscono lo strumento principale per comprendere lo stato interno dei microservizi, diagnosticare errori e analizzare il comportamento del sistema durante le varie fasi di esecuzione. Il logging è gestito da Spring Boot e può essere indirizzato sia allo standard output (utilizzato in ambiente Docker) sia a file locali.
Quando i servizi vengono eseguiti in Docker, i log sono accessibili tramite i comandi docker compose logs. Dalla cartella docker/ è possibile:
-
visualizzare i log di tutti i servizi:
docker compose logs
-
seguire i log in streaming:
docker compose logs -f
-
filtrare i log di un singolo servizio, ad esempio:
docker compose logs -f user-manager-service
docker compose logs -f data-collector-service
-
limitare il numero di righe iniziali, ad esempio le ultime 200:
docker compose logs --tail=200 -f data-collector-service
In caso di esecuzione locale senza Docker, i log sono normalmente visibili direttamente nel terminale o nella console dell’IDE da cui è stato avviato il microservizio (mvn spring-boot:run, run configuration, ecc.).
Alcune categorie di messaggi di log sono particolarmente significative per la diagnostica.
Fase di bootstrap del servizio
-
Messaggi relativi all’avvio di Spring Boot, ad esempio:
Started UserManagerApplication in ... secondsStarted DataCollectorApplication in ... seconds
-
Messaggi di inizializzazione del contesto, come:
- registrazione dei bean e mapping degli endpoint REST (
Mapped "{[/api/users],methods=[POST]}" ...); - attivazione degli scheduler nel Data Collector Service.
- registrazione dei bean e mapping degli endpoint REST (
La presenza di questi messaggi indica che il servizio è stato avviato correttamente e ha completato la fase di bootstrap.
Connessione al database e migrazioni Flyway
-
Messaggi di connessione al datasource, ad esempio:
HikariPool-1 - Starting...HikariPool-1 - Start completed.
-
Messaggi di Flyway, come:
Flyway Community Edition ...;Current version of schema "public": ...;Successfully applied ... migration(s).
Eventuali errori in questa fase possono manifestarsi con messaggi quali:
org.postgresql.util.PSQLException: Connection refusedocould not connect to server: indicano problemi di connettività verso PostgreSQL (host, porta o credenziali errate, database non disponibile);FlywayException: Validate failedo errori di migrazione: indicano inconsistenze tra le migrazioni attese e lo stato corrente dello schema.
Interazione gRPC tra Data Collector e User Manager
Nel Data Collector Service è importante monitorare:
-
la creazione del canale gRPC verso lo User Manager Service;
-
eventuali errori di chiamata durante la validazione degli utenti, ad esempio:
UNAVAILABLE: io exception(problemi di rete o servizio non raggiungibile);DEADLINE_EXCEEDED(timeout sulla chiamata gRPC);- messaggi applicativi che indicano l’assenza dell’utente (
User not found for email ...).
Questi log sono cruciali per diagnosticare problemi di integrazione tra i due microservizi.
Interazione con le OpenSky Network API
Per il Data Collector Service, i log relativi al client OpenSky permettono di verificare:
- il corretto ottenimento dei token OAuth2 (
Successfully obtained access token); - eventuali errori di autenticazione o autorizzazione (
401 Unauthorized,403 Forbidden); - errori di rete (
Read timed out,Connection reset); - eventuali limiti di rate limiting o vincoli sui parametri delle richieste.
È utile prestare attenzione a messaggi che segnalano fallimenti ripetuti nella raccolta dei dati, poiché possono indicare problemi di configurazione delle credenziali o modifiche lato provider esterno.
Errori applicativi e REST
Gli errori a livello di API REST vengono generalmente riportati sotto forma di eccezioni Spring (ad esempio MethodArgumentNotValidException, HttpMessageNotReadableException) e di log generati dal Global Exception Handler. È opportuno monitorare:
- errori sistematici di validazione input (che possono indicare problemi nei client);
- errori
500 Internal Server Errorricorrenti su endpoint specifici, che suggeriscono bug nella logica applicativa.
La diagnostica del database PostgreSQL consente di verificare lo stato degli schemi, la corretta applicazione delle migrazioni e la presenza dei dati attesi. È possibile accedere al database sia tramite CLI (psql) sia tramite client grafici esterni.
Quando PostgreSQL è eseguito in Docker, è possibile accedere alla shell del container e utilizzare psql direttamente dall’interno:
cd docker
docker compose exec postgres bashAll’interno del container:
psql -U flight_monitor -d userdbper connettersi al User DB, oppure:
psql -U flight_monitor -d datadbper connettersi al Data DB.
Da psql è possibile, ad esempio:
-
elencare le tabelle:
\dt
-
esplorare la struttura di una tabella specifica:
\d users
oppure
\d flight_records
In alternativa, se PostgreSQL espone la porta 5432 sull’host (5432:5432 nel docker-compose.yml), è possibile utilizzare psql o un client grafico (ad esempio DBeaver, DataGrip, pgAdmin) direttamente dall’host, specificando:
- host:
localhost; - port:
5432(o altra porta mappata); - database:
userdbodatadb; - user:
flight_monitor(o altro utente configurato); - password: quella definita in
postgres.env.
La creazione di schemi e tabelle è gestita dai microservizi tramite Flyway. Per verificare che le migrazioni siano state applicate correttamente:
-
Connettersi al database di interesse (
userdbodatadb) tramitepsqlo client esterno. -
Controllare la tabella
flyway_schema_history:SELECT installed_rank, version, description, success FROM flyway_schema_history ORDER BY installed_rank;
Tutte le migrazioni rilevanti devono avere
success = true. Eventuali record consuccess = falseindicano problemi durante l’applicazione di una migrazione. -
Verificare la presenza delle tabelle attese.
Nel User DB:
\dt
Ci si aspetta di trovare almeno la tabella
userse la tabellaflyway_schema_history.Nel Data DB:
\dt
Ci si aspetta di trovare le tabelle
airports,user_airport_interest,flight_records, oltre alla tabellaflyway_schema_history. -
Effettuare alcune query di controllo sui dati, ad esempio:
-
numero di utenti registrati:
SELECT COUNT(*) FROM users;
-
numero di aeroporti censiti:
SELECT COUNT(*) FROM airports;
-
numero di record di volo raccolti:
SELECT COUNT(*) FROM flight_records;
-
Se il numero di record in flight_records è pari a zero nonostante lo scheduler del Data Collector Service sia attivo, è opportuno:
- controllare i log del servizio per capire se le chiamate a OpenSky hanno successo;
- verificare che esistano interessi utente–aeroporto (tabella
user_airport_interest) per almeno un aeroporto; - controllare che i parametri temporali utilizzati dallo scheduler siano configurati correttamente.
Questi controlli permettono di isolare rapidamente problemi legati alla fase di bootstrap (mancata applicazione delle migrazioni), alla popolazione iniziale dei dati (assenza di aeroporti o interessi) o alla raccolta periodica dei voli (scheduler non attivo o errori nelle chiamate alle OpenSky Network API).
La fase di build può fallire per prerequisiti mancanti o per errori nella costruzione delle immagini Docker. Questa sezione elenca i casi più frequenti e le azioni consigliate per risolverli.
Quando si esegue la build senza Docker (ad esempio con mvn clean package o mvn spring-boot:run), sono necessari un JDK supportato e Apache Maven correttamente installati e presenti nel PATH.
Sintomi tipici
-
Il comando
mvnnon viene riconosciuto:'mvn' is not recognized as an internal or external command -
Il comando
javanon è presente o punta a una versione non supportata:'java' is not recognized as an internal or external commandoppure, in caso di versione non compatibile, errori del tipo:
Unsupported class file major version
Verifiche e rimedi
-
Verificare la versione di Java:
java -version
Assicurarsi che sia installato un JDK compatibile (ad esempio JDK 17 o 21) e non un JRE obsoleto.
-
Verificare la versione di Maven:
mvn -v
Controllare che la versione riportata sia >= 3.8.x.
-
In caso di assenza dei comandi, installare JDK e Maven secondo le linee guida del sistema operativo in uso e aggiornare il
PATHin modo che punti alle directory corrette. -
Se dopo l’installazione persistono problemi, verificare l’eventuale presenza di più versioni di Java o Maven e assicurarsi che quella attivata sia coerente con i requisiti del progetto.
La build tramite Docker Compose (docker compose build o docker compose up --build) può fallire per diversi motivi: problemi di rete nel download delle dipendenze, errori di compilazione del codice, configurazioni errate dei Dockerfile.
Sintomi tipici
-
Errori durante la fase
mvn clean packageall’interno dello stage di build:[ERROR] Failed to execute goal ... on project user-manager-service -
Errori nel recupero delle dipendenze Maven (timeout, errori DNS):
Could not resolve dependencies for project ... -
Errori legati al
Dockerfile(path errati, file mancanti):COPY failed: file not found in build context
Verifiche e rimedi
-
Verificare che la build Maven locale (fuori da Docker) vada a buon fine per ciascun microservizio:
cd user-manager-service mvn clean package cd ../data-collector-service mvn clean package
Se la build locale fallisce, risolvere prima gli errori riportati (problemi di compilazione, test falliti, dipendenze mancanti).
-
Controllare che il contesto di build indicato nel
docker-compose.ymlcorrisponda alla radice di ciascun microservizio e che i percorsi neiDockerfile(ad esempioCOPY pom.xml,COPY src/) siano coerenti con la struttura effettiva del progetto. -
In caso di errori di rete nel download delle dipendenze Maven durante la build Docker, verificare:
- la connettività verso Internet dal nodo che esegue Docker;
- eventuali proxy o firewall che possano bloccare l’accesso ai repository Maven pubblici.
-
Se Docker riutilizza una cache di build non coerente, può essere utile forzare la ricostruzione senza cache:
docker compose build --no-cache
-
In presenza di messaggi di errore generici, eseguire la build in modo verboso (ad esempio aggiungendo
-Xa Maven nello stage di build) per ottenere maggiori dettagli.
Una volta completata la build, la fase di esecuzione può essere ostacolata da problemi legati al database, alla connettività tra servizi o alle integrazioni esterne.
Sintomi tipici
-
Il container PostgreSQL non risulta in stato
runningdopodocker compose up:docker compose ps
mostra il servizio
postgrescon statoexitedounhealthy. -
I log del container mostrano errori in fase di bootstrap, ad esempio:
database files are incompatible with serveroppure
FATAL: password authentication failed for user "flight_monitor"
Verifiche e rimedi
-
Controllare i log del container PostgreSQL:
cd docker docker compose logs postgresIdentificare eventuali messaggi di errore relativi a:
- credenziali errate (
POSTGRES_USER,POSTGRES_PASSWORD); - conflitti con dati preesistenti nei volumi;
- errori negli script di inizializzazione.
- credenziali errate (
-
Verificare che le variabili d’ambiente in
postgres.envsiano coerenti con quelle utilizzate dai microservizi (services.env), in particolare utente, password e nomi dei database logici. -
In caso di problemi legati a dati corrotti o a modifiche incompatibili della configurazione, può essere necessario rimuovere i volumi associati al database (attenzione: questa operazione cancella tutti i dati persistenti):
docker compose down -v docker compose up -d postgres
-
Verificare che la porta host configurata per PostgreSQL non sia già occupata da un’installazione locale del database o da altri servizi. In caso di conflitto, adeguare il port mapping nel
docker-compose.ymlo fermare il servizio in conflitto.
Sintomi tipici
-
Nei log dei microservizi compaiono errori di tipo:
org.postgresql.util.PSQLException: Connection refusedoppure
Connection to postgres:5432 refused -
Le applicazioni non completano la fase di avvio e si arrestano con errori legati al datasource.
Verifiche e rimedi
-
Verificare che il container PostgreSQL sia effettivamente in esecuzione e in stato
healthy:docker compose ps
-
Controllare che il nome host del database utilizzato dai microservizi (
DB_HOST) sia coerente con il nome del servizio neldocker-compose.yml(ad esempiopostgres). In un ambiente Docker, non deve essere utilizzatolocalhostcome host del database all’interno dei container. -
Verificare che porta, utente, password e nome del database coincidano tra i file
.enve le property Spring Boot (per i profilidockero equivalenti). -
Se i microservizi vengono eseguiti in locale contro un database Dockerizzato, assicurarsi di aver adattato il
DB_HOSTalocalhoste che il port mapping (5432:5432o equivalente) sia correttamente configurato. -
In caso di errori di autenticazione (
password authentication failed), controllare che l’utente indicato (DB_USERNAME) esista effettivamente in PostgreSQL e che la password impostata inservices.envcoincida con quella dipostgres.env.
Sintomi tipici
-
Nei log del Data Collector Service compaiono errori durante l’ottenimento del token OAuth2, ad esempio:
401 Unauthorized invalid_clientoppure
403 Forbidden -
Le richieste alle OpenSky Network API falliscono sistematicamente e lo scheduler non riesce a popolare la tabella
flight_records.
Verifiche e rimedi
-
Verificare che le variabili d’ambiente
OPEN_SKY_CLIENT_IDeOPEN_SKY_CLIENT_SECRETsiano impostate con valori reali e non con placeholder (ad esempioyour_client_id). -
Controllare che gli endpoint configurati (
OPEN_SKY_AUTH_BASE_URL,OPEN_SKY_API_BASE_URL) siano corretti e aggiornati rispetto alla documentazione ufficiale di OpenSky. -
Assicurarsi che l’account OpenSky associato alle credenziali sia attivo e abilitato all’utilizzo delle API richieste.
-
Esaminare i log completi del Data Collector Service durante il tentativo di autenticazione per individuare dettagli aggiuntivi restituiti dal server OAuth2 (errori di formato della richiesta, grant type non supportato, scope non valido).
-
In presenza di errori intermittenti dovuti a problemi di rete o di disponibilità del servizio OpenSky, valutare l’introduzione di meccanismi di retry e backoff (se non già presenti) o eseguire nuovamente il sistema in un momento successivo.
Le seguenti verifiche guidano un percorso step-by-step per isolare i problemi più comuni, partendo dallo strato di configurazione fino ai singoli container.
-
Controllare il contenuto dei file
.envnella cartelladocker/env/(postgres.env,services.env) e assicurarsi che non contengano valori evidentemente errati o placeholder. -
Dal terminale, verificare che le variabili critiche siano effettivamente visibili nel contesto da cui verrà lanciato
docker compose. Ad esempio:echo "$DB_HOST" echo "$DB_USERNAME" echo "$OPEN_SKY_CLIENT_ID"
Se i valori non risultano impostati, è possibile che vengano letti esclusivamente dai file
.enva livello di Docker Compose (in tal caso il controllo va effettuato leggendo direttamente tali file) o che sia necessario esportarli manualmente per l’esecuzione locale dei microservizi. -
Verificare eventuali errori di digitazione nei nomi delle variabili, tanto nei file
.envquanto nelle proprietà Spring Boot che le referenziano (ad esempio${DB_HOST}vs${DB_HOSTNAME}).
-
Controllare che le porte configurate per PostgreSQL e per i microservizi non siano già occupate da altri processi sull’host. È possibile utilizzare comandi come:
-
su sistemi Unix-like:
lsof -i :5432 lsof -i :8080 lsof -i :8081
-
su Windows:
netstat -ano | findstr ":5432" netstat -ano | findstr ":8080" netstat -ano | findstr ":8081"
-
-
Se una porta risulta occupata, identificare il processo che la utilizza e valutare se può essere arrestato o se è opportuno modificare il port mapping nel
docker-compose.ymlo la porta di ascolto del servizio. -
Dopo ogni modifica di port mapping, ricordarsi di aggiornare le configurazioni dei client (Postman, script di test) e le variabili di ambiente correlate (ad esempio
user_manager_base_url,data_collector_base_urlin Postman).
-
Elencare lo stato di tutti i servizi definiti in
docker-compose.yml:cd docker docker compose psVerificare che tutti i container attesi siano in stato
runningohealthy. -
In caso di problemi con un servizio specifico, esaminare i log dedicati:
docker compose logs user-manager-service docker compose logs data-collector-service docker compose logs postgres
-
Per analizzare il comportamento in tempo reale, utilizzare l’opzione
-f:docker compose logs -f user-manager-service
e ripetere le operazioni che causano l’errore (avvio del sistema, chiamate API di test) osservando i messaggi che compaiono.
-
Prestare particolare attenzione a:
- stack trace di eccezioni non gestite;
- errori di connessione verso database o servizi esterni;
- errori di validazione legati a input non conformi.
-
Se nonostante l’analisi dei log il problema rimane poco chiaro, è possibile aumentare temporaneamente il livello di log per determinati package o componenti (ad esempio impostando il livello
DEBUGper i package di integrazione con OpenSky o con PostgreSQL) attraverso le proprietà Spring Boot dedicate o file di configurazione del logging.
Lo scenario di smoke test ha l’obiettivo di verificare che l’intera piattaforma sia in grado di:
- avviarsi correttamente;
- accettare richieste di gestione utenti;
- registrare interessi utente–aeroporto;
- raccogliere e rendere disponibili dati di volo di base.
-
Assicurarsi che i prerequisiti hardware e software siano soddisfatti e che le variabili d’ambiente critiche siano state configurate.
-
Posizionarsi nella directory
docker/della repository:cd docker -
Avviare l’intero sistema in modalità containerizzata:
docker compose up --build -d
-
Verificare lo stato dei servizi:
docker compose ps
Tutti i container devono risultare in stato
runningohealthy. -
Controllare rapidamente i log per accertarsi dell’assenza di errori gravi in fase di bootstrap:
docker compose logs --tail=100
In particolare, è opportuno verificare che:
- PostgreSQL sia operativo e pronto ad accettare connessioni;
- le migrazioni Flyway siano state applicate con successo;
- i microservizi abbiano completato la fase di avvio ed espongano le porte previste.
-
Utilizzando Postman o
curl, inviare una richiestaPOSTallo User Manager Service per creare un utente di test, ad esempio:curl -i -X POST "http://localhost:<HOST_PORT_UMS>/api/users" \ -H "Content-Type: application/json" \ -d '{ "email": "smoke.user@example.com", "name": "Smoke User" }'
-
Verificare che la risposta abbia uno dei seguenti codici:
201 Createdse l’utente viene creato ex novo;200 OKse la logica applicativa prevede idempotenza sulla creazione e l’utente esiste già.
-
Accertarsi che il payload di risposta contenga almeno l’indirizzo e‑mail e gli altri campi essenziali dell’utente.
-
Facoltativamente, connettersi al database
userdbe verificare la presenza dell’utente nella tabellausers, ad esempio:SELECT * FROM users WHERE email = 'smoke.user@example.com';
-
Se non già presente, scegliere un codice aeroporto valido e coerente con la configurazione del sistema (ad esempio un codice IATA o ICAO caricato nella tabella
airports). -
Invocare l’endpoint REST del Data Collector Service per creare un interesse utente–aeroporto, ad esempio:
curl -i -X POST "http://localhost:<HOST_PORT_DCS>/api/interests" \ -H "Content-Type: application/json" \ -d '{ "userEmail": "smoke.user@example.com", "airportCode": "LIRF" }'
-
Verificare che la risposta sia
201 Createdo200 OK, in base alla semantica implementata. -
Controllare che un’eventuale risposta di errore (
404 Not Found,400 Bad Request) sia coerente con la causa (utente non esistente, codice aeroporto non valido, ecc.) e che nei log del Data Collector Service non compaiano eccezioni inattese. -
Facoltativamente, interrogare il database
datadbper verificare la presenza dell’interesse nella tabellauser_airport_interest, ad esempio:SELECT * FROM user_airport_interest WHERE user_email = 'smoke.user@example.com' AND airport_id = (SELECT id FROM airports WHERE code = 'LIRF');
-
Attendere che lo scheduler del Data Collector Service esegua almeno un ciclo di raccolta dei dati di volo per gli aeroporti con interessi attivi. L’intervallo di esecuzione è definito dalla configurazione del servizio (cron o intervallo fisso).
-
Monitorare i log del Data Collector Service per individuare messaggi che indicano:
- l’avvenuta autenticazione verso OpenSky;
- il successo delle chiamate alle API esterne;
- l’inserimento di nuovi record nella tabella
flight_records.
-
Interrogare il database
datadbper verificare la presenza di record di volo associati all’aeroporto di test, ad esempio:SELECT COUNT(*) FROM flight_records WHERE airport_code = 'LIRF';
-
Utilizzare le API REST del Data Collector Service (ad esempio
GET /api/flights/lastoGET /api/flights/average) per controllare che i dati appena raccolti siano effettivamente esposti e interrogabili.
Lo scenario di validazione dell’at-most-once semantics ha lo scopo di verificare che operazioni concettualmente idempotenti (come la registrazione di un utente o di un interesse utente–aeroporto) non generino duplicati né in memoria né a livello di database.
-
Assicurarsi che lo User Manager Service sia in esecuzione e che il database sia accessibile.
-
Inviare una prima richiesta di registrazione utente, ad esempio:
curl -i -X POST "http://localhost:<HOST_PORT_UMS>/api/users" \ -H "Content-Type: application/json" \ -d '{ "email": "idempotent.user@example.com", "name": "Idempotent User" }'
-
Verificare la risposta (
201 Createdo200 OK) e, facoltativamente, controllare che l’utente sia presente nella tabellausers. -
Ripetere la stessa richiesta senza modificare il payload.
-
Osservare il comportamento del servizio e dei log applicativi.
Comportamento atteso
-
Non devono essere creati nuovi record nella tabella
users. -
Il servizio può rispondere con:
200 OKrestituendo l’utente già esistente;- oppure
409 Conflictcon un messaggio esplicito che segnali il tentativo di creare un duplicato.
-
Nei log non devono comparire eccezioni di violazione di vincoli di unicità non gestite.
-
Eseguire una query sul database per verificare il numero di record per l’indirizzo e‑mail utilizzato nel test:
SELECT COUNT(*) FROM users WHERE email = 'idempotent.user@example.com';
Il risultato atteso è 1.
-
Ripetere un test analogo per la registrazione di un interesse utente–aeroporto, ad esempio inviando due volte la stessa richiesta
POST /api/interestscon identicouserEmaileairportCode. -
Verificare che il numero di record nella tabella
user_airport_interestper la coppia(user_email, airport_id)rimanga 1, grazie al vincolo di unicità applicato a livello di schema e alla logica applicativa. -
Controllare i codici di risposta HTTP:
- la prima richiesta deve portare alla creazione dell’interesse (
201 Createdo200 OKin base alla semantica scelta); - le richieste successive devono produrre una risposta coerente con la politica di idempotenza, senza causare errori di violazione di vincoli non gestiti.
- la prima richiesta deve portare alla creazione dell’interesse (
Questo scenario verifica che le API di interrogazione dei voli su intervalli temporali gestiscano correttamente i parametri di input, filtrino in modo coerente i dati e restituiscano risposte strutturate e consistenti.
-
Assicurarsi che il Data Collector Service abbia già popolato la tabella
flight_recordscon un numero significativo di record per almeno un aeroporto di interesse. -
Identificare un intervallo temporale per cui si ha ragionevole certezza dell’esistenza di dati, ad esempio basandosi sulla finestra temporale utilizzata dallo scheduler di raccolta.
-
Invocare l’endpoint di interrogazione per intervallo temporale, ad esempio:
curl -i "http://localhost:<HOST_PORT_DCS>/api/flights?airportCode=LIRF&direction=ARRIVAL&from=2025-11-29T00:00:00Z&to=2025-11-30T00:00:00Z" -
Verificare che:
- la risposta abbia codice
200 OKin presenza di parametri validi; - il payload contenga una lista di voli con campi coerenti con il modello
FlightRecord(identificativi, orari, direzione, aeroporto, ritardi, ecc.); - non siano restituiti voli al di fuori dell’intervallo
[from, to]specificato.
- la risposta abbia codice
-
Ripetere la chiamata variando i parametri di intervallo temporale per coprire i seguenti casi:
- intervallo senza dati (ad esempio un periodo precedente all’avvio della raccolta): il comportamento atteso è una lista vuota con
200 OK, non un errore; - inversione dei parametri (
fromsuccessivo ato): il comportamento atteso è un errore di validazione (400 Bad Request) con un messaggio esplicito; - intervallo molto ampio: il sistema deve continuare a rispondere in tempi ragionevoli e con un payload coerente, eventualmente limitando i risultati se previsto.
- intervallo senza dati (ad esempio un periodo precedente all’avvio della raccolta): il comportamento atteso è una lista vuota con
-
Per un controllo aggiuntivo, eseguire query dirette sul database
datadbper verificare la corrispondenza tra i record restituiti dall’API e i dati presenti nella tabellaflight_records, ad esempio:SELECT * FROM flight_records WHERE airport_code = 'LIRF' AND direction = 'ARRIVAL' AND scheduled_time >= '2025-11-29T00:00:00Z' AND scheduled_time < '2025-11-30T00:00:00Z';
I risultati della query devono essere coerenti con il contenuto della risposta JSON ottenuta dall’endpoint REST.
Questi scenari di validazione forniscono una base operativa per verificare rapidamente il corretto comportamento del sistema nelle principali aree funzionali: gestione utenti, registrazione degli interessi e interrogazione dei dati di volo.