Skip to content

Latest commit

Β 

History

10 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ“¦ Smart Logistic - Logistics Management System

Java Spring Boot PostgreSQL License

CI/CD Pipeline Docker Build Deploy to GitHub Pages

Enterprise-grade logistics management system with intelligent package routing, capacity optimization, and state machine validation.

Live Demo β€’ Features β€’ Quick Start β€’ API Docs β€’ Contributing


πŸ“‹ Table of Contents


🎯 Overview

Smart Logistic is a production-ready logistics management system built with Spring Boot 3 and Clean Architecture principles. It demonstrates enterprise software development best practices including:

  • βœ… Domain-Driven Design (DDD) - Rich domain models with business logic
  • βœ… Clean Architecture - Layered design with clear separation of concerns
  • βœ… SOLID Principles - Maintainable and extensible codebase
  • βœ… Test-Driven Development - Comprehensive unit tests (12 tests, 100% pass rate)
  • βœ… RESTful API Design - Industry-standard REST endpoints
  • βœ… Transaction Management - ACID guarantees with Spring @Transactional

✨ Features

1. πŸ›‘οΈ Capacity Guard - Vehicle Overload Prevention

Validates vehicle capacity before package assignment to prevent overloading.

// Validation Logic: src/main/java/.../service/DeliveryService.java:47-56
if (!vehicle.canLoad(totalPackageWeight)) {
    throw VehicleOverloadedException.forPackage(
        vehicle.getLicensePlate(),
        totalPackageWeight,
        vehicle.getRemainingCapacityKg()
    );
}

Business Rule: totalWeight + currentLoad <= vehicleCapacity

2. πŸ”„ State Machine - Package Status Validation

Enforces valid package status transitions to maintain data integrity.

// State Machine: src/main/java/.../domain/entity/Package.java:55-65
public boolean canTransitionTo(PackageStatus newStatus) {
    return switch (this.status) {
        case CREATED -> newStatus == PackageStatus.LOADED;
        case LOADED -> newStatus == PackageStatus.DELIVERED;
        case DELIVERED -> false; // Terminal state
    };
}

Valid Flow: CREATED β†’ LOADED β†’ DELIVERED (no skipping allowed)

3. 🎯 Smart Routing - Deadline-Based Optimization

Automatically sorts packages by delivery deadline for optimal route planning.

// Routing Algorithm: src/main/java/.../service/DeliveryService.java:58-61
List<Package> sortedPackages = packages.stream()
    .sorted(Comparator.comparing(Package::getDeliveryDeadline))
    .toList();

Result: Earliest deadline packages are delivered first.


🎨 Demo

Web UI

Access the modern web interface at http://localhost:8080 after starting the application.

API Examples

βœ… SUCCESS: Assign packages within capacity

curl -X POST http://localhost:8080/api/delivery/assign \
  -H "Content-Type: application/json" \
  -d '{
    "vehicleId": 1,
    "packageIds": [4, 2, 5]
  }'

# Response: 200 OK (packages sorted by deadline)

❌ FAILURE: Capacity Guard prevents overload

curl -X POST http://localhost:8080/api/delivery/assign \
  -H "Content-Type: application/json" \
  -d '{
    "vehicleId": 1,
    "packageIds": [1, 3]
  }'

# Response: 400 Bad Request
{
  "status": 400,
  "error": "Vehicle Overload",
  "message": "Vehicle 'ABC-1234' cannot load package of 450.00 kg..."
}

❌ FAILURE: State Machine prevents invalid transition

curl -X PATCH http://localhost:8080/api/packages/1/status \
  -H "Content-Type: application/json" \
  -d '{"status": "DELIVERED"}'

# Response: 400 Bad Request
{
  "status": 400,
  "error": "Invalid Status Transition",
  "message": "Package cannot transition from CREATED to DELIVERED"
}

πŸ›  Tech Stack

Category Technology
Language Java 17+
Framework Spring Boot 3.2.1
Database PostgreSQL 16 (Docker)
ORM Spring Data JPA + Hibernate
Validation Jakarta Bean Validation
Mapping MapStruct + Lombok
Testing JUnit 5 + Mockito
Build Tool Maven 3.6+
Containerization Docker & Docker Compose

πŸ— Architecture

Layered Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Controller Layer                      β”‚
β”‚        (REST API Endpoints + DTO Validation)            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    Service Layer                         β”‚
β”‚   (Business Logic: Capacity Guard, State Machine)       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                  Repository Layer                        β”‚
β”‚           (Spring Data JPA Repositories)                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           ↓
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   Database Layer                         β”‚
β”‚                (PostgreSQL 16)                          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Domain Model

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Vehicle   │◄────────│DeliveryRoute │────────►│   Package   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€         β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€        β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ id          β”‚         β”‚ id           β”‚        β”‚ id          β”‚
β”‚ licensePlateβ”‚         β”‚ vehicle      β”‚        β”‚ address     β”‚
β”‚ capacityKg  β”‚         β”‚ packages[]   β”‚        β”‚ weightKg    β”‚
β”‚ currentLoad β”‚         β”‚ createdAt    β”‚        β”‚ status      β”‚
β”‚ status      β”‚         β”‚ completedAt  β”‚        β”‚ deadline    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Quick Start

Prerequisites

Ensure you have the following installed:

java -version    # Java 17 or higher
mvn -version     # Maven 3.6+
docker --version # Docker Desktop

1. Clone the Repository

git clone https://github.com/yourusername/logiroute.git
cd logiroute

2. Start PostgreSQL

# Start PostgreSQL container
docker-compose up -d

# Verify database is ready (wait 10-15 seconds)
docker exec logiroute-postgres psql -U postgres -d logiroute -c "SELECT 1"

Note: If you have a local PostgreSQL running on port 5432, stop it first:

brew services stop postgresql@14  # macOS
# or
sudo systemctl stop postgresql    # Linux

3. Run Tests (Optional but Recommended)

mvn test

# Expected output: Tests run: 12, Failures: 0, Errors: 0

4. Start the Application

mvn spring-boot:run

Wait for: Started LogiRouteApplication in X.XXX seconds

5. Access the Application

Seed Data

The application automatically loads test data:

  • 2 vehicles: ABC-1234 (1000kg), XYZ-5678 (1500kg)
  • 5 packages: Various weights and deadlines

πŸ“š API Documentation

Vehicles

Method Endpoint Description
GET /api/vehicles List all vehicles
GET /api/vehicles/{id} Get vehicle by ID
GET /api/vehicles/available Get available vehicles
POST /api/vehicles Create new vehicle
PUT /api/vehicles/{id} Update vehicle
DELETE /api/vehicles/{id} Delete vehicle

Packages

Method Endpoint Description
GET /api/packages List all packages
GET /api/packages/{id} Get package by ID
GET /api/packages/unassigned Get unassigned packages
GET /api/packages/status/{status} Filter by status
POST /api/packages Create new package
PUT /api/packages/{id} Update package
PATCH /api/packages/{id}/status Update status (validates state machine)
DELETE /api/packages/{id} Delete package

Delivery Operations

Method Endpoint Description
POST /api/delivery/assign Assign packages to vehicle (capacity guard)
GET /api/delivery/routes Get all active routes
GET /api/delivery/routes/{id} Get route by ID
GET /api/delivery/routes/vehicle/{vehicleId} Get routes by vehicle
PATCH /api/delivery/routes/{id}/complete Complete delivery route

πŸ“‚ Project Structure

src/main/java/com/logistics/logiroute/
β”œβ”€β”€ config/
β”‚   └── DataLoader.java              # Seed data configuration
β”œβ”€β”€ controller/
β”‚   β”œβ”€β”€ DeliveryController.java      # Delivery operations REST API
β”‚   β”œβ”€β”€ PackageController.java       # Package CRUD operations
β”‚   └── VehicleController.java       # Vehicle CRUD operations
β”œβ”€β”€ domain/
β”‚   β”œβ”€β”€ entity/
β”‚   β”‚   β”œβ”€β”€ DeliveryRoute.java       # Route entity
β”‚   β”‚   β”œβ”€β”€ Package.java             # Package entity (State Machine)
β”‚   β”‚   └── Vehicle.java             # Vehicle entity (Capacity logic)
β”‚   └── enums/
β”‚       β”œβ”€β”€ PackageStatus.java       # CREATED, LOADED, DELIVERED
β”‚       └── VehicleStatus.java       # AVAILABLE, IN_TRANSIT
β”œβ”€β”€ dto/                             # Data Transfer Objects
β”‚   β”œβ”€β”€ request/                     # Request DTOs
β”‚   └── response/                    # Response DTOs
β”œβ”€β”€ exception/
β”‚   β”œβ”€β”€ GlobalExceptionHandler.java  # Centralized error handling
β”‚   β”œβ”€β”€ VehicleOverloadedException.java
β”‚   β”œβ”€β”€ InvalidStatusTransitionException.java
β”‚   └── ResourceNotFoundException.java
β”œβ”€β”€ mapper/                          # MapStruct mappers
β”‚   β”œβ”€β”€ DeliveryRouteMapper.java
β”‚   β”œβ”€β”€ PackageMapper.java
β”‚   └── VehicleMapper.java
β”œβ”€β”€ repository/                      # Spring Data JPA repositories
β”‚   β”œβ”€β”€ DeliveryRouteRepository.java
β”‚   β”œβ”€β”€ PackageRepository.java
β”‚   └── VehicleRepository.java
└── service/
    β”œβ”€β”€ DeliveryService.java         # Core business logic
    β”œβ”€β”€ PackageService.java
    └── VehicleService.java

πŸ§ͺ Testing

Run All Tests

mvn test

Run Specific Test Class

mvn test -Dtest=DeliveryServiceTest

Test Coverage

12 comprehensive unit tests covering:

βœ… Capacity Guard:

  • Success: Packages within capacity
  • Failure: Single package exceeds capacity
  • Failure: Multiple packages exceed capacity

βœ… State Machine:

  • Valid transitions (CREATEDβ†’LOADED, LOADEDβ†’DELIVERED)
  • Invalid transition prevention (CREATEDβ†’DELIVERED)
  • Backward transition prevention
  • No transitions from DELIVERED state

βœ… Smart Routing:

  • Packages sorted by earliest deadline

βœ… Additional:

  • Resource not found handling
  • Route completion
  • Package state validation

🌐 GitHub Pages Setup

To enable GitHub Pages for this project:

  1. Go to your repository on GitHub
  2. Navigate to Settings β†’ Pages
  3. Under Source, select "GitHub Actions" (not "Deploy from a branch")
  4. Click Save

The deployment will automatically trigger when you push changes to the docs/ directory. The site will be available at:

https://meliharik.github.io/smart_logistic/

Manual Deployment

You can also trigger the deployment manually:

  1. Go to the Actions tab in your repository
  2. Select the Deploy to GitHub Pages workflow
  3. Click Run workflow β†’ Run workflow

Workflow Status

  • Deploy to GitHub Pages

Note: If the badge shows "failing", it means GitHub Pages hasn't been enabled yet in repository settings. Follow the steps above to enable it.


πŸ› Troubleshooting

Issue: Application won't start - Port 8080 already in use

Solution:

# Find process using port 8080
lsof -i :8080

# Kill the process
kill -9 <PID>

# Or kill all Java processes
pkill -9 java

Issue: PostgreSQL connection failed - "role does not exist"

Solution:

# Stop local PostgreSQL if running
brew services stop postgresql@14  # macOS
sudo systemctl stop postgresql    # Linux

# Reset Docker PostgreSQL
docker-compose down -v
docker-compose up -d
sleep 15

# Restart application
mvn spring-boot:run

Issue: Tests failing

Solution:

# Clean and rebuild
mvn clean compile

# Run tests with detailed output
mvn test -X

Issue: PostgreSQL container won't start

Solution:

# Check Docker is running
docker ps

# View logs
docker logs logiroute-postgres

# Complete reset
docker-compose down -v
docker-compose up -d

🀝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

Quick Contribution Steps

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

Development Guidelines

  • Follow the existing code style
  • Write unit tests for new features
  • Update documentation as needed
  • Ensure all tests pass before submitting PR

πŸ“„ License

This project is licensed under the MIT License - see the LICENSE file for details.


πŸ“ž Contact & Support


🌟 Acknowledgments

Built with:


⭐ If you find this project useful, please consider giving it a star! ⭐

Made with ❀️ using Spring Boot 3, Clean Architecture, and Domain-Driven Design

About

Logistics management system built with Java 17, Spring Boot 3 and PostgreSQL. Shipment tracking and route planning.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages