Restaurant Management System - Backend API
REST API for restaurant operations with 30+ endpoints, three-role RBAC, dual-token JWT, and a six-state order workflow, deployed on AWS EC2 behind Nginx.
Role
Backend Developer
Client
Academic Project - Web Programming Course
Team
Solo Developer
Timeline
1 week • 2025

Problem
Restaurant data mixes customers, staff and admins with very different permissions, while orders and prices must stay historically accurate as the menu changes.
Solution
Designed seven normalized Prisma models with price snapshots, composable auth and ownership middleware, Zod validation on every input, and a server-enforced order state machine.
Impact
30+ secured endpoints with indexed queries under 50 ms, rate limiting on sensitive routes, and a stable public deployment on AWS EC2.
Skills & Tools
Skills Applied
Tools & Software
Project Overview
A RESTful backend for restaurant operations — authentication, menu browsing, order processing, table management, and reviews — with granular role-based access control across 3 roles and 30+ endpoints. Deployed on AWS EC2 with an Elastic IP for a stable endpoint.
Stack
Node.js 20 + Express 5, Prisma ORM (SQLite in dev, PostgreSQL in prod), JWT dual-token auth, bcrypt (10 rounds), Zod validation, Helmet, a CORS whitelist, express-rate-limit, and gzip compression. 14 strategic indexes keep queries fast.
Database Design
Seven normalized entities: Users, Categories, MenuItems, Tables, Orders, OrderItems, and Reviews. Two patterns are central:
- Price snapshot — when an order is created, the current menu price is copied into
OrderItem.priceso historical totals stay accurate even after menu prices change. - Cascade strategy — CASCADE where children are integral (Order to OrderItem, reviews), RESTRICT to protect referenced data (cannot delete users or items with history), and SET NULL for tables so orders survive table removal.
Authentication & Authorization
Dual-token JWT balances security and UX: a 15-minute access token (memory-only) authorizes requests, while a 7-day refresh token issues new access tokens without re-login — stateless, revocable, and low-exposure.
Role-based access control spans 30+ endpoints across three roles:
| Role | Permissions | Restrictions |
|---|---|---|
| CUSTOMER | Create orders | Cannot see other users' orders |
| STAFF | All CUSTOMER permissions | Cannot delete menu items |
| ADMIN | All STAFF permissions | Can only delete orders with status CANCELLED |
Authorization is enforced by composable middleware — authenticateToken, then requireRole([...]), then an ownership check — so CUSTOMER queries are automatically scoped to their own userId.
Order Workflow
Orders follow a strict state machine; skipping states is rejected, and terminal states drive table status:
PENDING → CONFIRMED → PREPARING → READY → COMPLETED
↓
CANCELLED
| Current Status | Allowed Transitions | Who Can Transition | Side Effects |
|---|---|---|---|
| PENDING | CONFIRMED, CANCELLED | STAFF/ADMIN (confirm), CUSTOMER (cancel) | If DINE_IN: set table status to OCCUPIED |
| CONFIRMED | PREPARING, CANCELLED | STAFF/ADMIN | None |
| PREPARING | READY, CANCELLED | STAFF/ADMIN | None |
| READY | COMPLETED, CANCELLED | STAFF/ADMIN | None |
| COMPLETED | None (terminal state) | N/A | Set table status to AVAILABLE, unlock review permissions |
| CANCELLED | None (terminal state) | N/A | Set table status to AVAILABLE |
Order creation validates item availability, quantity bounds (1–20), and order type (DINE_IN requires an available table; TAKEAWAY/DELIVERY must not specify one). It generates an ORD-YYYYMMDD-XXXX number, snapshots prices, and sums the total atomically.
Querying, Tables & Reviews
- Filtering — every collection endpoint supports pagination (
page,limitup to 100), full-textsearch,sortBy/order, plus resource filters (category, price range, availability, status, date range), and returns pagination metadata. - Table status — updates automatically from order lifecycle events: a DINE_IN order sets a table OCCUPIED; completion or cancellation of the last active order returns it to AVAILABLE; staff can manually set RESERVED.
- Reviews — verified only: a user can review an item only after a COMPLETED order containing it, with a unique
(userId, menuItemId)constraint preventing duplicates.
Security & Deployment
Zod validates every request body (email format, password strength, enum values, numeric ranges, length limits, and custom refinements). Helmet sets security headers, CORS uses an origin whitelist, and critical endpoints are rate-limited (login and reviews 5 per 15 min, orders 10 per 15 min). bcrypt hashes passwords with constant-time comparison.
Deployed on an AWS EC2 t2.micro (Ubuntu 22.04) with a static Elastic IP (44.216.9.251), PM2 process management, and Nginx as a reverse proxy. Indexed queries stay under 50ms even at scale; login is intentionally slower due to bcrypt hashing.
Key Takeaways
- The price snapshot pattern is essential for immutable, historically accurate financial records.
- Dual-token JWT gives short-exposure access tokens without constant re-authentication.
- Role scoping must be explicit — always filter CUSTOMER queries by
userIdto prevent data leakage. - A server-side state machine prevents invalid business transitions; strategic indexes prevent performance decay.
Repository: restaurant-api · Live API: 44.216.9.251/api · Course: Web Programming, Hasanuddin University, 2025
Project Metrics
7 normalized database models with 14 indexed fields for query optimization
30+ REST endpoints with role-based authorization (CUSTOMER, STAFF, ADMIN)
JWT dual-token system: 15-minute access tokens + 7-day refresh tokens
Zod schema validation on all input with 20+ custom validation rules
6-state order workflow state machine (PENDING → COMPLETED/CANCELLED)
Rate limiting on critical endpoints: 5-10 requests per 15 minutes
Deployed on AWS EC2 t2.micro with Elastic IP (44.216.9.251)
Automated table status updates based on order lifecycle events
Project Tags
Related Projects
View all projects →
Urban Complaint Pattern Mining on NYC 311 Data (21M+ Records)
Data mining of 21.3M NYC 311 requests that found a six-complaint building 'syndrome' (mean lift 8.48) and validated it against 11M inspection records: 12-44x higher violation rates.
ICONNET Finance Dashboard
Next.js 16 · React 19 · TypeScript
ICONNET Finance Dashboard - OPEX, Cash Advance & Contract Monitoring
Internal finance dashboard for PLN Icon Plus that replaced spreadsheet-based reporting with four modules (OPEX monitoring, cash-advance tracking, outsourced-staff contract budgets, and vehicle monitoring) on a Next.js + Express + PostgreSQL stack, hardened after a full penetration test.

Medical Anamnesis Chatbot with NLP (Chatbot PUSTU)
Indonesian medical anamnesis chatbot for Puskesmas reaching 92.61% intent accuracy across 14 classes, trained on 14,000 samples generated with Gemini 2.0 Flash and a custom preprocessing and NER pipeline built from scratch.
