Full-stack restaurant platform built for a premium Persian dining brand. This monorepo combines a public website, reservation and event ticketing flows, an internal admin dashboard, and the backend services needed to operate them.
Portfolio demo: Saffron Table is a fictional brand. Names, contacts, domains, locations, credentials, and seed records in this repository are placeholders and do not represent a real business or customer.
- Repository: github.com/arshial/saffron-table
- Live deployment: intentionally not published; production domains and credentials are placeholders
- Main applications: public restaurant experience, operations dashboard, and LAN print agent
- It covers both customer-facing UX and back-office operations in one system.
- It includes real business flows: reservations, event purchases, payment confirmation, QR ticket delivery, and check-in.
- It is built with production-minded concerns in mind: authentication, role-based access, rate limiting, audit logs, migrations, and automated tests.
- Signed QR tickets with server-side validation and check-in tracking
- Stripe payment flow with webhook support for reliable confirmation
- Admin dashboard for menu, reservations, events, orders, tickets, customers, and settings
- Reservation slot and capacity rules backed by server validation
- Dockerized local setup with PostgreSQL, Flyway migrations, and Nginx
- Backend and frontend test coverage for key application flows
- Home page with brand storytelling, contact information, and discovery content
- Bilingual menu and content structure
- Reservation booking flow with consent handling and slot validation
- Events listing and detail pages
- Ticket purchase flow with QR code delivery after successful payment
- Secure login for
ADMINandSTAFFroles - Dashboard with operational KPIs
- CRUD workflows for menu, events, reservations, and customers
- Order and ticket management, including resend flows
- Ticket scanner and manual check-in tools for on-site staff
- Spring Boot API with JWT-based auth
- PostgreSQL database managed with Flyway migrations
- Stripe integration for payments
- SMTP integration for transactional email
- Nginx reverse proxy and Docker Compose orchestration
Angular frontend -> Spring Boot API -> PostgreSQL
|-> Stripe
|-> SMTP provider
|-> HTTPS print-job queue -> Local Print Agent -> ESC/POS TCP 9100
|-> Nginx reverse proxy
- Frontend: Angular 17, TypeScript, Angular Router, standalone components
- Backend: Spring Boot 3, Java 21, Spring JDBC, JWT
- Database: PostgreSQL, Flyway
- Infra: Docker Compose, Nginx
- Testing: JUnit, Spring integration tests, Angular/Karma
/frontendcustomer site and admin interface/backendAPI, business logic, auth, migrations, and backend tests/backend/src/main/resources/db/migrationFlyway SQL migrations/print-agentJava 21 application that runs inside the restaurant LAN/nginxreverse proxy configuration/docker-compose.ymllocal orchestration/docker-compose.prod.ymlproduction-style overlay/.env.exampleenvironment template
- Clone the repository:
git clone https://github.com/arshial/saffron-table.git
cd saffron-table- Create local environment files:
cp .env.example .env
cp backend/.env.example backend/.env- Generate strong secrets for
JWT_SECRETandTICKET_TOKEN_SECRET:
openssl rand -hex 48
openssl rand -hex 48- Start the stack:
docker compose up --build- Open the app at
http://localhost.
- Copy the same environment files and generate the required secrets.
- Start PostgreSQL.
- Run database migrations:
docker compose run --rm flyway- Start the backend:
cd backend
mvn spring-boot:run- Start the frontend:
cd frontend
npm install
npm start- Open:
- Public site:
http://localhost:5173 - Admin login:
http://localhost:5173/admin/login
Optional seed users are controlled through environment variables and are disabled by default.
Run backend tests:
mvn -q -f backend/pom.xml testRun frontend tests:
cd frontend
npm testThe production backend never connects to private printer addresses. Orders and ESC/POS payloads are stored as durable PostgreSQL jobs; an authenticated agent inside the restaurant polls them over HTTPS and opens the local TCP connection on port 9100.
- In the admin area, open Gestione stampanti and create a Print Agent.
- Copy the API key shown once.
- Build and install the application in
print-agent. - Assign each configured printer to that agent and enable automatic printing.
The dashboard reports agent heartbeat, printer connectivity, queue size, last print, and the latest error. See print-agent/README.md for Windows, macOS, and Linux installation details.
.envandbackend/.envare local-only files and should remain untracked.- Commit only templates, mocks, and sanitized fixtures.
- Never commit credentials, provider keys, certificates, customer data, exports, or screenshots containing personal data.
- If a secret is exposed, rotate it immediately at the provider and remove it from Git history if it was pushed.
- For production, prefer platform-managed environment variables or a dedicated secret manager.
- JWT auth for admin endpoints
- Role-based access for
ADMINandSTAFF - Per-IP rate limiting on sensitive and public form endpoints
- Validation at both controller and service layers
- Audit trail for ticket validation and check-in actions
- HTTPS required for production deployments
- Configure
BASE_URL,CORS_ORIGIN, database credentials, SMTP settings, and Stripe keys through environment variables. - Keep production secrets outside the repository.
- Use the production compose overlay only with production-safe secrets and TLS configuration.
This project demonstrates end-to-end product engineering rather than a single isolated feature: customer UX, operational tools, payments, email delivery, security, database evolution, deployment, and local hardware integration are designed as one system.
