The status model is the product; the software is just how you look at it. A housekeeping board is a live grid of every room's state (vacant clean, vacant dirty, occupied, inspected, out of order), an assignment engine that splits the day's cleans fairly across attendants, an inspection queue for supervisors, and a discrepancy check against the front office. Define those four things precisely and any stack works: a spreadsheet to about 40 rooms, Airtable to a mid-size property, a small web app beyond that. With an AI coding agent and the reference schema linked below, a working phase one is a week of evenings, not a software project.
Every hotel already has a housekeeping board. At smaller properties it is a whiteboard behind the front desk or a printed sheet on a clipboard; at larger ones it is a module inside the PMS that housekeeping tolerates rather than likes. This guide is for the ops leader who wants to build their own: a purpose-built internal tool that shows room status live, assigns fairly, enforces the inspection pass, and reconciles against the front office twice a day. It is the hotel sibling of our vacation rental ops platform build guide, and like that guide it assumes you are directing an AI coding agent rather than writing every line yourself. Our open source PMS research found plenty of self-hosted PMS projects but almost nothing purpose-built for the housekeeping layer, which is exactly why this is worth building internally.
One scoping rule before anything else: you are building the housekeeping layer, not a PMS. Reservations, rates, folios, and check-ins stay where they are. Your board consumes occupancy from the PMS and owns exactly one thing: the cleanliness state of each room and the work that changes it.
The room-status model comes first
A room's status on a housekeeping board is really two independent facts stapled together. Occupancy (vacant or occupied) is owned by the front office, because it follows from check-ins and check-outs. Cleanliness (dirty, clean, inspected) is owned by housekeeping, because only someone standing in the room can know it. The classic two-letter codes are just the cross product, plus two maintenance states that sit outside the grid:
| Code | Meaning | Set by | What it tells the desk |
|---|---|---|---|
| VD | Vacant dirty | Front office + Housekeeping | Guest left; room needs a checkout clean before it can sell. |
| VC | Vacant clean | Housekeeping | Cleaned, awaiting inspection. Not yet sellable if you run an inspection step. |
| VI | Vacant inspected | Supervisor | Verified guest-ready. This is the status the front desk actually sells. |
| OD | Occupied dirty | Front office + Housekeeping | Stayover awaiting service today. |
| OC | Occupied clean | Housekeeping | Stayover serviced; nothing more needed until checkout. |
| OOO | Out of order | Management | Removed from sellable inventory entirely. Occupancy math excludes it. |
| OOS | Out of service | Management | Blocked for a minor fault but still in inventory; sellable if the house fills. |
The OOO and OOS distinction is not pedantry; it changes tonight's capacity. According to Oracle's OPERA Cloud documentation (oracle.com), out of order rooms are removed from inventory availability entirely, while out of service rooms remain in inventory and available to assign. A renovation floor is OOO. A room waiting on a lamp part is OOS. Your board needs both, because a sold-out night with three OOS rooms is a very different problem from one with three OOO rooms.
The same OPERA documentation defines the two discrepancy types your PM check exists to catch. A skip is a room the front office shows as occupied but housekeeping reports vacant. A sleep is the reverse: the front office shows vacant, but housekeeping reports it occupied, luggage in the room being the classic evidence. Oracle's guidance is that the front office resolves discrepancies by checking a reservation in or out; your board's job is to surface the mismatch the same afternoon it appears, because a skip is often an unrecorded departure (or a walked guest) and a sleep can be an unregistered occupant.
Here is the screen you are building. One glance answers the three questions a desk agent, a supervisor, and an executive housekeeper are all asking: what can I sell, what is still in progress, and where are the problems.
The board view: rooms grouped by floor, colored by status, with the assigned attendant and credit value on each pending clean. The header counts are the whole dashboard most days.
The build, from scoping to daily use
The board lives inside a daily rhythm, and the build order below follows it: each step ships something the next one depends on, and each is independently useful the day it lands.
The daily loop your board serves. If a step has no screen in your tool, that step is happening on paper or not at all.
Define the status model on paper
Before any software: write down your statuses, who may set each, and the legal transitions. VD to VC is an attendant action. VC to VI is a supervisor action only. VI back to VD happens at the next checkout, automatically. If you skip the inspected status because you run lean, decide that now and delete it everywhere, but decide deliberately: the VC to VI gate is where quality is enforced, and it is the one status a guest never sees but always feels.
Field note: resist inventing extra statuses ("deep clean pending", "manager hold"). Every status you add is a color your team must learn and a transition matrix that doubles. Flags and notes on a room handle the exotic cases; statuses handle the daily loop.
Pick the stack for the size you actually are
The status model transfers unchanged across all three of these, so start cheap and migrate when it hurts:
Shared spreadsheet
To ~40 roomsOne row per room, a status column with conditional formatting, a morning paste from the night audit report. Free, live in an hour, understood by everyone.
Breaks when: attendants need to update from phones mid-shift, or you need a trustworthy history of who changed what.
Airtable / Notion
Mid-size propertyRooms as records, a kanban or grid view by status, per-person views for attendants, form-based inspection checklists, an activity log for free.
Breaks when: you need real role permissions, sub-minute updates on a busy checkout day, or PMS API sync beyond CSV imports.
Small web app
No practical ceilingA database, one board screen, one assignment screen, one inspection queue. This is what the AI-agent prompt below builds, on the reference schema.
Breaks when: nobody owns it. An internal tool needs one named owner or it quietly dies at the first schema change.
Build the board view, on events
The screen above is deliberately boring: rooms by floor, colored by status, attendant and credits on pending work, counts in the header. The non-negotiable is underneath: every status change is an event (room, from-status, to-status, who, when), never an overwrite. The current board is just the latest event per room. This one decision gives you the end-of-day timeline ("who set 305 to clean, and when?"), attendant productivity reporting, and dispute evidence for free. It costs nothing extra to build on day one and is nearly impossible to retrofit after a month of overwrites.
Assign by credits, not room counts
Splitting 96 cleans across 8 attendants as "12 rooms each" feels fair and is not, because rooms are not equal work. The industry's answer is the credit system. According to Optii Solutions (optiisolutions.com), a housekeeping technology vendor, credits estimate the time a given clean takes, with each room type and clean type (departure, stayover, turndown) carrying its own value; some hotels value a credit at one minute, others at 15 or 30 minute increments, and departure cleans carry more credits than stayovers.
The gap between clean types is bigger than most first-time builders assume. A time and motion study reported by Hotel Management (2016) observed 60 suite cleans at one property, 30 checkouts and 30 stayovers: checkout cleans averaged 43 minutes against 23 minutes for stayovers, and on heavy checkout days attendants' time-based workload rose by as much as 80 percent even when their room count stayed flat. That hotel's fix was exactly the credit move: checkout cleans were set to twice the credits of a stayover, and daily quotas balanced on credits.
Workload caps are also increasingly a legal fact, not a policy choice. The City of Los Angeles Hotel Worker Protection Ordinance (2022) prohibits requiring a room attendant in a hotel with 60 or more rooms to clean more than 3,500 square feet of floor space in an eight-hour workday unless the hotel pays double the regular rate for every hour worked that day, with the cap reduced further for special-attention rooms. If you operate in a jurisdiction with such an ordinance, your assignment logic must track square footage per attendant per day, which means square footage belongs on the room record in your schema from the start.
The assignment algorithm itself is simple enough that your agent will get it right in one pass: sort the day's tasks by credits descending, then repeatedly hand the next task to the attendant with the lowest running total, respecting floor groupings so nobody rides the elevator all day.
Build the inspection pass as a real workflow
The supervisor pass is the difference between a status board and a quality system. Model it explicitly: when an attendant sets a room to VC, it enters the inspection queue. A supervisor either passes it (VC to VI, room becomes sellable) or fails it, which reverts the room to VD with a reason code and puts it back on the original attendant's list. Fail reasons are the most valuable dataset this tool will ever produce: three weeks of them tells you which rooms, which attendants, and which checklist items drive rework, which is coaching material no meeting will surface.
Anything the inspection finds that cleaning cannot fix (a burned-out fixture, chipped tile, a stained chair) becomes a work order, not a hallway conversation. That is one more table and a status field, and it is the difference between maintenance issues that get fixed and maintenance issues that get re-discovered by the next three inspectors. Photo documentation of what the inspector saw belongs on both the failed inspection and the work order; it settles the "it was already like that" conversation before it starts.
Field note: at scale, the inspection pass is also the layer where AI earns its keep. If your inspectors photograph rooms anyway, tools like RapidEye review those photos against each room's baseline and flag damage and misses a rushed human walkthrough skips. Build the workflow first; the photos it produces get more valuable, not less.
Connect the PMS at whatever level it honestly allows
Your board needs two things from the PMS: today's occupancy movements in (arrivals, departures, stayovers) and, ideally, cleanliness status back out so the desk sees it in the system they live in. There are three honest tiers:
- Manual, always available. The night audit produces an arrivals and departures report in every PMS ever made. Export or retype it into the board each morning; ten minutes, zero integration risk. Every board should be able to run this way, because it is also your fallback when an API breaks.
- CSV or scheduled export. Most PMSs can email or drop a scheduled report. A tiny parser turns that into the morning status roll automatically. This is the workhorse tier for independent properties.
- API, where the PMS is open. The cloud PMS generation genuinely supports this. Mews' Connector API documents housekeeping as a first-class use case: pull resource states, push clean or inspected states back, and subscribe to changes over webhooks or WebSockets instead of polling; Mews will even auto-mark vacant spaces dirty after a property-configured interval of up to 7 days. Cloudbeds' developer documentation likewise exposes getHousekeepingStatus and postHousekeepingStatus to read and write room condition and postHousekeepingAssignment to assign rooms to housekeepers. On legacy or closed systems, assume tier two and be pleasantly surprised.
Whichever tier you land on, the direction rule from the STR guide holds unchanged: the PMS owns occupancy, your board owns cleanliness, and each system syncs the other's fact read-only. Two systems both writing occupancy will disagree within a week, and the PMS is the one connected to reality.
This tier is also where the afternoon discrepancy check becomes a screen instead of a ritual: join housekeeping's reported occupancy against the PMS's, and every mismatch is a skip or a sleep for the front office to chase before the evening arrivals land.
Roll it out like an operator, not a developer
The board fails socially before it fails technically. Three rules that keep it alive: run the old paper or whiteboard process in parallel for two weeks and let the digital board win on merit; train supervisors first, because if the inspection queue works, attendants adopt the rest to feed it; and keep the attendant interaction to two taps (open my list, mark room clean). Every extra field you ask a room attendant to fill at the door of room 14 of 14 is a field that will be filled with fiction.
Measure adoption by one number: the gap between when a room was actually finished and when its status changed. If that gap is under ten minutes by week three, the board is real. If it is an hour, people are batch-updating from the break room and the "live" board is a diary.
The AI-agent build prompt
If you are going the small-web-app route, do not let the agent invent a schema on the fly; it will model whatever your first message happened to mention. We publish a hotel operations reference schema for exactly this: rooms, statuses, housekeeping tasks and assignments, inspections, and work orders, as downloadable SQL. Hand it to the agent and scope phase one tightly:
Build an internal housekeeping board for my hotel.
First, fetch and read the reference data model:
https://rapideyeinspections.com/blog/hotel-operations-data-model/schema.sql
Use it as the database schema. Keep at minimum the room, room_status_log,
hk_task, hk_assignment, inspection, and work_order tables; drop
anything we do not need yet.
Constraints:
- The PMS stays the system of record for occupancy. This board owns
cleanliness only (dirty / clean / inspected) plus OOO and OOS blocks.
- Room status changes are append-only events (room, from, to, who,
when), never overwrites. The board renders the latest event per room.
- Assignment balances credits, not room counts. Each room type and
clean type (checkout, stayover) has a configurable credit value;
default checkout = 2x stayover. Store square footage per room so
per-attendant daily totals can be reported.
- Inspected is a separate status only a supervisor role can set.
A failed inspection reverts the room to dirty with a reason code
and creates a work_order if the failure is a maintenance issue.
- OOO rooms leave the cleanable count; OOS rooms stay visible flagged.
Phase 1 only: the live board grid (rooms by floor, colored by
status), a morning assignment screen that balances credits across
attendants, two-tap status updates for attendants on mobile, and an
inspection queue for supervisors. No PMS API integration yet; I will
import the arrivals and departures list as CSV each morning. Ask me
for my room list, room types, square footages, and credit values
before writing code.
Three practices carry over directly from the STR build guide and matter just as much here: phase the build and live with each phase for a week before extending it; put the tool behind real authentication from day one, since it holds staff accounts and room-level operational detail; and keep every imported PMS report in an append-only inbox table so a sync bug three weeks in is replayable instead of a mystery.
Quick FAQ
What do the room status codes VC, VD, VI, OC, OD, OOO, and OOS mean?
They combine occupancy and cleanliness: VC is vacant clean, VD is vacant dirty, VI is vacant inspected (ready to sell), OC is occupied clean, OD is occupied dirty, OOO is out of order (removed from sellable inventory), and OOS is out of service (blocked for a minor issue but still sellable). Occupancy is owned by the front office; cleanliness is owned by housekeeping. A room is only guest-ready when both agree.
How much longer does a checkout clean take than a stayover clean?
Roughly twice as long. A time and motion study reported by Hotel Management in 2016 observed 60 suite cleans (30 checkouts, 30 stayovers) and found checkout cleans averaged 43 minutes against 23 minutes for stayovers. That is why credit systems typically weight a checkout clean at about double a stayover clean, and why balancing raw room counts across attendants produces unfair days.
Can I run a hotel housekeeping board in a spreadsheet?
Yes, up to roughly 40 rooms and one supervisor. A shared sheet with one row per room, conditional formatting for status colors, and a morning paste from the night audit report is a real board. It breaks when you need concurrent phone updates from attendants, role permissions, or a trustworthy history of who changed what and when. At that point move to Airtable or a small web app; the status model transfers unchanged.
What is the difference between out of order and out of service?
Out of order (OOO) removes the room from sellable inventory entirely, so occupancy percentages are calculated without it; it is used for renovations or rooms that genuinely cannot be sold. Out of service (OOS) blocks the room for a minor issue, such as a lamp waiting on a part, but keeps it in inventory and available to assign if the house fills. Oracle's OPERA Cloud documentation draws exactly this line, and your board should too, because the two statuses answer different questions about tonight's capacity.
Sources
Sources are named at the publisher level with their root domain, rather than linked or titled; every figure is verifiable at the named source.
- Optii Solutions help center, housekeeping credit systemsoptiisolutions.com
- Hotel Management, housekeeping productivity coverage, 2016hotelmanagement.net
- Hotel Worker Protection Ordinance, City of Los Angeles Municipal Code, 2022lacity.org
- OPERA Cloud housekeeping and discrepancy documentation, Oracle Hospitalityoracle.com
- Mews Connector API documentation, housekeepingmews.com
- Cloudbeds API documentation, housekeepingcloudbeds.com

