System Architecture
StreamLine Logistics follows a microservices architecture pattern with domain-driven design principles. Each service owns its database and communicates through well-defined APIs using OpenFeign.Architecture Diagram
The following diagram illustrates the complete system architecture, showing how components interact:Architectural Decisions
Database per Service Pattern
Each microservice maintains its own database to ensure loose coupling and independent scalability.
- Loose Coupling: Services don’t share database schemas, preventing coupling through the database
- Independent Scaling: Each database can be scaled independently based on service needs
- Technology Freedom: Each service can choose the optimal database technology
- Schema Evolution: Database schemas can evolve without affecting other services
- Data Consistency: Requires distributed transaction patterns (eventual consistency)
- Data Duplication: Some data may need to be replicated across services
- Complex Queries: Cross-service queries require API calls or data aggregation
Monorepo Approach
All microservices are maintained in a single repository: Advantages:- Simplified dependency management for shared libraries (DTOs, utilities)
- Single
docker-compose.ymlfor entire stack - Consistent versioning across services
- Easier refactoring and code navigation
- Atomic commits across multiple services
Synchronous Communication (Phase 1)
Current implementation uses OpenFeign for synchronous HTTP calls between services: Flow Example (Order Creation):- Client sends POST request to API Gateway
- Gateway routes to Order Service
- Order Service calls Inventory Service via Feign to validate stock
- Inventory Service responds with availability confirmation
- Order Service calls Tracking Service to create shipment
- Order Service responds to client with order details
Microservices Deep Dive
Order Service
Responsibility: Entry point for customer orders, orchestrates order creation workflow. Database: PostgreSQL (Port 5432) Configuration:Data Model
Order Entity:id: Long (Primary Key)orderNumber: String (UUID for public tracking)customerId: Long (Reference to customer)orderDate: LocalDateTimestatus: Enum (PENDING_CHECK,CONFIRMED,SHIPPED,CANCELLED)totalPrice: BigDecimal
id: Long (Primary Key)productId: Long (Reference to inventory product)quantity: IntegerpriceAtPurchase: BigDecimal (Historical price snapshot)
Storing
priceAtPurchase ensures order totals remain accurate even if product prices change later.Inventory Service
Responsibility: Manages product catalog and stock levels with reservation support. Database: MySQL (Port 3306) Configuration:Data Model
Product Entity (products table):
stocks table):
API Endpoints
The Inventory Service exposes REST endpoints at/api/v1/inventory:
- Reserve Stock: When an order is created, stock is moved from
totalQuantitytototalReserved - Release Stock: If an order is cancelled, reserved stock returns to available quantity
- Consume Stock: When order ships, reserved stock is permanently removed
- Add Stock: Inventory replenishment increases total quantity
Available stock =
totalQuantity - totalReserved. This prevents overselling during concurrent orders.Tracking Service
Responsibility: Records shipment lifecycle events with flexible event metadata. Database: MongoDB (Port 27017) Configuration:Data Model (MongoDB Collection)
Shipment Document:Why MongoDB? The schema-less nature allows different event types to store diverse information (GPS coordinates, delivery photos, customs data, weather incidents) without requiring schema migrations.
- Generates unique
trackingNumberusing UUID - Supports multiple carriers (DHL, FedEx, UPS, etc.)
- Flexible event metadata (GPS, photos, signatures)
- Real-time event aggregation
- Historical tracking data retention
Infrastructure Services
Eureka Server (Port 8761)
Purpose: Service discovery and registration. How it works:- Each microservice registers with Eureka on startup
- Services periodically send heartbeats to maintain registration
- Services query Eureka to discover other service instances
- Enables dynamic scaling without hardcoded URLs
Config Server (Port 8888)
Purpose: Centralized configuration management. Configuration sources:- Local file system
- Git repository (recommended for production)
- Environment variables
- Change configuration without rebuilding services
- Environment-specific configurations (dev, staging, prod)
- Encrypted sensitive properties
- Configuration versioning with Git
API Gateway (Port 8080)
Purpose: Single entry point for external clients. Responsibilities:- Routing: Forwards requests to appropriate microservices
- Security: Authentication and authorization
- Rate Limiting: Prevents API abuse
- Load Balancing: Distributes load across service instances
- Circuit Breaking: Handles service failures gracefully
- Request/Response Transformation: Standardizes API contracts
Communication Patterns
Service-to-Service Communication (OpenFeign)
Example: Order Service calling Inventory Service- Discovers service instances via Eureka
- Performs client-side load balancing
- Handles request serialization/deserialization
- Integrates with Spring Cloud Circuit Breaker
Data Transfer Objects (DTOs)
Services communicate using well-defined DTOs: InventoryRequest: Order Service → Inventory ServiceData Consistency Strategies
Saga Pattern (Future Implementation)
For distributed transactions across services: Order Creation Saga:- Create order (Order Service)
- Reserve stock (Inventory Service)
- Create shipment (Tracking Service)
- Confirm order (Order Service)
- Release reserved stock
- Cancel shipment
- Mark order as cancelled
Eventual Consistency
The system accepts that data across services may be temporarily inconsistent but will eventually converge to a consistent state.
- Order Service creates order (status: PENDING_CHECK)
- Inventory check happens asynchronously
- Order status updates to CONFIRMED or CANCELLED
Scaling Strategies
Horizontal Scaling
Each service can be independently scaled:Database Scaling
PostgreSQL (Order Service):- Read replicas for query scaling
- Connection pooling (HikariCP)
- Partitioning by date for historical data
- Read replicas for product catalog queries
- Write-through caching (Redis) for hot products
- Sharding by product category
- Replica sets for high availability
- Sharding by tracking number
- Time-series collections for event data
Security Considerations
Required for Production:- JWT-based authentication in API Gateway
- Service-to-service authentication (mutual TLS)
- Encrypted database connections
- Secret management (HashiCorp Vault, AWS Secrets Manager)
- Rate limiting and DDoS protection
- Input validation and SQL injection prevention
- CORS configuration for web clients
Monitoring and Observability
Recommended Tools (not yet implemented):- Spring Boot Actuator: Health checks and metrics
- Prometheus: Metrics collection
- Grafana: Metrics visualization
- ELK Stack: Centralized logging (Elasticsearch, Logstash, Kibana)
- Zipkin/Jaeger: Distributed tracing
- Spring Cloud Sleuth: Trace ID propagation
Next Steps
Quick Start
Get the system running locally
API Reference
Explore detailed API documentation