id: UUID
title: string
totalSeats: int
startsAt: DateTimeImmutable
id: UUID
eventId: UUID
rowName: string
seatNumber: int
status: SeatStatus (AVAILABLE | LOCKED | SOLD) – backed string enum
priceCents: int (EUR default)
reservationId: UUID|null
id: UUID
userId: UUID (ValueObject\UserId)
status: ReservationStatus (PENDING | PAID | CANCELLED | EXPIRED)
expiresAt: DateTimeImmutable (15 minutes from creation)
totalAmountCents: int
seats: OneToMany Seat
Money(amount: int, currency: 'EUR')
UserId(string $value) – validates UUID v4 on construct
Business Rules (Immutable)
Maximum 5 seats per reservation
Reservation TTL: exactly 900 seconds (15 minutes) from creation
Currency: always EUR, stored as cents (int)
Money Value Object: Domain\ValueObject\Money
Immutable
Always positive
Methods: add(Money $other): Money, equals(Money $other): bool, toCents(): int
UserId Value Object: Domain\ValueObject\UserId
Validates UUID v4 on construction
Always stored lowercase
SeatStatus and ReservationStatus: backed string enums (PHP 8.1+)
Domain Events (dispatched to Messenger/outbox)
{
"reservationId" : " uuid" ,
"userId" : " uuid" ,
"eventId" : " uuid" ,
"seatIds" : [" uuid" , " ..." ],
"expiresAt" : " 2025-11-22T10:15:00+00:00" ,
"totalAmount" : 15000 ,
"occurredOn" : " 2025-11-22T10:00:00+00:00"
}
{
"reservationId" : " uuid" ,
"reason" : " TIMEOUT" ,
"occurredOn" : " 2025-11-22T10:15:01+00:00"
}