This project implements a microservices-based system for managing customer orders and product offerings, built as part of the backend engineering challenge.
- Java 21
- Maven 3.9+
- Docker & Docker Compose
- Environment Variables: The project requires a
.envfile in the root directory.cp .env_sample .env
- Execute Automation Script: Use the provided
xthore.shscript to build and deploy the entire stack.# Run full sequence: Test -> Build -> Deploy ./xthore.sh # Or run individual steps: ./xthore.sh --test # Run unit and integration tests ./xthore.sh --build # Build JARs and Docker images using Jib ./xthore.sh --deploy # Spin up containers (PostgreSQL, Eureka, Services)
- Order Service:
http://localhost:8090/order(Mapped via Gateway/Eureka) - Service Registry (Eureka): http://localhost:8761/
- Swagger Documentation: http://localhost:8090/swagger-ui/index.html for accessing specific services using the
qquery parameter, e.g;- Catalog service
http://localhost:8090/swagger-ui/index.html?q=catalog - Order service
http://localhost:8090/swagger-ui/index.html?q=order
- Catalog service
- Customer Order Service: Manages the order lifecycle (Draft -> Preview -> Submitted -> Confirmed) with strict state transition rules.
- Product Catalog Service: Provides product offering validation for the Order service.
- Core Modules: Shared libraries for REST handling (
core-rest), Remote communication (core-remote), and Common utilities (core-common). - Persistence Layer: Reactive persistence using Spring Data R2DBC and PostgreSQL.
- Service Discovery: Integrated Netflix Eureka for seamless inter-service communication.
- Authentication: Purposely omitted to focus on core domain logic and idempotency as per exercise requirements.
- Event-Driven Updates: Chose synchronous Feign communication for catalog validation to ensure immediate consistency during order creation/patching, though an async event-bus was considered for state changes.
- Placement: Validation logic is centralized in the
domainlayer using use cases and specific transition validators. This ensures the business rules are independent of the entry point (REST/CLI). - Transitions: Implemented a strict state transition matrix. Once an order reaches
SUBMITTED, only the state can be patched. OnceCONFIRMED, it becomes immutable.
- Used JSON Merge Patch behavior. Absent fields in the request body do not overwrite existing data. This is handled by a dedicated
UpdateModeland internal domain mapping that selectively applies changes.
- Mechanism: Fresh creations are tracked via an
Idempotency-Keyheader. - Persistence: The key is stored alongside the session in the database. If a request is replayed with the same key and identical payload, the existing order is returned. Different payloads for the same key result in a
409 Conflict.
- Feign + Eureka: Used Feign clients with service discovery.
- Unavailability: The Order service uses a custom
RemoteResponsewrapper to handle the standardized response format of the Catalog service. If the Catalog is down, the system fails-fast with a descriptive error to maintain data integrity.
- R2DBC: Selected for its non-blocking nature, aligning with the Spring WebFlux stack.
- Liquibase: Used for versioned schema migrations, ensuring the PostgreSQL database is correctly structured on startup.
- Seeding: The catalog is pre-seeded via Liquibase with offerings
po-1,po-2, andpo-3(Google Pixel 8, iPhone 15, etc.). - Currency: All prices are handled as decimals in the catalog but treated as simple numeric types in the current iteration for simplicity.