A backend architecture exploration inspired by real-world booking systems, built with Java 21 + Spring Boot.
This project demonstrates how a system evolves from synchronous correctness to controlled event-driven coordination — with strong emphasis on lifecycle integrity, concurrency safety, and deterministic domain behaviour.
It is intentionally single-process and single-database to focus on architectural clarity over infrastructure complexity.
This repository is designed to showcase practical backend engineering principles:
- Aggregate-driven domain modeling
- Explicit lifecycle management
- Inventory correctness under concurrency
- Event-driven orchestration within clear boundaries
- Retry classification and failure isolation
- Deterministic state transitions
- Clean read/write separation
The goal is to explore how systems grow in complexity responsibly, not to simulate a full booking product.
The intent is not to simulate a production-scale booking product, but to demonstrate how complex backend systems are structured responsibly.
This project follows a layered architecture with explicit responsibility boundaries:
Controller → Application Service → Domain Aggregate → Repository → Database
↓
Event Boundary (Async)- Controllers act strictly as HTTP adapters
- Services orchestrate workflows and transactions
- Domain aggregates enforce lifecycle invariants
- Repositories are persistence-only
- State transitions are explicit and validated
- Events represent domain facts
- Idempotency is enforced primarily via domain state
- Retry logic is isolated from domain logic
The system emphasises correctness before scalability.
The architecture was evolved incrementally:
- Baseline synchronous flow
- Inventory correctness with optimistic locking
- Time-bound booking lifecycle (expiry)
- Explicit aggregate state machine
- Async event boundary introduction
- Retry classification and bounded retries
- Dead-letter persistence
- Read/write separation (CQRS-lite)
Each phase introduces one complexity dimension at a time.
The booking aggregate enforces explicit lifecycle transitions such as:
Created → ConfirmedCreated → CancelledCreated → ExpiredConfirmed → Refund PendingRefund Pending → Refunded
Lifecycle invariants are enforced inside the aggregate to ensure:
- No illegal transitions
- Terminal state protection
- Idempotent operations
- Deterministic behavior under retries
This prevents business rules from leaking across services.
Inventory is modelled explicitly by: (hotel, roomType, date)
Characteristics:
- Quantity-based availability
- Optimistic locking for concurrency safety
- Symmetric reserve and release operations
- No derived inventory logic
- No negative inventory states
The system ensures correctness under concurrent booking attempts.
Payments and refunds cross an explicit async boundary within the JVM.
Design characteristics:
- Executor-based async dispatch
- Separate transaction per consumer execution
- Deterministic domain updates
- Retry classification (retryable vs non-retryable)
- Bounded retries with backoff
- Dead-letter persistence for exhaustion
This simulates distributed behaviour while maintaining architectural clarity.
Idempotency is enforced at multiple levels:
- Unique constraints for booking/payment/refund creation
- Aggregate-level state guards
- Event-level deduplication
- Retry boundary isolation
The aggregate remains the ultimate consistency guard.
Failure states are modelled explicitly and persisted.
The system demonstrates:
- Retry classification
- Controlled retry exhaustion
- Dead-letter persistence
- Failure reason tracking
- Deterministic aggregate behavior under repeated events
Async consumers remain predictable and side effect safe.
The system exposes:
- REST endpoints for write operations
- GraphQL as a read-only aggregation layer
This establishes a CQRS-lite separation where:
REST = Command Layer
GraphQL = Query Layer
The read layer has no side effects and no async behaviour.
- Java 21
- Spring Boot 3.x
- Spring Web
- Spring Data JPA (Hibernate)
- PostgreSQL
- Redis (idempotency & retry coordination)
- Spring GraphQL
- Maven
This project demonstrates:
- Aggregate design and invariant enforcement
- Concurrency-aware modeling
- Event-driven coordination patterns
- Retry boundary design
- Failure isolation strategies
- Defensive idempotency patterns
- Clean service boundary refactoring
- Architecture-first scaling mindset
It reflects hands-on backend system design thinking rather than framework usage alone.
- Single JVM
- Single database
- No external message broker
- No distributed tracing
- No horizontal scaling assumptions
The goal is architectural discipline, not infrastructure simulation.
This repository represents a structured backend evolution journey:
From correctness →
To concurrency safety →
To async orchestration →
To failure isolation →
To design clarity before scale.
It reflects how production systems should be cleaned and stabilised before introducing horizontal scaling.
Built as an architectural learning and engineering discipline project.