Real-time bed & housekeeping operations for hostels — with a local-AI ops layer.
A multi-property platform that runs the daily housekeeping operation of a hostel: a mobile app for cleaners on the floor, a live reception board, a manager analytics dashboard, a maintenance ticket system, and an AI ops copilot — all over a multi-tenant data model that syncs two-way with the Cloudbeds PMS.
The AI runs on a local Ollama model — free, private, no external API, no keys — and degrades gracefully to deterministic logic when it's offline, so nothing ever hard-depends on it.
Built with
Next.js 16 (App Router) · TypeScript ·
Tailwind CSS v4 · Supabase (Postgres + Realtime + RLS) ·
Cloudbeds API v1.3 · Ollama
Portfolio project. It runs fully standalone on generated demo data for a fictional hostel chain (“Driftwood Hostels”) —
npm install && npm run dev, no database, no API keys. The Supabase + Cloudbeds integration is real and documented; live mode is opt-in via env. No real PMS data is ever written.
Most housekeeping tools are room-centric. Hostels run on beds — each capsule or bunk is its own unit, with same-day dorm turnover, continuous (long-stay) guests that shouldn't be re-cleaned, and female/mixed/private dorm rules. BunkBoard is built bed-first, and layers on the workflows real products ship (inspection QA, maintenance tickets, credit-based assignment, productivity analytics) — plus an AI layer that reasons over the live board instead of bolting on a generic chatbot.
The feature set is grounded in how leading housekeeping/PMS tools actually work (Flexkeeping, Sweeply, Optii, hotelkit, Cloudbeds Housekeeping).
Mobile-first, built for speed and one-handed use. Priority-sorted beds, predicted clean times, dorm-type badges, the four muscle-memory actions (Ext / Flag / NS / Done) with a two-tap guard on the destructive one, per-bed notes that turn into maintenance tickets, and an AI cleaning order that explains how to attack the shift.
Read-only, at-a-glance bed state for the front desk — who cleaned what and when, clean/dirty/ready, KPI strip, an AI shift briefing, and a manager inspection (pass / re-clean) QA loop.
Completion %, average clean time, occupancy-based staffing forecast, a per-cleaner productivity leaderboard with one-click credit-based load balancing, clean-time anomaly detection, and an open-issue feed.
Report an issue → AI triage classifies category + severity and suggests an action → it becomes a ticket on an Open / In progress / Resolved board. Blocking issues automatically take the bed out of order until resolved.
Ask the board anything in natural language — “What should we prioritise before the 15:00 check-ins?” — answered from a compact live-board digest, entirely on a local model.
Everything runs on a local Ollama model (llama3.2 by default). Each feature has a
deterministic rule-based fallback, so the product works with AI off too (the
status pill in the nav shows which is active).
| Feature | What it does | Endpoint |
|---|---|---|
| Shift briefing | A duty-manager briefing — priorities, risks, staffing | POST /api/ai/briefing |
| Cleaning order | An explained, priority-ranked plan for the floor | POST /api/ai/prioritize |
| Maintenance triage | Free text → {category, severity, action} (JSON mode) |
POST /api/ai/triage |
| Ops copilot | Q&A grounded in a live-board digest | POST /api/ai/chat |
The board is pre-aggregated into a tight text digest (lib/ai/context.ts)
before it reaches the model — small local models reason far better over the few facts
a question needs than over raw rows.
- Bed-level turnover — full-clean vs stayover-light vs continuous (no re-clean), per bed.
- Predicted clean time — explainable formula: base minutes by unit type × occupancy effort (
lib/ops.ts). - Cleaning priority — combines turnover/arrival signal, cleanliness, and time until check-in.
- Inspection QA —
clean → inspectedon pass;→ dirty / re-cleanon fail. - Credit-based assignment — greedy load balancing (pod = 1, deluxe = 2, DP2 = 3 credits).
- Staffing forecast — remaining predicted work ÷ time to the check-in peak → cleaners needed.
- Anomaly flag — serviced beds that took ≥2× their predicted time.
Cloudbeds (PMS) ──webhooks──▶ sync engine ──▶ Supabase (Postgres)
▲ reservations + housekeeping bed_states / bed_assignments / tickets
│ (source of truth) │ RLS + Realtime
└──── housekeeping write-back ◀── BFF ◀─────────┤
▼
Next.js surfaces ──▶ local Ollama (AI ops layer)
- Multi-tenant from day one — every operational row carries
property_id; per-property isolation via real RLS policies keyed off a minted Realtime token. - Cloudbeds is the source of truth for reservations + guests; this DB owns only bed↔state, timing, housekeeping, tickets, and the sync audit trail (no guest PII).
- One bed == one Cloudbeds
roomID(each capsule/bunk is its own room). - Safe by construction — a Supabase-backed mock Cloudbeds (
/api/mock-cloudbeds) lets the full client → sync → board pipeline run end-to-end against fake data; the dev sync + mock routes 404 on a real Cloudbeds base URL. - Standalone demo — surfaces read/write a single in-memory ops store
(
lib/demo/store.ts) seeded by a deterministic generator, so a change on the housekeeper phone shows up on the reception board and dashboard. The sameOpsSnapshotshape comes from Supabase + Cloudbeds in live mode.
Full design record + the Cloudbeds quirks that shape it: docs/architecture.md.
npm install
npm run dev # http://localhost:3007 — fully working on demo dataThat's it — no database, no API keys. Open / and explore every surface.
# install Ollama from https://ollama.com, then:
ollama pull llama3.2 # ~2 GB, runs locallyWith Ollama running, the AI features produce live output. Without it, they fall back to deterministic logic and the app still works end to end.
Copy .env.example → .env.local and fill Supabase + Cloudbeds keys to swap the
in-memory store for real persistence + PMS sync. See
docs/architecture.md and docs/pseudo-cloudbeds.md.
npm run build && npm run start # terminal 1
npm run shots # terminal 2 → docs/screenshots/*app/
page.tsx portfolio hub
housekeeping/ mobile floor app (priority sort, AI order, report issue)
reception/ live board + KPIs + AI briefing + inspection QA
dashboard/ KPIs, leaderboard, staffing forecast, anomalies
maintenance/ ticket kanban + AI triage + report form
copilot/ natural-language ops chat
api/
ai/ briefing · prioritize · triage · chat · status
board/ tickets/ in-memory store mutations
mock-cloudbeds/ pseudo-PMS for safe end-to-end testing
dev/sync/ dev-only Cloudbeds → bed_states sync trigger
lib/
ops.ts domain: predicted time, priority, tickets, assignment
metrics.ts KPIs, per-cleaner stats, anomalies, staffing forecast
ai/ Ollama client, board digest, AI ops functions (+ fallbacks)
demo/ deterministic generator + in-memory ops store
cloudbeds/ API client, rate limiter, sync engine (live mode)
supabase/ db/ auth/ realtime/ live-mode data + auth + RLS plumbing
supabase/migrations/ multi-tenant schema · RLS + realtime · mock-PMS schema
scripts/ migrate · seed · register-webhooks · screenshots
- Next.js 16 App Router with server components reading the store and client components persisting through small route handlers.
- TypeScript strict, ESLint (flat config) and a clean production build.
- Rate-limited Cloudbeds client (~4 req/s with 429 backoff) and idempotent webhook handling — built around real Cloudbeds API quirks.
- No secrets in the repo; all keys are env-only and gitignored.
BunkBoard is an independent portfolio project and is not affiliated with Cloudbeds or Ollama. All hostels, guests, and PMS IDs in the demo data are fictional.





