System Overview
StreamLine Logistics implements a microservices architecture to manage the complete order lifecycle from creation to final delivery. The system ensures stock consistency and provides real-time package tracking capabilities.Core Services
The platform consists of three domain-driven microservices:
- Order Service - Manages customer orders and order lifecycle
- Inventory Service - Controls product stock and reservations
- Tracking Service - Records shipment events and delivery status
Hexagonal Architecture (Ports & Adapters)
All microservices follow the Hexagonal Architecture pattern (also known as Ports and Adapters), which provides clear separation between business logic and external concerns.What is Hexagonal Architecture?
What is Hexagonal Architecture?
Hexagonal Architecture organizes code into three main layers:1. Domain Layer (Core)
- Contains pure business logic and domain models
- No dependencies on frameworks or infrastructure
- Implements domain rules and validations
- Uses immutable entities and value objects
- Orchestrates domain objects to fulfill use cases
- Defines input and output ports (interfaces)
- Implements application services
- Handles cross-cutting concerns like transactions
- Implements ports defined in application layer
- Contains framework-specific code
- Input adapters: REST controllers, message consumers
- Output adapters: Database repositories, external API clients
- Test business logic without databases or web servers
- Swap infrastructure implementations easily
- Delay technical decisions (database choice, messaging, etc.)
- Keep domain logic clean and focused
Package Structure Example (Inventory Service)
Key Principle: Dependencies point inward. The domain layer has zero external dependencies. Infrastructure depends on application, which depends on domain.
Technology Stack
| Component | Technology | Purpose |
|---|---|---|
| Framework | Spring Boot 3.x | Microservice foundation |
| Service Discovery | Netflix Eureka | Dynamic service registration |
| API Gateway | Spring Cloud Gateway | Unified entry point (port 8080) |
| Config Server | Spring Cloud Config | Centralized configuration (port 8888) |
| Communication | OpenFeign | Synchronous inter-service calls |
| Databases | PostgreSQL, MySQL, MongoDB | Polyglot persistence |
| Orchestration | Docker Compose | Multi-container deployment |
Infrastructure Components
Eureka Server
Port: 8761Service registry and discovery. All microservices register themselves on startup and can discover other services dynamically.
Config Server
Port: 8888Centralized configuration management. Stores YAML configuration files for all services, supporting environment-specific profiles.
API Gateway
Port: 8080Single entry point for external clients. Handles routing, security, and cross-cutting concerns like authentication and rate limiting.
Database Per Service Pattern
Each microservice owns its database to ensure loose coupling and independent scalability:Order Service - PostgreSQL (Port 5432)
Order Service - PostgreSQL (Port 5432)
Why PostgreSQL?
- ACID compliance for transactional integrity
- Strong support for complex relationships (orders, order items, customers)
- Excellent performance for relational data
orderdbInventory Service - MySQL (Port 3306)
Inventory Service - MySQL (Port 3306)
Why MySQL?
- High performance for read/write operations on master data
- Proven reliability for product catalogs
- Excellent concurrent access handling
inventorydbTracking Service - MongoDB (Port 27017)
Tracking Service - MongoDB (Port 27017)
Why MongoDB (NoSQL)?
- Schema-less design for flexible event data
- Different tracking events need different fields (GPS coordinates, photos, customs data)
- High write throughput for event streaming
- Natural fit for event sourcing patterns
trackingdbService Communication Flow
The system uses synchronous communication via OpenFeign for Phase 1:Shipment Initialization
If stock is available, Order Service calls Tracking Service to create shipment
Service Endpoints
| Service | Port | Base Path | Eureka Name |
|---|---|---|---|
| Order Service | 8090 | /api/v1/orders | msvc-order |
| Inventory Service | 9090 | /api/v1/inventory | msvc-inventory |
| Tracking Service | 8091 | /api/v1/tracking | msvc-tracking |
Design Decisions
Why Monorepo?
Why Monorepo?
- Simplifies dependency management across services
- Single
docker-compose.ymlfor entire stack - Easier to maintain shared contracts and DTOs
- Unified versioning and deployment
Why Database Per Service?
Why Database Per Service?
- Loose coupling: Schema changes don’t affect other services
- Independent scaling: Scale only the databases that need it
- Technology freedom: Choose the best database for each domain
- Fault isolation: Database failure affects only one service
Why Docker Compose?
Why Docker Compose?
- Guarantees identical dev and production environments
- Orchestrates 3 databases + N services with single command
- Simplifies networking between containers
- Easy to add new infrastructure components
Next Steps
Inventory Service
Deep dive into hexagonal architecture implementation
Order Service
Order management and lifecycle
Tracking Service
Shipment tracking and events