Un Dominio Complesso per Problemi Reali
Il modello di dominio è il cuore di qualsiasi applicazione che adotta il Domain-Driven Design. In Play The Event, questo cuore è composto da 86 entità distribuite su molteplici aggregati, ciascuno responsabile di un aspetto specifico della gestione eventi.
In questo articolo analizzeremo i principali aggregati, il ciclo di vita degli eventi, i ruoli dei partecipanti, i Value Objects e i sotto-domini che compongono la piattaforma.
Cosa Troverai in Questo Articolo
- I principali aggregati del dominio: Evento, Viaggio, Spesa, User
- La macchina a stati per il ciclo di vita degli eventi
- I ruoli dei partecipanti e il sistema RSVP
- I Value Objects e la loro importanza
- Il dominio delle spese con lo smart splitting
- Il dominio dei viaggi con itinerari multi-tappa
- I sotto-domini aggiuntivi: festival, inventario, documenti, questionari
Gli Aggregati Principali
Il dominio di Play The Event è organizzato intorno a quattro aggregati principali, ciascuno con la propria radice (Aggregate Root) che controlla l'accesso e mantiene le invarianti di business.
AGGREGATI DEL DOMINIO
EVENTO (Aggregate Root)
├── EventoId (identità)
├── Stato (macchina a stati)
├── Partecipante[]
│ ├── Ruolo (ORGANIZER, CO_ORGANIZER, ATTENDEE, VIP)
│ └── StatoRSVP (IN_ATTESA, ACCETTATO, RIFIUTATO, FORSE, SCADUTO)
├── Budget
├── Documento[]
├── Questionario[]
└── Task[]
VIAGGIO (Aggregate Root)
├── ViaggioId (identità)
├── Tappa[]
│ ├── Attività[]
│ ├── Alloggio
│ └── Trasporto
└── Budget viaggio
SPESA (Aggregate Root)
├── SpesaId (identità)
├── Categoria
├── SplitStrategy (EQUAL, PERCENTAGE, FIXED, CUSTOM)
├── Pagamento[]
└── Settlement[]
USER (Aggregate Root)
├── UserId (identità)
├── Profilo
├── Preferenze
└── Ruoli di sistema
Il Ciclo di Vita dell'Evento
Ogni evento in Play The Event attraversa un ciclo di vita ben definito, gestito tramite una macchina a stati che garantisce transizioni valide e impedisce operazioni non consentite nello stato corrente.
Gli Stati dell'Evento
DRAFT ──────────► PUBLISHED ──────────► CONFIRMED
│ │ │
│ │ ▼
│ │ IN_PROGRESS
│ │ │
│ ▼ ▼
│ (cancellazione) EXPENSE_SPLITTING
│ │
▼ ▼
(eliminazione) COMPLETED
TRANSIZIONI VALIDE:
DRAFT → PUBLISHED (l'organizzatore pubblica l'evento)
PUBLISHED → CONFIRMED (raggiunto il quorum o conferma manuale)
CONFIRMED → IN_PROGRESS (data evento raggiunta, check-in attivo)
IN_PROGRESS → EXPENSE_SPLITTING (evento concluso, fase spese)
EXPENSE_SPLITTING → COMPLETED (tutte le spese saldate)
- DRAFT: l'evento è in fase di creazione. Solo l'organizzatore può vederlo e modificarlo. Non sono possibili inviti.
- PUBLISHED: l'evento è visibile ai partecipanti invitati. Il sistema RSVP è attivo e gli invitati possono confermare o rifiutare.
- CONFIRMED: l'evento ha raggiunto il numero minimo di partecipanti confermati. La pianificazione è consolidata.
- IN_PROGRESS: l'evento è in corso. Il check-in/checkout è attivo e le spese possono essere registrate in tempo reale.
- EXPENSE_SPLITTING: l'evento è terminato. È la fase dedicata alla suddivisione e saldo delle spese tra i partecipanti.
- COMPLETED: tutte le spese sono state saldate. L'evento è archiviato e disponibile per le statistiche storiche.
Ruoli dei Partecipanti
Il sistema dei ruoli è fondamentale per gestire i permessi all'interno di ogni evento. Ogni partecipante ha un ruolo che determina le azioni che può compiere.
- ORGANIZER: il creatore dell'evento. Ha il controllo completo: modifica, cancellazione, gestione partecipanti, gestione budget e spese. Esiste un solo organizzatore per evento.
- CO_ORGANIZER: collaboratore dell'organizzatore. Può gestire partecipanti, inviare comunicazioni e modificare dettagli logistici, ma non può cancellare l'evento.
- ATTENDEE: il partecipante standard. Può confermare la presenza, registrare spese, partecipare alla chat e compilare questionari.
- VIP: partecipante con visibilità speciale. Ha accesso a contenuti esclusivi e priorità nella gestione dei posti limitati.
Il Sistema RSVP
Il sistema RSVP gestisce le conferme di partecipazione con cinque stati possibili, inclusa la gestione automatica delle scadenze.
- IN_ATTESA: l'invito è stato inviato ma il partecipante non ha ancora risposto
- ACCETTATO: il partecipante ha confermato la presenza
- RIFIUTATO: il partecipante ha declinato l'invito
- FORSE: il partecipante è incerto e confermerà in seguito
- SCADUTO: il termine per la risposta è scaduto senza una conferma. Il sistema gestisce automaticamente questa transizione tramite un job schedulato
I Value Objects
I Value Objects sono elementi fondamentali del dominio che incapsulano validazione e comportamento direttamente nei tipi di dato, eliminando la possibilità di dati inconsistenti.
Money: Gestione Multi-Valuta
Il Value Object Money gestisce importi monetari con supporto multi-valuta. Ogni
operazione aritmetica verifica la compatibilità delle valute, e l'arrotondamento è
gestito secondo le regole bancarie standard (due decimali, arrotondamento HALF_UP).
Email: Validazione Integrata
Il Value Object Email garantisce che ogni indirizzo email nel sistema sia sintatticamente
valido al momento della creazione. La validazione avviene nel costruttore, rendendo impossibile
l'esistenza di un'istanza Email con formato non valido.
UserId: Identità Tipizzata
Invece di usare Long o String come identificativi, il sistema utilizza
UserId, EventoId, SpesaId e altri ID tipizzati. Questo
previene errori comuni come passare l'ID di un utente dove era atteso l'ID di un evento.
Il Dominio delle Spese
Una delle funzionalità più complesse di Play The Event è il sistema di suddivisione spese, che supporta quattro diverse modalità di splitting.
MODALITA' DI SPLIT
1. EQUAL (Equa)
Spesa totale: 120 EUR / 4 partecipanti = 30 EUR ciascuno
2. PERCENTAGE (Percentuale)
Spesa totale: 200 EUR
├── Alice: 50% → 100 EUR
├── Bob: 30% → 60 EUR
└── Carol: 20% → 40 EUR
3. FIXED (Importo Fisso)
Spesa totale: 150 EUR
├── Alice: 80 EUR (fisso)
├── Bob: 50 EUR (fisso)
└── Carol: 20 EUR (fisso)
4. CUSTOM (Personalizzata)
Ogni partecipante ha un importo specifico
definito manualmente dall'organizzatore
Il sistema calcola automaticamente i saldi tra i partecipanti e genera i settlement ottimali, minimizzando il numero di transazioni necessarie per chiudere tutti i debiti. Le spese sono organizzate per categorie (cibo, trasporto, alloggio, intrattenimento, altro) e possono essere associate a un evento specifico o a una tappa di viaggio.
Il Dominio dei Viaggi
Il sotto-dominio dei viaggi gestisce itinerari complessi con tappe multiple, ciascuna con le proprie attività, alloggi e trasporti.
VIAGGIO
├── Informazioni generali
│ ├── Nome, descrizione, date
│ ├── Budget totale
│ └── Partecipanti
│
├── Tappa 1: Roma (3 giorni)
│ ├── Attività: Colosseo, Musei Vaticani, Trastevere
│ ├── Alloggio: Hotel Centro, check-in/out
│ └── Trasporto: Treno da Bari
│
├── Tappa 2: Firenze (2 giorni)
│ ├── Attività: Uffizi, Ponte Vecchio, Chianti tour
│ ├── Alloggio: B&B Oltrarno
│ └── Trasporto: Treno da Roma
│
└── Budget
├── Spese previste per tappa
├── Spese effettive registrate
└── Differenza budget
Domini Aggiuntivi
Oltre ai quattro aggregati principali, il modello di dominio include diversi sotto-domini che arricchiscono la piattaforma con funzionalità specializzate.
- Festival Management: gestione di eventi multi-giornata con programmi, palchi, artisti e lineup. Supporta eventi complessi come festival musicali e conferenze multi-track
- Inventario: tracciamento di materiali e risorse necessarie per l'evento (attrezzature, decorazioni, forniture), con gestione quantità e assegnazione ai responsabili
- Documenti: gestione documentale con versionamento, condivisione e categorizzazione. Include contratti, permessi, fatture e qualsiasi documento associato all'evento
- Questionari: creazione e distribuzione di sondaggi e questionari per raccogliere feedback, preferenze alimentari, disponibilità orarie e altri dati dai partecipanti
Evoluzione dello Schema: 116+ Migrazioni Flyway
Il database di Play The Event è gestito tramite Flyway, con oltre 116 script di migrazione che documentano l'intera evoluzione dello schema. Ogni modifica al database è tracciata, versionata e reversibile.
db/migration/
├── V1__create_users_table.sql
├── V2__create_events_table.sql
├── V3__create_participants_table.sql
├── V4__add_rsvp_status.sql
├── ...
├── V50__create_expense_splits.sql
├── V51__add_settlement_optimization.sql
├── ...
├── V100__create_trip_activities.sql
├── V101__add_accommodation_details.sql
├── ...
└── V116__add_questionnaire_analytics.sql
Perché 116+ Migrazioni?
Un numero elevato di migrazioni non indica necessariamente un design iniziale carente. Al contrario, è il risultato di un approccio iterativo e incrementale: il dominio è evoluto insieme alla comprensione dei requisiti, e ogni migrazione rappresenta un passo in avanti nella modellazione del dominio. Questo approccio è perfettamente allineato con i principi DDD, dove il modello viene raffinato continuamente attraverso il feedback degli utenti.
Il codice del modello di dominio è disponibile su GitHub. Nel prossimo articolo analizzeremo il sistema di sicurezza e autenticazione JWT, esplorando come Play The Event protegge i dati degli utenti e gestisce le autorizzazioni.







