Skip to content

amanda622/TransportationOperationSystem

Repository files navigation

Logistics Order Management API

A backend service for a logistics operation: manage customers, vehicles, and orders, with a guarded order-status state machine and automatic vehicle dispatch. Built to demonstrate object-oriented design and a clean, layered backend architecture.

CI Python License

Replace USER/REPO in the badge once the project is on GitHub, and add a live demo link here after deploying (see Deployment).


What this project demonstrates

Skill Where to look
OOP / inheritance CustomerCorporate / Private via SQLAlchemy single-table inheritance (db/models.py)
Business modeling domain/ + db/models.py (Order, OrderItem, Vehicle, status history)
Order status flow domain/status_flow.py — a state machine that rejects illegal transitions
Dispatch rules domain/dispatch.py — chooses the smallest vehicle that fits the load
Database CRUD repositories/ — the only layer that touches the DB
REST API api/routers/ — orders, vehicles, customers, shipment status
Tests tests/ — 30 tests: domain unit + repository/service integration + API

Architecture

A strict layering — each layer depends only on the one below it:

        HTTP (FastAPI)              CLI
        api/routers/  ───────┐   cli/main.py
                             ▼        ▼
                       services/  (business logic, orchestration)
                             │
              ┌──────────────┼───────────────┐
              ▼              ▼                ▼
        domain/        repositories/     (rules)   (CRUD)
   (pure logic:        db/models.py + db/base.py
    status_flow,       SQLite / Postgres
    dispatch, enums)

Why it matters: the domain layer is pure Python (no database, no web), so the business rules are trivially testable. The services layer is the single home of business logic, which is why the API and CLI can share it without duplication.

Order status state machine

PENDING ─▶ CONFIRMED ─▶ ASSIGNED ─▶ IN_TRANSIT ─▶ DELIVERED
   │           │            │
   └───────────┴────────────┴──▶ CANCELLED

DELIVERED and CANCELLED are terminal. Any illegal jump (e.g. DELIVERED → PENDING) is rejected with HTTP 409 and a message listing the allowed next states. Every transition is recorded in an order_status_history table, exposed as a timeline at GET /orders/{id}/status.

Vehicle dispatch

Each vehicle type has a capacity; assign-vehicle picks the smallest type that fits the order's item count and weight, reserves an available vehicle, marks it busy, and frees it again when the order is delivered.

Type Max items Max weight
bike 2 10 kg
truck 100 3,000 kg
ship 10,000 100,000 kg

Tech stack

Python 3.11+ · FastAPI · Pydantic v2 · SQLAlchemy 2 · SQLite / Postgres · pytest · Ruff · Docker · GitHub Actions.

Project structure

src/transport_ops/
├── config.py                  schemas/    customer.py order.py vehicle.py
├── domain/   enums.py status_flow.py dispatch.py errors.py
├── db/       base.py  models.py
├── repositories/  customer_repo.py order_repo.py vehicle_repo.py
├── services/      customer_service.py order_service.py vehicle_service.py
├── api/      app.py deps.py  routers/ customers.py vehicles.py orders.py
└── cli/      main.py
tests/  Dockerfile  docker-compose.yml  Makefile  pyproject.toml

Getting started (local)

Requires Python 3.11+.

python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

# Run the API (http://127.0.0.1:8000)
uvicorn transport_ops.api.app:app --reload

Open http://127.0.0.1:8000/docs for interactive Swagger docs. Tables are created automatically on startup (SQLite by default).

A Makefile wraps common commands: make install, make test, make lint, make run, make cli, make docker-up.

API walkthrough

# 1. Create a customer (corporate or private — one polymorphic endpoint)
curl -X POST localhost:8000/customers -H 'Content-Type: application/json' -d \
 '{"customer_type":"private","reference_person":"Alice","contact_email":"a@x.com","invoice_email":"a@x.com"}'

# 2. Add a vehicle
curl -X POST localhost:8000/vehicles -H 'Content-Type: application/json' -d \
 '{"vehicle_type":"truck","current_location":"Beijing"}'

# 3. Create an order, add items
curl -X POST localhost:8000/orders -H 'Content-Type: application/json' -d \
 '{"customer_id":1,"delivery_location":"456 Oak Ave"}'
curl -X POST localhost:8000/orders/1/items -H 'Content-Type: application/json' -d \
 '{"name":"Laptop","weight":2,"quantity":10}'

# 4. Walk the status flow (confirm → auto-assign vehicle → in_transit → delivered)
curl -X POST localhost:8000/orders/1/status -H 'Content-Type: application/json' -d '{"status":"confirmed"}'
curl -X POST localhost:8000/orders/1/assign-vehicle
curl -X POST localhost:8000/orders/1/status -H 'Content-Type: application/json' -d '{"status":"in_transit"}'
curl -X POST localhost:8000/orders/1/status -H 'Content-Type: application/json' -d '{"status":"delivered"}'

# 5. Shipment status timeline
curl localhost:8000/orders/1/status

Endpoints

Method Path Description
GET /health Liveness probe
POST/GET/DELETE /customers Manage customers (corporate/private)
POST/GET/PATCH /vehicles Manage vehicles
POST/GET /orders Create & list orders
POST /orders/{id}/items Add an item
POST /orders/{id}/assign-vehicle Auto-select & assign a vehicle
POST /orders/{id}/status Guarded status transition
GET /orders/{id}/status Current status + history timeline

Command-line interface

The same services power a terminal menu:

python -m transport_ops.cli.main

Testing & quality

pytest          # 30 tests
ruff check .    # lint

Tests cover the state machine and dispatch rules (pure unit tests), the repositories and order service (integration, against an isolated SQLite DB), and the API — including that an illegal transition returns 409 and a missing entity returns 404.

Docker

docker compose up --build

Builds the API image and starts it with a Postgres database on http://localhost:8000. (Locally without Docker it defaults to SQLite.)

Deployment

The image is self-contained, so any container host works. Quickest public demo:

Render (free tier):

  1. Push the repo to GitHub.
  2. On render.com, create a Web Service from the repo, environment Docker.
  3. Add a Postgres instance and set DATABASE_URL to its postgresql+psycopg://... connection string.
  4. Deploy and put the live URL at the top of this README.

The same image deploys to Railway or Fly.io via their "deploy from Dockerfile" flows.

License

MIT.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages