Request a table
The public form validates event and seating choices before creating a UUID-tracked pending reservation.
FiredOrder up · service night
Guests fire the request, the system stamps it, staff work the rail, and a token-secured API plates the data downstream.
This split shaped the whole system: public intent first, protected operations second.
The brief
A reservation platform serves two very different rooms. Guests want a seat with zero friction. Staff want control, filters, and a record of every call. The job was to let both work the same ticket without handing the wrong controls to the wrong person.
Browse events and seatings, request a table, and get a confirmation code. No account, no friction.
Sign in, filter the queue by event and status, assign a table, then approve or deny. Every call is logged.
Palette
Flavor da Casa had to feel like a warm, family-run dining room, not a cold booking tool. The palette is built from kitchen and dining-room materials: cinnamon wood and coffee bean for warmth, soft apricot for candlelight glow, and a deep blue-grey set against them for grounded, legible headings. The warm tones invite; the cool blue-grey keeps the interface calm and readable through a busy service.
Service choreography
Every reservation runs the same line: a guest fires the request, the system stamps a confirmation, staff work the queue and assign a table, and a secured API plates the data for anyone downstream.
The public form validates event and seating choices before creating a UUID-tracked pending reservation.
FiredEmailService sends the guest a formatted confirmation with event, seating time, and confirmation code.
SentThe dashboard narrows reservations by event and status so staff can work the next service window.
QueuedAuthenticated users review full guest details and attach a valid dining table before approval.
PlatedThe separate REST app uses bearer tokens and OpenAPI docs for third-party access.
ServedGuest surface
The guest flow keeps attention on event, seating, and contact details. It behaves like a host stand: collect the request, confirm the code, then move the ticket into the queue.
Staff surface
Staff do not need every record at once. They need the next decision. Event and status filters turn the reservation list into a working queue.
Security surface
The login screen marks the boundary between public browsing and operational authority. That boundary matters because approvals change the guest experience.
Integration surface
Swagger turns the backend into something reviewable. The API is secured with JWT bearer tokens and separated from the Thymeleaf web app.
Architecture
Clients hit the runnable apps, the apps call the domain modules, every module stands on the shared foundation, and persistence and mail sit at the edges. Dependencies flow down.
01 Clients
02 Delivery apps
03 Domain modules
04 Shared foundation
05 Persistence
Built for service
Maven multi-module project with shared common libraries. Each module (restaurant, auth, common) has its own Domain, Application, Infrastructure, and Presentation layers with strict dependency inversion.
Separate modulesCustom ValidationService pattern per entity with Result/ValidatedResult wrapper types, field-level error binding to BindingResult, and dedicated validation services for Events, Seatings, Menus, MenuItems, DiningTables, and Reservations.
Field-level feedbackSeating CRUD with table assignments (many-to-many via SeatingTableEntity), capacity tracking, overlapping seating conflict detection, and cascade delete management.
Capacity logicInitializeDataServiceImpl seeds the database with default dining tables, events, seatings, menus, and menu items on first startup, enabling immediate demo readiness.
Demo-ready seed data