Skip to content

Repository files navigation

WeBox — Employee Meal Ordering Platform

An enterprise-grade meal ordering platform for company employees. Built with Java 17 + Spring Boot (backend) and React + TypeScript (frontend).

Tech Stack

Layer Technology
Backend Java 17, Spring Boot 3.3.4, Spring Security, Spring Data JPA
Frontend React 18, TypeScript, Vite, Ant Design, Zustand
Database MySQL 8.x (external, standalone)
Cache Caffeine (in-memory)
Auth JWT HS384 (access 1h + refresh 7d tokens)
Build Maven (backend), npm (frontend)

Features

Tier 1 — Core

  • Employee registration & login (JWT, bcrypt, email validation)
  • Daily menu browsing with dish cards, images, prices
  • Dish detail with customization options (required/optional, extra costs)
  • Multi-select cuisine filter + keyword search
  • Shopping cart with unique entries per customization
  • Idempotent order placement (UUID-based)
  • Order history & detail with cancellation

Tier 2 — Advanced

  • Dietary Preferences: Allergen marking, cuisine preferences, spice/taste preferences, per-meal budget
  • Allergen Warning: Popup when adding allergen-containing dishes to cart
  • Ordering Rules: Max 5 items/order, cutoff times (10:00 lunch / 15:00 dinner), auto-switch meal slot, duplicate prevention
  • Admin Console: Dish CRUD, on/off shelf toggle, daily menu setup with supply quantities
  • Role-based Access: Admin-only routes and API endpoints

Project Structure

webox-xuhaodong-20260831/
├── backend/               # Spring Boot application
│   ├── pom.xml
│   └── src/main/java/com/webox/
│       ├── config/        # Security, Cache, Web, DataInitializer
│       ├── controller/    # REST endpoints (auth, dishes, orders, admin)
│       ├── dto/           # Request/Response DTOs
│       ├── entity/        # JPA entities
│       ├── enums/         # Domain enums
│       ├── exception/     # Global exception handling
│       ├── repository/    # Spring Data JPA repositories
│       ├── security/      # JWT provider & filter
│       └── service/       # Business logic
├── frontend/              # React SPA
│   └── src/
│       ├── api/           # Axios client & API modules
│       ├── components/    # Layout, dish, cart, admin components
│       ├── pages/         # Page components
│       ├── store/         # Zustand state management
│       ├── types/         # TypeScript type definitions
│       └── utils/         # Money, cart, date utilities
├── docs/                  # PRD and product images
├── ai-conversations/      # AI coding conversation logs (required deliverable)
├── API.md                 # Full API reference with request/response examples
├── ARCHITECTURE.md        # System architecture, data flow, design decisions
└── README.md              # This file

Prerequisites

  • JDK 17+java -version
  • Maven 3.8+mvn -version
  • Node.js 18+node -v
  • MySQL 8.x — running and accessible

Quick Start

1. Database Setup

Create a MySQL database:

CREATE DATABASE webox CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

Update credentials in backend/src/main/resources/application.yml if needed:

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/webox?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
    username: root
    password: root

2. Start Backend

cd backend
mvn spring-boot:run

The backend starts on port 8080. On first run:

  • Flyway automatically runs 4 migration scripts (users, dishes, orders, preferences)
  • DataInitializer seeds:
    • Admin account: admin@webox.com / Admin123
    • 9 dishes with customization options (burgers, pasta, salads, etc.)
    • 20 product images copied from docs/webox_product_images/product_images/./uploads/
    • Today's daily menu (all 9 dishes, 50 supply each)
    • Tomorrow's daily menu (6 dishes, 30 supply each)

3. Start Frontend

cd frontend
npm install
npm run dev

The frontend starts on port 5173 with a Vite proxy (/apihttp://localhost:8080).

4. Access the Application

API Endpoints

Method Path Auth Description
POST /api/auth/register Public Register new employee
POST /api/auth/login Public Login → JWT tokens
POST /api/auth/refresh Public Refresh access token
GET /api/auth/me Bearer Current user info
GET /api/menu/today Bearer Today's menu with inventory
GET /api/menu/{date} Bearer Menu for specific date
GET /api/dishes Bearer Search/filter dishes
GET /api/dishes/{id} Bearer Dish detail + customizations
GET /api/orders/current-slot Bearer Current meal slot + active order check
POST /api/orders Bearer Place order (idempotent)
GET /api/orders Bearer Order history (paginated)
GET /api/orders/{orderNo} Bearer Order detail
PUT /api/orders/{orderNo}/cancel Bearer Cancel pending order
GET /api/preferences Bearer Get dietary preferences
PUT /api/preferences Bearer Update dietary preferences
POST /api/files/upload Admin Upload dish image
GET /api/files/{filename} Public Serve uploaded file
GET /api/admin/dishes Admin List all dishes (incl. off-shelf)
POST /api/admin/dishes Admin Create dish
PUT /api/admin/dishes/{id} Admin Update dish
PATCH /api/admin/dishes/{id}/status Admin Toggle on/off shelf
GET /api/admin/daily-menu/{date} Admin View daily menu setup
PUT /api/admin/daily-menu/{date} Admin Setup daily menu

Full API reference with request/response examples: see API.md.

Architecture

┌─────────────────────────────────────────┐
│        React SPA (port 5173)            │
│   Ant Design + Zustand + Axios          │
│   JWT auto-refresh interceptor          │
└──────────────────┬──────────────────────┘
                   │ HTTP (Vite proxy /api → :8080)
┌──────────────────▼──────────────────────┐
│       Spring Boot (port 8080)           │
│                                         │
│  ┌─ Security ──────────────────────┐   │
│  │ JWT filter · BCrypt · RBAC      │   │
│  └─────────────────────────────────┘   │
│  ┌─ Controllers ───────────────────┐   │
│  │ Auth · Dish · Order · Prefs     │   │
│  │ AdminDish · AdminDailyMenu      │   │
│  └─────────────────────────────────┘   │
│  ┌─ Services ──────────────────────┐   │
│  │ @Transactional(rollbackFor)     │   │
│  │ @Cacheable / @CacheEvict        │   │
│  └─────────────────────────────────┘   │
│  ┌─ Repositories ──────────────────┐   │
│  │ Spring Data JPA                 │   │
│  │ Pessimistic locks (inventory)   │   │
│  └─────────────────────────────────┘   │
│  ┌─ Cache (Caffeine) ──────────────┐   │
│  │ dishes: 10 min · menu: 5 min    │   │
│  └─────────────────────────────────┘   │
└──────────────────┬──────────────────────┘
                   │ JDBC (Flyway migrations)
┌──────────────────▼──────────────────────┐
│        MySQL 8.x (standalone)           │
│   10 tables · utf8mb4                   │
└─────────────────────────────────────────┘

See ARCHITECTURE.md for detailed data flow, module breakdown, and design decisions.

Key Design Decisions

Decision Approach
Money All prices stored as INT in cents (¥22.50 = 2250). No floating-point arithmetic anywhere.
Idempotency Client generates crypto.randomUUID() per order. DB UNIQUE constraint on idempotency_key.
Inventory safety UPDATE ... WHERE supply - sold >= qty atomic row-level operation. No overselling under concurrency.
Order snapshots order_items store dish_name and unit_price_cents at order time. Historical orders survive dish edits.
Cache Caffeine in-memory. Dishes: 10 min, daily menus: 5 min. Evicted on admin CRUD or order changes.
Cutoff logic < 10:00 → Lunch today · < 15:00 → Dinner today · ≥ 15:00 → Lunch tomorrow
Transactions All @Transactional declare rollbackFor = Exception.class for full rollback coverage.
Lazy loading Read methods use @Transactional(readOnly = true) to keep session open during DTO mapping.
Cart uniqueness `dishId::groupName:optionName
Product images Auto-copied from docs/webox_product_images/./uploads/ on first startup. Served at /api/files/.

Database Schema

users ─────────< orders ─────────< order_items ─────────< order_item_customizations
                  │
                  │ delivery_date + meal_slot (unique active per user)
                  │
dishes ─────────< daily_menu_items >───────── daily_menus
  │
  ├── customization_groups ────< customization_options
  │
dietary_preferences ──── users (1:1)

4 Flyway migrations: V1__create_users, V2__create_dishes_and_menu, V3__create_orders, V4__create_dietary_preferences.

Running Tests

cd backend
mvn test

24 unit tests (JUnit 5 + Mockito) covering:

  • AuthService (5 tests): register, login, duplicate email, wrong password, user not found
  • OrderService (8 tests): place order, idempotency, 5-item limit, duplicate order, insufficient inventory, cancel, wrong user
  • InventoryService (5 tests): deduct, insufficient stock, restore, remaining calculation, low-stock threshold
  • DietaryPreferenceService (4 tests): get existing, get defaults, create, update
  • CutoffTime (2 tests): delivery date, meal slot determination

Deliverables Checklist

Item Status
Runnable full-stack code
README
API documentation (API.md)
Architecture documentation (ARCHITECTURE.md)
Test cases (24 unit tests, all passing)
AI coding conversation logs (ai-conversations/)
English UI (all user-facing content)
Independent MySQL (not embedded)
Seed data (dishes + images + admin)

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages