Guesperia ORMS
01 — The brief
Guesperia ORMS — an Order & Request Management System for hotels — replaces the phone calls and paper chits guests use to ask for towels, a technician, or anything else. A guest scans a QR in their room, submits a request, and it lands with the right department. Staff work a live queue; managers see whether the hotel is hitting its service targets.
Two things made it more than a to-do list. Requests are governed by SLAs — every one has a deadline the system, not a person, computes and enforces. And it is multi-tenant from the first table: several hotels share one deployment, and no request, guest or metric may ever leak across a tenant boundary.
02 — Approach
The backend is a Spring Boot service in a hexagonal, ports-and-adapters shape: a framework-free domain at the centre, use cases and ports around it, and adapters — persistence, Redis messaging, SSE, SLA, Clerk, email, QR — at the edge. Multi-tenancy is enforced at three layers at once: a request-scoped tenant context, a Hibernate filter on every query, and a database CHECK that a tenant id is never null.
The SLA clock is the heart of it. Deadlines are computed on the server, and a scheduled ticker — guarded by ShedLock so only one instance runs it across the cluster — sweeps open requests every fifteen to thirty seconds, crossing five-, two- and zero-minute thresholds and raising escalations. Real-time updates ride Redis pub/sub out to two separate SSE channels: a guest stream scoped to their own submission, and a department-scoped staff stream — and the DTO boundary guarantees a guest is never sent SLA data meant for staff.
- Core Java 21 · Spring Boot · hexagonal ports & adapters
- Tenancy TenantContext + Hibernate @Filter + NOT NULL tenant CHECK
- SLA engine Server deadlines · ShedLock ticker (15–30s) · threshold escalations
- Real-time Redis pub/sub → separate guest & staff SSE streams
- Auth Clerk org auth · JWT resource server · app-layer PermissionService
- Frontend Next.js 16 · React 19 · next-intl (tr/en) · Turborepo
None of this was free. Each choice bought something and charged for it somewhere else — the work was in choosing where to pay.
-
Trade-off 01
Hexagonal core over a framework-coupled service
Keeping the domain free of Spring means the request and SLA rules can be tested and reasoned about without a database or a web server — the core compiles with zero framework on the classpath. The cost is more moving parts: ports, adapters and mappers that a straight layered service would not need.
-
Trade-off 02
Server-authoritative SLA over client timers
Deadlines and threshold crossings are computed on the server and swept by one lock-guarded ticker, so every device shows the same clock and nothing depends on a phone being awake. The cost is a scheduled job that must be tenant-scoped, idempotent and safe to run on exactly one node — which is what ShedLock buys.
-
Trade-off 03
Two SSE channels over one shared stream
Guests and staff get separate real-time streams, and the DTO boundary means SLA and internal data can never reach a guest by accident. The cost is maintaining two channels and two projections of the same event instead of broadcasting one.
-
Trade-off 04
Multi-tenant from day one over retrofitting later
Enforcing tenant isolation in the context, the ORM filter and a database constraint at once makes a cross-tenant leak a hard error, not a code-review hope. The cost is that every query, migration and test has to carry the tenant dimension from the very start.
The clock belongs to the server — every screen only reads it.
03 — Results
Guesperia’s backend is feature-complete for its MVP — the guest and staff flows, the SLA engine, escalations, reports and Clerk-based access all pass a suite of ninety-plus tests across sixteen migrations. It runs multi-tenant for a two-hotel pilot, with the Next.js guest and staff apps coming up behind it.
04 — What’s next
The backend is ahead of the clients, so the near-term work is finishing the guest and staff web apps, wiring the Clerk webhook and a real email provider in production, and hardening the platform for more than the pilot’s two hotels.