What we solved
Physical keys and magstripe cards are the operational failure point of a hotel. They get lost, shared, demagnetised; re-issues pull a manager off the floor. Staff access is worse - housekeepers and maintenance carry master cards with no audit trail, and revoking access means collecting plastic. JustKeyLess replaces the whole stack: guest keys activate at check-in and revoke at check-out; staff keys bind to rooms or amenity zones for a defined window; the front desk gets time back.
The system at a glance
Three coordinated surfaces, one codebase. A web/iPad dashboard for hoteliers (branches, floors, rooms, amenities, staff, bookings); a mobile app for guests and staff to unlock rooms via BLE; a FastAPI + SQL Server backend tying it all together. BLE locks authenticate against tokens issued by the backend - no account handoff, no physical key to revoke.
What the user experiences
Guests
- Book a room. On check-in, the phone gets a time-boxed key.
- Walk to the room. Tap the app. The lock opens. Ten seconds later it re-locks.
- At check-out, the key expires automatically.
Staff
- Housekeeping opens the rooms on their shift list. No master card.
- Maintenance gets keyed to a specific room for the window of the ticket.
- Emergency keys exist but every use is logged with time, lock, and staff ID.
Hoteliers
- Log in on iPad or web. See every branch’s occupancy.
- Drag-and-drop booking calendar: rooms on the Y axis, infinite-scroll dates on the X. Double-tap to add; long-press to cancel; drag to extend or upgrade.
- Lock battery levels visible at a glance; low-battery alerts route to maintenance.
- Manage branches, assign managers per-location, onboard staff by role.
How we built the pieces
One codebase, three form factors
Phone, iPad, and desktop each get their own layout - not a stretched phone UI. Flutter 3.7 renders distinct responsive layouts from shared business logic. A feature shipped once shows up correctly on all three.
BLE - auth, not broadcast
The app does not “broadcast a key.” It presents a short-lived token during a BLE handshake with the lock. The lock validates with the backend (or cache if offline for a brief window), opens for exactly 10 seconds, and logs the unlock. Two failed auths in a row raise an alert.
We use flutter_blue_plus with our own patches on top - production BLE on a hotel floor with dozens of locks and dozens of guests needed reconnection and caching behaviour the plugin didn’t ship with out of the box.
Backend - FastAPI + SQL Server
A hotel booking system is fundamentally relational: branches, rooms, bookings, guests, staff, access events. SQL Server holds the schema with transactional integrity; FastAPI exposes typed endpoints with Pydantic models. Audit trails land in an append-only events table - every unlock, every key grant, every revoke - queryable for the operator.
The calendar - hand-built, not off-the-shelf
Off-the-shelf calendar widgets choke at hotel scale (50 rooms × 365 days). We built a custom infinite-scroll grid: rooms as rows, dates as columns, virtualised rendering. Double-tap, long-press, and drag interactions mirror desk-manager muscle memory.
Real-time ops feed
Bookings, check-ins, check-outs, and battery events stream to the dashboard without a refresh. Managers see the state of the floor in real time.
Multi-branch by default
A hotelier with three properties manages all three from one login. Branch managers get scoped access to their property. Audit trails roll up to the hotelier.
The hardware-software loop, end to door
Hotels run on a hardware-software loop. Building the app without the lock integration is demo-ware; building the lock firmware without the operations UI is a lab experiment. JustKeyLess is the whole loop: the firmware layer (BLE auth), the operator UI (drag-and-drop calendar), the guest surface (tap to unlock), and the audit trail that lets the property close the month.
Results
- Three device-class UIs (phone, iPad, desktop) from one Flutter codebase.
- BLE locks respond under a second to key-grant / key-revoke events from the backend.
- Custom infinite-scroll calendar rendering 50+ rooms without jank.
- Multi-branch deployment with assignable managers.
- FastAPI + SQL Server backend with append-only audit trail.
What an engineering team should take from this
If you are shipping operations software that spans phone, tablet, and desktop:
- Design per form factor, not stretched layouts. Flutter makes this cheap; skipping it makes the UI worse on every device.
- BLE is auth, not broadcast. Tokens expire, handshakes log, offline grace windows have limits. Expect to patch your BLE plugin - production hardware loops rarely ship perfect.
- Hand-build calendars if scale demands it. Off-the-shelf options will run out of road faster than you expect.
Tech stack
- Mobile + iPad + web admin: Flutter 3.7 (single codebase, distinct layouts per form factor)
- Backend: FastAPI (Python, typed)
- Database: SQL Server
- Hardware: BLE locks;
flutter_blue_pluswith custom patches - Auth: OTP mobile verification, JWT tokens
- Real-time: push notifications on mobile, WebSocket for web dashboard
- Payments: gateway for on-property charges (provider undisclosed)
Screens
