Files
2026-06-15 11:56:18 +03:00

14 KiB

Cymelle

Cymelle is a commerce, delivery, and ride operations application. Customers can browse products, place orders, request delivery rides, and complete a simulated checkout. Admins manage products, inventory, orders, users, and rides. Drivers accept and complete delivery rides.

Screenshots

Storefront product listing
Storefront product listing
Customer dashboard
Customer dashboard
Customer ride history
Customer ride history
Driver dashboard
Driver dashboard
Admin dashboard
Admin dashboard
Admin operations overview
Admin operations overview
Admin inventory health
Admin inventory health
Admin users management
Admin users management
Admin orders management
Admin orders management
Admin product catalog
Admin product catalog

Architecture

The current system is a three-tier application: a React frontend, a Spring Boot API, and PostgreSQL.

+-----------------------------+
| Browser                     |
| Customer / Admin / Driver   |
+-------------+---------------+
              |
              | HTTP
              | http://localhost:3000
              v
+-----------------------------+
| orders-frontend             |
| React + TypeScript          |
| TanStack Router + Query     |
| Vite dev server             |
+-------------+---------------+
              |
              | REST API
              | VITE_API_BASE_URL
              | http://localhost:8080/api
              v
+-----------------------------+
| orders-backend              |
| Spring Boot REST API        |
| Security + Services + JPA   |
| Swagger/OpenAPI             |
+--------+--------------------+
         |
         | JDBC
         v
+----------------+
| PostgreSQL     |
| app data       |
+----------------+

Local Docker Compose runs the same shape with three services:

+------------------------------------------------------------+
| Docker Compose project: cymelle                            |
|                                                            |
|  web: node:24                         api: temurin 17      |
|  pnpm dev --host 0.0.0.0              ./gradlew bootRun    |
|  localhost:3000      ------------->   localhost:8080       |
|       |                                      |              |
|       v                                      v              |
|  orders-frontend/                       db: postgres:18    |
|  bind mount                             localhost:5432     |
|                                              |             |
|                                              v             |
|                                       postgres-data volume |
+------------------------------------------------------------+

Project Layout

  • orders-frontend/: React web app, route files, API clients, hooks, shared UI, dashboard and storefront screens.
  • orders-backend/: Spring Boot API, controllers, services, repositories, DTOs, entities, security, OpenAPI, and seed data.
  • compose.yml: Local development stack for Postgres, API, and web.
  • .env.example: Local environment variables consumed by Docker Compose.
  • render.yaml: Render Blueprint for Docker-backed deployment.
  • DEPLOYMENT.md: Render and Neon deployment notes.
  • PART_2.md: Real-time location tracking backend design walkthrough.

Tech Stack

Frontend

  • React 19
  • TypeScript
  • Vite
  • TanStack Router for file-based routing
  • TanStack Query for server state
  • TanStack Table and TanStack Form
  • Tailwind CSS 4
  • Radix UI, local UI components, Lucide React, and Tabler Icons
  • pnpm
  • Biome for linting and formatting
  • Vitest for tests
  • Nitro output for production server builds

Backend

  • Java 17
  • Spring Boot 3.5
  • Spring Web
  • Spring Security
  • Spring Data JPA
  • Bean Validation
  • PostgreSQL driver
  • H2 test dependency
  • Springdoc OpenAPI / Swagger UI
  • Gradle Kotlin DSL

Infrastructure

  • Docker Compose for local development
  • PostgreSQL 18 Alpine locally
  • Render Docker web services for deployment
  • Neon PostgreSQL for deployed database
  • Simulated checkout for local and deployed testing

Domain Model

AppUser
  id, username, displayName, passwordHash, role, enabled
  role: ADMIN | CUSTOMER | DRIVER
      |
      +--> CUSTOMER owns Orders and requested Rides
      +--> DRIVER can accept and complete Rides
      +--> ADMIN manages products, users, orders, inventory, and rides

Product
  id, name, sku, price, currency, active
      |
      +-- one-to-one --> InventoryItem
      |
      +-- many-to-one from --> OrderItem

InventoryItem
  id, product, availableQuantity, reservedQuantity, reorderLevel
  status: IN_STOCK | LOW_STOCK | OUT_OF_STOCK

Order
  id, customerName, customer, status, totalAmount, currency, createdAt
  status: PENDING | SHIPPED | DELIVERED | CANCELLED
      |
      +-- one-to-many --> OrderItem
      |
      +-- optional delivery association --> Ride
      |
      +-- one-to-one --> Payment

OrderItem
  id, order, product, productName, quantity, unitPrice, lineTotal
  stores product name and price snapshot at checkout time

Ride
  id, customer, driver, order, pickupLocation, dropoffLocation
  distanceKm, fareAmount, currency, status
  status: REQUESTED | ACCEPTED | COMPLETED | CANCELLED

Payment
  id, order, ride, reference, productSubtotal, rideFare
  amountMajor, amountSubunits, currency, status
  status: PENDING | PAID | FAILED | ABANDONED | REFUNDED

Main Application Flows

Authentication

User registers or logs in
        |
        v
Spring Security authenticates credentials
        |
        v
Frontend calls /api/auth/me
        |
        v
Routes and backend endpoints use the user's role

Roles drive most behavior:

  • Customers can browse, order, pay, request rides, and view their own orders.
  • Drivers can see requested rides, accept rides, and complete assigned rides.
  • Admins can manage users, products, orders, inventory, and ride status.

Product and Inventory

Admin creates product
        |
        v
Product stored with SKU, price, currency, active flag
        |
        v
InventoryItem tracks available quantity and reorder level
        |
        v
Inventory status is derived from available quantity

Inventory status is computed:

  • OUT_OF_STOCK when available quantity is 0
  • LOW_STOCK when available quantity is at or below the reorder level
  • IN_STOCK otherwise

Checkout Quote

Customer submits cart + optional delivery ride
        |
        v
Backend validates products and stock
        |
        v
Backend calculates product subtotal
        |
        +--> optional fare calculation for delivery ride
        |
        v
Quote returns productSubtotal, rideFare, grandTotal, currency, expiresAt

The quote endpoint is useful before checkout so the customer can see the final total.

Order Placement

Customer places order
        |
        v
Backend loads active products
        |
        v
Backend locks inventory rows for update
        |
        +--> insufficient stock -> request fails
        |
        v
Inventory is deducted
        |
        v
Order and OrderItems are created as PENDING
        |
        +--> optional delivery ride is created as REQUESTED

Order items store productName, unitPrice, and lineTotal, so historical orders keep their checkout-time product snapshot even if the product changes later.

Simulated Checkout

Customer starts checkout
        |
        v
Backend calculates quote and creates pending order
        |
        v
Payment row is created with unique reference
        |
        v
Backend marks the local simulated payment as PAID
        |
        v
Frontend clears the cart and sends the customer to orders

No external payment provider is required for local or deployed testing.

Order Status

PENDING -> SHIPPED -> DELIVERED
   |
   +-> CANCELLED

Rules in the domain model:

  • Only pending orders can be cancelled by the normal cancellation flow.
  • Cancelling restores inventory quantities.
  • Final orders cannot be moved to another status.
  • Completing an attached ride marks the order as delivered.

Ride Status

REQUESTED -> ACCEPTED -> COMPLETED
    |
    +-> CANCELLED

Ride behavior:

  • Customers request rides for their own orders.
  • Drivers see requested rides plus rides assigned to them.
  • Drivers accept requested rides.
  • Drivers complete rides assigned to them.
  • Completing a ride also marks the attached order as delivered.
  • Admins can cancel or complete rides.

API Surface

All backend endpoints are under /api.

