Domain-Driven Design Concepts
Aggregates
Clusters of domain objects treated as a single unit (e.g., Booking, Venue)
Entities
Objects with unique identity that persists over time
Value Objects
Immutable objects defined by their attributes (e.g., Address, Money)
All domain entities are located in
modules/*/domain/ directoriesBooking Domain
Booking Aggregate
TheBooking aggregate manages the complete lifecycle of a court booking.
Booking Entity Structure
Booking Entity Structure
Location: Factory Methods:Domain Methods:
modules/booking/domain/Booking.javaAttributes:confirmPayment(clock)- Mark payment as complete, activate bookingexpireHold(clock)- Cancel booking if payment not receivedcancel(reason, clock)- User cancellation (24h rule enforced)adminCancel(reason, clock)- Admin override cancellationconfirmMatch(clock)- Confirm match booking when fullrevertToPendingMatch(clock)- Revert to pending if player leavescancelMatch(clock)- Cancel match booking
- Payment must be confirmed before booking activation
- Cancellations within 24h of start time are not allowed (user)
- Admin cancellations bypass time restrictions
- Match bookings follow different state transitions
Payment Entity
Payment Entity Structure
Payment Entity Structure
Location:
modules/booking/domain/Payment.javaPurpose: Tracks payment transactions linked to bookingsKey Attributes:- Payment intent ID (payment provider integration)
- Amount and currency
- Payment status tracking
- Link to booking and player
Booking Value Objects
Venue Domain
Venue Aggregate
Venue Entity Structure
Venue Entity Structure
Location: Factory Methods:Domain Methods:
modules/venue/domain/Venue.javaAttributes:update(...)- Modify venue details (triggers re-review if active)suspend(clock)- Owner-initiated suspensionreactivate(clock)- Resume after suspensionaddImage(imageUrl, clock)- Add venue photoremoveImage(imageId, clock)- Delete photoapprove(clock)- Admin approvalreject(reason, clock)- Admin rejectionadminSuspend(reason, clock)- Admin suspension
- Only owner can modify venue
- Updates to active venues trigger PENDING_REVIEW status
- At least one image recommended (not enforced)
- Coordinates required for geographic search
VenueImage Entity
Purpose: Manages venue photos with display ordering Attributes:- Image URL and public ID (Cloudinary)
- Display order (integer)
- Creation timestamp
Venue Value Objects
Resource Domain
Resource Aggregate
Resource Entity Structure
Resource Entity Structure
Location: Factory Methods:Domain Methods:
modules/resource/domain/Resource.javaAttributes:update(...)- Modify resource detailssetSchedule(day, opening, closing, clock)- Set hours for dayremoveSchedule(day, clock)- Remove day availabilityaddPriceRule(...)- Add pricing ruleremovePriceRule(id, clock)- Delete pricing ruleaddImage(imageUrl, clock)- Add photoremoveImage(imageId, clock)- Delete photosuspend/reactivate(clock)- Owner suspensionapprove/reject/adminSuspend(...)- Admin actionsgenerateSlotsForDay(day)- Generate bookable slotsgetPriceForSlot(day, time)- Calculate slot priceisAvailableOn(day)- Check day availability
- Resource belongs to exactly one venue
- Schedules define operating hours per day of week
- Price rules evaluated in order (most specific wins)
- Slot duration divides evenly into schedule
DaySchedule Entity
Purpose: Operating hours for a specific day of week Attributes:- Day of week
- Opening time
- Closing time
generateSlots(slotDuration)- Create bookable time slots
Resource Value Objects
Matching Domain
MatchRequest Aggregate
MatchRequest Entity Structure
MatchRequest Entity Structure
Location: Factory Method:Domain Methods:
modules/matching/domain/MatchRequest.javaAttributes:openForPlayers()- Open after organizer paymentcancelDueToPaymentTimeout()- Cancel if organizer doesn’t payjoin(playerId, team, clock)- Player joins matchcancel()- Organizer cancellationremovePlayer(playerId)- Remove playercheckIn(playerId, clock)- Mark player presentreportAbsence(playerId)- Report no-showexpire()- Auto-close after expiration timeavailableSlots()- Calculate remaining spots
- Organizer must pay before match opens
- Player count cannot exceed format max
- Teams must be balanced (doubles)
- Match expires 24h before start time
- Players cannot join if already in match
MatchPlayer Entity
Purpose: Represents a player’s participation in a match Attributes:- Player ID
- Team assignment (A or B)
- Role (ORGANIZER or GUEST)
- Joined timestamp
- Check-in status
- Absence reporting
MatchInvitation Entity
Purpose: Tracks invitations sent to eligible players Attributes:- Match request ID
- Player ID and email
- Invitation status (PENDING, ACCEPTED, DECLINED)
- Sent and responded timestamps
- Free substitute flag
Matching Value Objects
IAM Domain
UserProfile Aggregate
UserProfile Entity Structure
UserProfile Entity Structure
Location: Factory Method:Domain Methods:
modules/iam/domain/UserProfile.javaAttributes:updateProfile(...)- Edit profile informationupdateAvatar(imageUrl, clock)- Change profile picturerequestOwnerRole(clock)- Request venue owner accessapproveOwnerRequest(clock)- Admin approvalrejectOwnerRequest(clock)- Admin rejectionchangeRole(newRole, clock)- Admin role changetoggleActive(clock)- Admin ban/unbanconfirmNoShow(clock)- Record match absenceisMatchBanned(clock)- Check if temporarily bannedrecordLogin(clock)- Update last login timestamp
- Auth0 ID is unique and immutable
- Default role is PLAYER
- Owner role requires admin approval
- 3 no-shows trigger 30-day ban
- Onboarding completed when name and city set
IAM Value Objects
Shared Value Objects
Domain Events
Domain events represent important business occurrences:Booking Events
Booking Events
Matching Events
Matching Events
Aggregate Boundaries
Aggregates are consistency boundaries - changes within an aggregate are atomic.
- Booking - Manages booking lifecycle and payment
- Venue - Groups venue details and images
- Resource - Groups court, schedules, pricing, and images
- MatchRequest - Groups match details and players
- UserProfile - User account and preferences
- Aggregates reference each other by ID only
- Cross-aggregate operations coordinated by use cases
- No direct object references between aggregates
Value Object Patterns
Immutability
All value objects are immutable (using Java records):Self-Validation
Value objects validate themselves on construction:Identity vs Value
Entities (identity matters):- Booking, Venue, Resource, UserProfile
- Compared by ID
- Mutable state
- Address, Coordinates, SlotRange
- Compared by attributes
- Immutable
Related Documentation
Backend Modules
Module structure and architecture
Database Schema
Persistence mapping and database structure