Relazione Solution Design KetchApp | Corso Sistemi Cloud A.A. 2024/2025 | Laurea in Tecnologie dei Sistemi Informatici - UNIBO
By Alessandro Bruno & Alessandra Di Bella
Questo documento descrive il Solution Design di "KetchApp", un'applicazione mobile progettata per ottimizzare la produttività e le abitudini di studio degli utenti attraverso il metodo Pomodoro, ovvero una tecnica di gestione del tempo che divide il lavoro in intervalli, chiamati "pomodori", separati da brevi pause. L'obiettivo primario di KetchApp è fornire un sistema personalizzato di pianificazione dello studio, integrando funzionalità avanzate come l'organizzazione intelligente delle sessioni basata su intelligenza artificiale, il monitoraggio delle statistiche di studio, un sistema di obiettivi (achievements) e classifiche globali.
Con questa relazione descriveremo l'architettura di KetchApp, le decisioni di design adottate e l'integrazione con altri microservizi.
Requisiti non funzionali aggiuntivi per il corso Sistemi Cloud.
- Sviluppare un’architettura a microservizi
- Utilizzare Docker
- Utilizzare Spring Boot
- Utilizzare Kafka per l’invio asincrono delle email
- Sviluppare un’autenticazione che sfrutta un token JWT con chiave pubblica e privata
- Mettere alcuni microservizi in cloud
I requisiti funzionali descrivono le funzionalità che l'applicazione deve offrire agli utenti dopo che questi ultimi hanno completato il processo di autenticazione.
- Pianificazione dello Studio Personalizzata:
- Gli utenti devono poter inserire le materie da studiare e la durata desiderata per ciascuna.
- Gli utenti devono poter definire la durata delle proprie sessioni di studio ("pomodori") e delle pause.
- Gli utenti devono poter inserire impegni e orari specifici durante la giornata (es. appuntamenti, lezioni).
- Un'intelligenza artificiale deve elaborare queste informazioni per generare un piano di studio ottimizzato, suddividendo il tempo di studio in "pomodori" e rispettando gli impegni inseriti.
- Sessioni di Focus: L'applicazione deve consentire l'avvio e la gestione di sessioni di studio basate sul metodo Pomodoro, con timer dedicati per il focus e le pause.
- Statistiche di Studio: L'applicazione deve presentare un sistema di statistiche che visualizzi le ore totali di studio per ogni singola materia dell'utente in un intervallo di date selezionabile.
- Visualizzazione tramite grafico a barre delle ore di studio giornaliere.
- Possibilità di selezionare un giorno specifico dal grafico per visualizzare statistiche dettagliate (materie studiate e tempo impiegato per ciascuna).
- Sistema di Achievements: Gli utenti devono poter visualizzare gli obiettivi completati giornalmente e quelli ancora da raggiungere, incentivando la costanza nello studio.
- Classifiche Globali: L'applicazione deve visualizzare una classifica globale dei primi 100 utenti con il maggior numero di ore di studio totali, promuovendo la competitività.
I requisiti non funzionali definiscono le qualità del sistema e i vincoli operativi.
- Usabilità: L'interfaccia utente (frontend in Flutter) deve essere intuitiva e facile da usare per garantire un'esperienza utente ottimale.
- Affidabilità: Il sistema deve garantire la corretta gestione e persistenza dei dati utente, delle pianificazioni e delle statistiche, minimizzando la perdita di dati.
- Scalabilità: Il backend (Java con Spring Boot) deve essere progettato per gestire un numero crescente di utenti e richieste, mantenendo prestazioni elevate.
- Sicurezza: L'applicazione deve implementare meccanismi di autenticazione robusti, inclusa la validazione di token JWT tramite un middleware di sicurezza.
- Sistema di Messaggistica Asincrona: L'applicazione deve utilizzare un broker di messaggi (Kafka) per gestire l'invio asincrono di email (es. promemoria inizio sessione), garantendo scalabilità e affidabilità del sistema di notifica.
Prima di iniziare la fase di progettazione della nostra applicazione, abbiamo analizzato alcune soluzioni esistenti riguardanti la produttività e lo studio, in particolare quelle che implementano il metodo Pomodoro o funzionalità di tracciamento dello studio. Questo ci ha permesso di identificare le funzionalità più comuni, i punti di forza e le funzionalità che avremmo potuto migliorare o aggiungere con la nostra applicazione.
- Timer Pomodoro: La maggior parte delle app offre un timer configurabile per le sessioni di studio e le pause.
- Tracciamento del Tempo: Funzionalità per registrare il tempo di studio per materia o progetto.
- Statistiche: Visualizzazione di statistiche aggregate come il tempo totale di studio giornaliero o settimanale.
- Liste di Attività/To-Do: Integrazione con liste di cose da fare per organizzare le sessioni.
- Semplicità d'uso: Molte app sono progettate per essere immediate e facili da avviare.
- Focus sul Pomodoro: Efficaci nel mantenere l'utente concentrato durante le sessioni.
Analizzando le applicazioni esistenti abbiamo notato diverse aree in cui sono presenti delle limitazioni e dove KetchApp può offrire un valore aggiunto:
- Pianificazione Intelligente: Molte app si limitano a fornire timer o a permettere l'inserimento manuale delle sessioni. Mancano di una logica avanzata per ottimizzare la pianificazione in base a impegni, preferenze e durata delle materie. KetchApp si distingue per l'integrazione di un Intelligenza Artificiale, che permette la generazione automatica e personalizzata di piani di studio ottimizzati, un aspetto raramente presente nelle app attuali.
- Classifiche: Le classifiche globali sono una funzionalità poco comune nel contesto delle app di studio. KetchApp introduce questo elemento per promuovere la competitività e la motivazione tra gli utenti, incentivando la costanza nello studio.
@startuml
!include https://raw-githubusercontent-com-gh.computerqwq.top/kirchsth/C4-PlantUML/extended/C4_Container.puml
title KetchApp - Context Diagram
Person(user, "User", "Utente che crea e gestisce i propri piani di studio")
Container_Boundary(ketchapp, "KetchApp Application") {
System(frontend, "FrontEnd", "Interfaccia utente che permette di visualizzare e modificare i piani di studio")
Container(backend, "BackEnd", "Punto di accesso unico che instrada le richieste dell'app mobile ai microservizi interni")
}
System_Ext(email, "Invio Notifiche Email", "Invia notifiche e comunicazioni via email all'utente.")
Rel_D(user, frontend, "Interagisce con Applicazione")
Rel_R(frontend, backend, "Comunica con le Api")
Rel_D(backend, email, "Invia Email con dettagli sul Piano Studio")
@enduml
- User (Utente): É l'utente che interagisce direttamente con l'applicazione. Lui puó effettuare registrazione/login, creare i propri piani di studio, visualizzare le proprie statistiche, il proprio profilo e le classifiche globali. É il punto di partenza per tutte le funzionalità del’applicativo.
- FrontEnd (Interfaccia Utente): Sviluppato in Flutter, è il componente che gestisce l'interfaccia utente. Permette all'utente di visualizzare i piani di studio e tutte le altre funzionalità dell'applicazione. È il punto di contatto diretto per l'utente e comunica con il BackEnd.
- BackEnd: Riceve le richieste provenienti dal FrontEnd e fornisce le risposte adeguate.
- Invio Notifiche Email (External System): Questo è un sistema esterno con cui l'applicazione comunica. La sua funzione è inviare notifiche via email all'utente.
@startuml
!include https://raw-githubusercontent-com-gh.computerqwq.top/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
title KetchApp - Container Diagram
Person(user, "Utente", "Crea e gestisce i propri piani di studio e le relative attività.")
Container_Boundary(ketchapp_application, "KetchApp Application") {
Component(frontend, "FrontEnd UI ", "Flutter", "Permette all' utente di gestire i propri piani di studio e le relative attività.")
Container_Boundary(bffcompose, "Bff Compose") {
Container(bffapi, "BackEnd Bff Api", "Spring Boot", "Gestisce le richieste dell' utente e richiama i microservizi interssati.")
}
Container_Boundary(appcompose, "App Compose") {
Container(appapi, "App Api", "Spring Boot", "Gestisce le richieste dell' utente e richiama i microservizi interssati.")
}
Container_Boundary(authcompose, "Auth Compose") {
Container(authapi, "Auth Api", "Actix", "Gestisce l' autenticazione e l' autorizzazione degli utenti.")
ContainerDb(authdb, "Auth Database", "PostgreSQL", "Memorizza i dati relativi agli utenti e alle loro credenziali.")
}
Container_Boundary(kafkacompose, "Kafka Compose") {
Container(kafka_broker, "Kafka Broker", "Apache Kafka", "Gestisce la ricezione e l'invio dei messaggi tra i microservizi.")
Container(kafka_zookeeper, "Zookeeper", "Apache Zookeeper", "Gestisce la configurazione e il coordinamento dei microservizi.")
}
Container_Boundary(kafkaconsumercompose, "Kafka Consumer Compose") {
Container(kafkaengine, "Kafka Engine", "Spring Boot Kafka", "Gestisce la ricezione e l' invio dei messaggi tra i microservizi.")
}
Container_Boundary(supabase, "Supabase") {
ContainerDb(appdb, "App Database", "PostgreSQL", "Gestisce la memorizzazione dei dati relativi agli utenti e alle loro interazioni con l' applicazione.")
}
}
System_Ext(smtp, "SMTP Service", "Servizio di invio email per notifiche e comunicazioni.")
System_Ext(mail, "Gmail Service", "Servizio di invio su Gmail per notifiche e comunicazioni.")
Rel_R(user, frontend, "Interagisce con l' applicazione")
Rel_D(frontend, bffapi, "Richiede dati e servizi")
Rel_D(bffapi, appapi, "Richiede dati e servizi")
Rel_R(bffapi, authapi, "Richiede autenticazione e autorizzazione")
Rel_D(authapi, authdb, "Memorizza e recupera dati utente")
Rel_D(appapi, appdb, "Memorizza e recupera dati utente")
Rel_L(appapi, kafka_broker, "Invia messaggi")
Rel_D(kafka_broker, kafkaengine, "Consuma messaggi")
Rel_D(kafka_broker, kafka_zookeeper, "Gestisce la configurazione e il coordinamento")
Rel_R(kafkaengine, smtp, "Invia Email via SMTP")
Rel_D(smtp, mail, "Invia notifiche via Email")
@enduml
Questo diagramma entra nel dettaglio dell'architettura del backend, mostrando come i vari microservizi interagiscono tra loro per implementare le funzionalità descritte nei requisiti.
I container rappresentati organizzano i componenti interni e le loro responsabilità.
- Frontend UI (Flutter): Rappresenta l'interfaccia utente (come descritto nel diagramma di alto livello), da cui partono le richieste verso il backend. La sua funzione è "interagire con l'applicazione" e "richiedere dati e servizi" al BFF.
- Bff Compose (Backend For Frontend):
- BackEnd Bff Api (Spring Boot): Questo componente agisce da "Backend For Frontend". È il primo punto di contatto per le richieste del FrontEnd e ha il compito di gestire le richieste dell'utente e richiamare i microservizi interessati. Riceve richieste di dati e servizi e a sua volta si interfaccia con l'Auth Compose per l'autenticazione e con App Compose per le altre richieste.
- Auth Compose:
- Auth Api (Spring Boot): Gestisce l'intera logica di autenticazione degli utenti. Riceve le richieste di autenticazione dal BFF e si interfaccia con l'Auth Database per la persistenza dei dati.
- Auth Database: Il database dedicato alla gestione dell'autenticazione. Memorizza e recupera i dati relativi agli utenti e alle loro credenziali.
- App Compose:
- App Api (Spring Boot): Il microservizio principale che gestisce la logica di business dell'applicazione, come la pianificazione dello studio, le statistiche e gli achievements. Si interfaccia con il database Supabase per la persistenza dei dati e con Kafka per le comunicazioni asincrone.
- Supabase (Container):
- App Database: Il database principale dell'applicazione, che gestisce tutti i dati relativi all’utente.
- Kafka Compose:
- Kafka Broker (Apache Kafka): Il broker di messaggistica asincrona. Gestisce la ricezione e l'invio di messaggi tra i microservizi, garantendo la scalabilità e l'affidabilità delle comunicazioni.
- Zookeeper (Apache Zookeeper): Servizio di coordinamento per Kafka. Gestisce la configurazione e il coordinamento dei microservizi all'interno del cluster Kafka.
- Kafka Consumer Compose:
- Kafka Engine (Spring Kafka): Il consumatore di messaggi di Kafka. Consuma i messaggi dal broker di Kafka e schedula i jobs che invieranno le email.
- SMTP Service (External System): Il sistema di posta elettronica. Viene richiamato dal Kafka Consumer per inviare le email.
- Gmail Service (External System): Servizio che si occupa di inviare le email all’utente.
Il flusso di interazione tra questi componenti è il seguente:
- L'Utente interagisce con il Frontend UI.
- Il Frontend UI invia richieste al Backend Bff Api.
- Il Backend Bff Api richiede l'autenticazione all'Auth Api e dati di business all'App Api.
- L'Auth Api valida le credenziali e genera il token JWT.
- L'App Api memorizza/recupera i dati relativi all’utente (per esempio i tomatoes che ha in programma, le attivitá relative ai tomatoes, gli achievements,…) dall'App Database (Supabase).
- Una volta che il piano di studio é stato generato dall’intelligenza artificiale viene pubblicato su un topic kafka.
- Il Kafka Engine (Kafka Consumer) consuma il messaggio dal Kafka Broker e genera i jobs schedulati per inviare l’email all’utente 15 minuti prima dell’inizio della sua sessione di studio.
- Il Kafka Engine invia la richiesta di email al SMTP Service che poi si occupa di inviarla tramite un indirizzo Gmail.
@startuml
title KetchApp - Token JWT Flow
actor Utente as U
participant "FrontEnd" as Client
participant "Bff BackEnd" as Bff
participant "Auth BackEnd" as Auth
== Login e JWT ==
U -> Client: Login (credenziali)
Client -> Bff: Richiesta di login(credenziali)
activate Bff
Bff -> Auth: Richiesta di login(credenziali)
deactivate Bff
activate Auth
Auth -> Auth: Valida le credenziali
Auth -> Auth: Genera il JWT
Auth -> Client: Restituisce il JWT
deactivate Auth
note right of Client: Client memorizza il JWT
' Fase 2: Uso del token per accedere a una risorsa
== Accesso API protetta ==
Client -> Bff: Richiesta API\n(Header: Authorization: Bearer JWT)
note right of Client: Prende il Token Memorizzato
activate Bff
Bff -> Bff: Valida il JWT
Bff --> App: Risposta API (dati)
deactivate Bff
activate App
App -> App: Esegue Logica della Api
App -> Bff: Risposta API(dati)
deactivate App
activate Bff
Bff -> Client: Risposta API(dati)
deactivate Bff
Client -> U: Visualizza dati
@enduml
- Contesto: Il progetto KetchApp prevede lo sviluppo di un'applicazione mobile scalabile e robusta.
- Problema: Un'architettura monolitica avrebbe potuto portare a difficoltà di scalabilità, tempi di deployment lunghi e sarebbe stata difficile da mantenere.
- Decisione: Abbiamo suddiviso l'applicazione in microservizi.
- Motivazioni:
- Scalabilità Indipendente: Ogni microservizio può essere scalato orizzontalmente in base al proprio carico, ottimizzando l'uso delle risorse.
- Manutenibilità: La suddivisione in servizi più piccoli e autonomi rende il codice più facile da comprendere, sviluppare e mantenere.
- Flessibilità Tecnologica: Permette l'utilizzo di tecnologie diverse per servizi specifici (es. Rust per l'autenticazione, Java Spring Boot per la logica principale).
- Contesto: Necessità di un meccanismo di sicurezza robusto per proteggere le API del backend, garantendo che solo gli utenti autenticati possano accedere alle risorse.
- Problema: Le sessioni tradizionali sono state scartate in quanto sono stateful e questo contrasta i principi stateless delle API REST.
- Decisione: Implementare un middleware di sicurezza basato su Spring Security configurato per la validazione dei token JWT tramite una chiave pubblica RSA.
- Motivazioni:
- Statelessness: I JWT sono auto-contenuti, eliminando la necessità per il server di mantenere lo stato della sessione in un database.
- Centralizzazione della Logica: Il middleware intercetta ogni richiesta HTTP in entrata, centralizzando la logica di validazione e impostando il contesto di sicurezza di Spring.
- Efficienza: La validazione avviene rapidamente senza interpellare un database di sessioni ad ogni richiesta.
- Contesto: Necessità di inviare notifiche (es. email sui piani di studio, promemoria) in modo affidabile e scalabile, senza bloccare il flusso principale dell'applicazione.
- Problema: L'invio sincrono di email potrebbe introdurre latenza nel processo di creazione del piano di studio e rendere il sistema vulnerabile a fallimenti del servizio di invio email.
- Decisione: Utilizzare Apache Kafka come broker di messaggi per gestire l'invio asincrono delle email. Un microservizio dedicato (Java Kafka API) si occupa di consumare questi messaggi.
- Motivazioni:
- Disaccoppiamento: Il servizio che crea il piano di studio non dipende direttamente dal servizio di invio email.
- Affidabilità: I messaggi vengono mantenuti in Kafka, garantendo che le notifiche vengano inviate anche se il servizio di invio email è temporaneamente non disponibile.
- Contesto: Necessità di un database relazionale robusto e affidabile per la persistenza dei dati strutturati dell'applicazione (utenti, achievements, tomatoes, activities).
- Problema: Bisognava scegliere il database più adatto per garantire la consistenza, l'integrità e le prestazioni dei dati in base alle nostre disponibilità e conoscenze.
- Decisione: Utilizzare PostgreSQL come database relazionale principale per entrambi i microservizi (Autenticazione e Applicazione principale).
- Motivazioni:
- Affidabilità e Consistenza: PostgreSQL è un database relazionale robusto che supporta ACID (Atomicità, Consistenza, Isolamento, Durabilità) e ha la capacità di gestire dati complessi.
- Open Source: Non ha costi di licenza.
- Ecosistema: Ampio supporto della community e integrazione con Spring Data JPA.
- Contesto: Necessità di fornire una pianificazione dello studio personalizzata e ottimizzata basata sugli input dell'utente.
- Problema: Implementare una logica di pianificazione complessa manualmente sarebbe molto difficile e poco flessibile.
- Decisione: Integrare le Gemini API (Google) per sfruttare le capacità di intelligenza artificiale nella generazione del piano di studio.
- Motivazioni:
- Ottimizzazione: Permette di generare piani di studio intelligenti che tengono conto di materie, ore di studio e impegni, massimizzando l'efficienza.
- Personalizzazione: Offre un'esperienza utente altamente personalizzata.
- Riduzione della Complessità: Delega la logica complessa di pianificazione a un servizio AI esterno, semplificando la logica di business interna.
- Contesto: Necessità di un ambiente di sviluppo e deployment coerente, isolato e portabile per i microservizi.
- Problema: La gestione delle dipendenze e degli ambienti per ogni microservizio può essere complessa e soggetta a errori.
- Decisione: Utilizzare Docker per containerizzare ogni microservizio e Docker Compose per gestire l'ambiente di sviluppo locale e i servizi correlati.
- Motivazioni:
- Isolamento: Ogni servizio opera nel proprio ambiente isolato, garantendo coerenza tra gli ambienti di sviluppo, test e produzione.
- Portabilità: I container possono essere eseguiti su qualsiasi sistema che supporti Docker.
- Semplificazione del Deployment: Docker Compose semplifica l'avvio e la gestione di più servizi interconnesi.
- Efficienza delle Risorse: I container sono più leggeri delle VM.
- Frontend: Flutter.
- Backend (Applicazione & Kafka): Java 21 con Spring Boot.
- Backend (Autenticazione): Rust.
- Database: PostgreSQL.
- Messaggistica Asincrona: Apache Kafka.
- Intelligenza Artificiale: Google Gemini API.
- Testing: JUnit 5, Mockito, Spring MockMvc.
- Documentazione API: Swagger/OpenAPI.
- Deployment/Containerizzazione: Docker, Docker Compose.
Nel nostro progetto, abbiamo scelto di sottoporre a test di integrazione il livello di routing, PlanBuilderRoutes, che gestisce le richieste HTTP in entrata relative alla creazione di piani di studio. Questo componente si occupa di ricevere le richieste, validare i dati e indirizzarle al controller appropriato.
Nei test implementati abbiamo coperto i seguenti scenari:
- testCreatePlanBuilder(): Verifica la creazione di un piano con dati validi aspettandosi che una richiesta valida porti a una risposta 200 OK e che il controller venga invocato con i dati corretti.
- testCreatePlanBuilder_InternalServerError(): Verifica la gestione di un errore interno del server (HTTP 500).
- testCreatePlanBuilder_BadRequest(): Testa una richiesta con un corpo JSON vuoto o incompleto, aspettandosi una risposta 400 Bad Request, che conferma il funzionamento della validazione dei dati a livello di routing.
- testCreatePlanBuilder_PartialBadRequest(): Verifica la risposta a una richiesta con DTO con dati insufficienti verificando che venga comunque generato un 400 Bad Request.
- testCreatePlanBuilder_InvalidValuesBadRequest(): Verifica la risposta a una richiesta con valori non validi aspettandosi che vengano rifiutati con un 400 Bad Request.
- testCreatePlanBuilder_NotFound(): Verifica la risposta a una richiesta verso un endpoint inesistente, aspettandosi un HTTP 404.
Per realizzare questi test abbiamo utilizzato il framework JUnit 5 in combinazione con Mokito per la simulazione delle dipendenze e con Spring MockMvc per la simulazione delle richieste HTTP. In particolare:
- JUnit5: è Il framework di test principale, esteso con
MockitoExtensionper abilitare l'integrazione con Mockito - Mokito: permette di sostituire le dipendenze della classe che stiamo testando con delle versioni fittizie chiamate Mock che possono essere programmate per agire in un determinato modo simulando l’oggetto reale.
- Spring MockMvc: è uno strumento fornito da Spring Test per simulare richieste HTTP verso i controller Spring senza dover avviare un server HTTP completo.
In questo modo i test vengono eseguiti in modo automatico verificando la correttezza del flusso delle richieste API e la validazione degli input.
Il metodo di test che abbiamo usato segue il patter Arrange, Act, Assert (AAA), ovvero nella fase di Arrange prepariamo i dati di input (come i DTO di richiesta) e definiamo il comportamento dei mock, nella fase di Act eseguiamo l’operazione da testare, ovvero in questo caso l’invio di una richiesta HTTP simulata grazie a Spring MockMvc e infine nella fase di Assert verifichiamo la correttezza dei risultati.
Abbiamo implementato una serie di test unitari per la classe KafkaProducer, il cui compito è serializzare un oggetto PlanBuilderRequestDto in una stringa JSON e inviarlo in un topic Kafka.
Nei test implementati abbiamo coperto i seguenti scenari:
testSendToKafkaSuccess(): Verifica il caso di successo, in cui un oggettoPlanBuilderRequestDtovalido viene correttamente serializzato in JSON e inviato al topic Kafka corretto.testSendToKafkaJsonProcessingException(): Verifichiamo un caso di errore. Simuliamo unaJsonProcessingExceptionda parte dell'ObjectMappere verifichiamo che il nostro producer non tenti di inviare il messaggio a Kafka, confermando che l'eccezione è gestita in modo corretto.- Test di gestione dei valori nulli e vuoti: Abbiamo sviluppato una serie di test per verificare il comportamento del producer in caso valori non validi o mancanti, come un oggetto
planvuoto (testSendToKafkaWithEmptyPlan), nullo (testSendToKafkaWithNullPlan), incompleto (testSendToKafkaWithIncompletePlan), o email vuote e nulle (testSendToKafkaWithEmptyEmail,testSendToKafkaWithNullEmail). Per ogni scenario, abbiamo verificato che il componente gestisse correttamente questi casi, inviando comunque un messaggio formattato in modo appropriato, delegando la validazione dei dati a un livello superiore.
@startuml
!include https://raw-githubusercontent-com-gh.computerqwq.top/plantuml-stdlib/C4-PlantUML/master/C4_Component.puml
title KetchApp - Diagram Context
Person(user, "Utente", "Crea e gestisce i propri piani di studio e le relative attività.")
Container_Boundary(ketchapp_application, "KetchApp Application") {
Container_Boundary(mobile, "Smartphone") {
Component(frontend, "FrontEnd UI ", "Flutter", "Permette all' utente di gestire i propri piani di studio e le relative attività.")
}
Container_Boundary(localhost, "LocalHost") {
Container_Boundary(bffcompose, "Bff Compose") {
Container(bffapi, "BackEnd Bff Api", "Spring Boot", "Gestisce le richieste dell' utente e richiama i microservizi interssati.")
}
Container_Boundary(appcompose, "App Compose") {
Container(appapi, "App Api", "Spring Boot", "Gestisce le richieste dell' utente e richiama i microservizi interssati.")
}
Container_Boundary(authcompose, "Auth Compose") {
Container(authapi, "Auth Api", "Actix", "Gestisce l' autenticazione e l' autorizzazione degli utenti.")
ContainerDb(authdb, "Auth Database", "PostgreSQL", "Memorizza i dati relativi agli utenti e alle loro credenziali.")
}
Container_Boundary(kafkacompose, "Kafka Compose") {
Container(kafka_broker, "Kafka Broker", "Apache Kafka", "Gestisce la ricezione e l'invio dei messaggi tra i microservizi.")
Container(kafka_zookeeper, "Zookeeper", "Apache Zookeeper", "Gestisce la configurazione e il coordinamento dei microservizi.")
}
Container_Boundary(kafkaconsumercompose, "Kafka Consumer Compose") {
Container(kafkaengine, "Kafka Engine", "Spring Boot Kafka", "Gestisce la ricezione e l' invio dei messaggi tra i microservizi.")
}
}
Container_Boundary(supabase, "Supabase") {
ContainerDb(appdb, "App Database", "PostgreSQL", "Gestisce la memorizzazione dei dati relativi agli utenti e alle loro interazioni con l' applicazione.")
}
}
System_Ext(smtp, "SMTP Service", "Servizio di invio email per notifiche e comunicazioni.")
Container_Boundary(google, "Google") {
System_Ext(mail, "Gmail Service", "Servizio di invio su Gmail per notifiche e comunicazioni.")
}
Rel_R(user, frontend, "Interagisce con l' applicazione")
Rel_D(frontend, bffapi, "Richiede dati e servizi")
Rel_D(bffapi, appapi, "Richiede dati e servizi")
Rel_R(bffapi, authapi, "Richiede autenticazione e autorizzazione")
Rel_D(authapi, authdb, "Memorizza e recupera dati utente")
Rel_D(appapi, appdb, "Memorizza e recupera dati utente")
Rel_L(appapi, kafka_broker, "Invia messaggi")
Rel_D(kafka_broker, kafkaengine, "Consuma messaggi")
Rel_D(kafka_broker, kafka_zookeeper, "Gestisce la configurazione e il coordinamento")
Rel_D(kafkaengine, smtp, "Invia Email via SMTP")
Rel_L(smtp, mail, "Invia notifiche via Email")
@enduml
- LocalHost Machine: Host Locale
- Smartphone: Host Client dell' Utente in quanto la nostra è un Applicazione Mobile
- Supabase: Host Cloud supabase.com con Database PostgreSQL
Il nostro applicativo non andrà in produzione, ma se dovessimo pubblicarlo eseguiremmo prima dei test per valutarne la sicurezza e le eventuali vulnerabilità. Per questo abbiamo scannerizzato i codici sorgenti dei nostri microserivzi tramite i tool SonarQube e Qodana per identificare eventuali falle di sicurezza e questo é il risultato:
- Bff Api
- App Api
- Kafka Engine
- Bff Api
- App Api
- Kafka Engine
In generale vediamo che tutti i microservizi mostrano uno stato "Passed" nelle scansioni SonarQube, il che è un buon punto di partenza, tuttavia ci sono alcune vulnerabilitá da sistemare, in particolare in KetchApp-App-Api. Nel caso volessimo mandare in produzione il nostro applicativo dovremmo sistemare prima queste problematiche.