Area Endpoints
Auth POST /auth/register, POST /auth/login, POST /auth/logout, GET /auth/me, GET /auth/csrf
Products GET /products, GET /products/{id}, POST /products, PUT /products/{id}, DELETE /products/{id}
Inventory GET /inventory, GET /inventory/low-stock
Orders POST /orders, GET /orders, GET /orders/{id}, DELETE /orders/{id}, PATCH /orders/{id}/status
Checkout POST /checkout/quote, POST /checkout/simulate
Rides GET /rides, POST /rides, POST /rides/{id}/accept, POST /rides/{id}/complete, DELETE /rides/{id}, PATCH /rides/{id}/status
Users GET /users, GET /users/customers, GET /users/drivers, POST /users, PUT /users/{id}, DELETE /users/{id}
Fare GET /fare/calculate
Health GET /health

Swagger UI is available locally at http://localhost:8080/swagger-ui.html.

Seed Data

Local development seeds demo data when SEED_DATA=true.

Demo users:

Role Username Password
Admin admin admin123
Driver driver driver123
Driver driver2 driver123
Driver driver3 driver123
Customer customer customer123
Customer customer2 customer123
Customer customer3 customer123
Customer customer4 customer123

Seeded products include accessories and office equipment such as wireless mice, keyboards, cables, stands, webcams, headphones, monitors, docks, backpacks, power banks, drawing tablets, and chairs.

Local Development

Prerequisites

  • Docker and Docker Compose

Run Everything With Docker Compose

cp .env.example .env
docker compose up

Services:

  • Web: http://localhost:3000
  • API base URL: http://localhost:8080/api
  • Swagger UI: http://localhost:8080/swagger-ui.html
  • OpenAPI JSON: http://localhost:8080/api-docs
  • Postgres: localhost:5432
  • Default database/user/password: cymelle / cymelle / cymelle

Seeded test credentials are available when SEED_DATA=true:

Role Username Password
Admin admin admin123
Driver driver driver123
Customer customer customer123

Useful commands:

docker compose logs -f api
docker compose logs -f web
docker compose restart api
docker compose down
docker compose down -v

The web service mounts orders-frontend/, so frontend edits reload through Vite. Restart the api service after backend code changes. Use docker compose down -v only when you want to delete local Postgres data and dependency cache volumes.

Environment Variables

Copy .env.example to .env, then adjust values as needed.

POSTGRES_DB=cymelle
POSTGRES_USER=cymelle
POSTGRES_PASSWORD=cymelle
POSTGRES_PORT=5432

API_PORT=8080
WEB_PORT=3000
VITE_API_BASE_URL=http://localhost:8080/api
APP_CORS_ALLOWED_ORIGINS=http://localhost:3000
SEED_DATA=true

LOW_STOCK_THRESHOLD=10

FARE_BASE_FARE=100.00
FARE_PER_KM_RATE=50.00
FARE_MINIMUM_FARE=150.00
FARE_DEFAULT_SURGE_MULTIPLIER=1.0
FARE_CURRENCY=KES

Run Services Manually

Docker Compose is recommended, but the services can run separately.

Backend:

cd orders-backend
SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/cymelle \
SPRING_DATASOURCE_USERNAME=cymelle \
SPRING_DATASOURCE_PASSWORD=cymelle \
APP_CORS_ALLOWED_ORIGINS=http://localhost:3000 \
./gradlew bootRun

Frontend:

cd orders-frontend
corepack enable
pnpm install
VITE_API_BASE_URL=http://localhost:8080/api pnpm dev

Development Checks

Backend tests:

cd orders-backend
./gradlew test

Frontend checks:

cd orders-frontend
pnpm test
pnpm lint
pnpm check

Deployment

See DEPLOYMENT.md for Render deployment steps. The deployed setup uses:

  • cymelle-api: Spring Boot API Docker service
  • cymelle-web: TanStack/Nitro frontend Docker service
  • Neon PostgreSQL through DATABASE_URL

Real-Time Location Design

See PART_2.md for the proposed backend architecture for real-time location updates across delivery and ride trips.