-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture Overview
This project follows Hexagonal Architecture (Ports & Adapters) combined with Domain-Driven Design (DDD).
The goal is to keep the business logic independent from frameworks, databases, or external services.
📐 High-level architecture:
- 💡 Pure business logic.
- Contains:
- Aggregates (
Order,Basket,Customer,Payment,Product) - Domain Events (
OrderCreated,OrderPaid, etc.) - Business rules and invariants.
- Aggregates (
- Framework-agnostic → no Spring annotations, no persistence logic.
- ⚙️ Orchestrates use cases.
- Coordinates domain objects and invokes ports to reach external systems.
- Contains:
-
Application services (e.g.,
OrderCommandService,BasketCommandService,NotificationService) -
Use case interfaces (
OrderCreation,BasketCheckout,NotificationSending) - Transaction boundaries, logging, validation.
-
Application services (e.g.,
- Publishes domain events into the Outbox for messaging.
- 🔌 Bridges external technologies with the domain.
- Two directions:
- Inbound Adapters → expose the app to the outside world (e.g., REST controllers, message listeners).
- Outbound Adapters → implement ports for persistence, messaging, notifications, payments, etc.
- Examples:
- REST adapter (Spring REST controllers)
- JPA adapter (PostgreSQL)
- Stripe payment adapter
- Email/SMS notification adapters
- RabbitMQ messaging adapter
- 🛠 Cross-cutting technical concerns.
-
Ports → Java interfaces defined in the Domain or Application layer (
OrderRepository,Notificator,PaymentProcessor). - Adapters → Implementations of those ports in the Adapters layer.
- Dependency Rule → Dependencies always point inward:
1️⃣ Inbound Adapter (REST controller) receives POST /orders.
2️⃣ Application Service (OrderCommandService) executes the use case.
3️⃣ Domain Layer creates a new Order aggregate and raises OrderCreated event.
4️⃣ Application Service persists the order through OrderRepository (a port).
5️⃣ Outbound Adapter (JPA) saves order into PostgreSQL.
6️⃣ Outbox Adapter stores the OrderCreated event in the outbox table (serialized payload).
7️⃣ Messaging Adapter (RabbitMQ) periodically polls the outbox, reads new events, and publishes them to the message broker.
8️⃣ Notification Adapter (e.g., email) or other bounded contexts consume the event and act on it.
📡 Messaging flow in action:
- ✅ Testable → Business rules can be tested without infrastructure.
- ✅ Maintainable → Clear separation of concerns.
- ⚡ Replaceable → Adapters (e.g., In-Memory → JPA, or Email → SMS) can be swapped without touching domain logic.
- 📦 Scalable → Outbox + Messaging ensures reliable event-driven workflows.