spans_next was using departure > viewDate (today), which made any 1-night
booking extend the card to the right. Fixed to departure > tomorrow so the
card only extends when it's also active tomorrow.
Night counter used Date.parse() on NewBook datetime strings, which browsers
parse as local time and shift off by hours in BST. Replaced with utcDay()
which slices the YYYY-MM-DD prefix and calls Date.UTC() — always correct.
When multiple bookings overlap today, prefer the one arriving today so an
arriving guest takes priority over a stale stopover. Also treat a co-active
non-arriving booking as the B2B departing context.
Force previous-day bracket to show as "departed" (purple) when that booking
departs today, without waiting for NewBook to update its status field.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Resolve NewBook category fields from site_category_id, category_id, or
category.id (whichever is present) so categories work regardless of which
naming convention the NewBook region uses. Log the first site's keys on
each /api/rooms request to confirm field names in docker compose logs.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace CSS grid with the original plugin's vertical list + 23px margin
bracket system. Each card has a 2px border coloured by booking status;
data-previous-status / data-next-status drive C-bracket pseudo-elements in
the 23px gutter; data-spans-previous/next remove the corresponding border
and collapse the margin to extend the card across days.
Card interior is restructured: header row (room number, flow badge, lock,
nights counter, site-status pill), guest info row, and stats row (time
pill, bed-type pill, task-status bordered pill). Category headers now match
the original's sticky bordered style with edge-extending pseudo-elements.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NewBook returns 412 if task_type is absent. The original dailylist plugin
always passes [-1] as a fallback when no specific types are configured.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
nginx alias + try_files resolves paths incorrectly (nginx trac #97), so
asset requests fell through to the SPA fallback and index.html was served
as the JS bundle — the app never booted. Match the proven twin-optimiser
pattern: copy dist to html/room-planner and use root with try_files.
Also node:20 → node:22 per stack convention.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The auth /verify endpoint returns { user_id, name, email, is_admin, caps }
directly, not wrapped in a user key, so data.user was undefined and the
gate never rendered. Also: caps come back as bare slugs when ?app= is
passed, so the prefixed room-planner:cap checks always failed — replaced
with the standard can(user, cap) helper honouring is_admin.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Without /room-planner/api/auth/ → 10.10.10.101, auth verify hits the
app backend instead of the central auth service, causing infinite loading.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
NewBook-connected daily housekeeping planner. Replaces the hotelhubmodule-housekeeping-dailylist
WordPress plugin. LXC 120 · 10.10.10.120:3080 · slug: room-planner.
- 3-day booking window (yesterday/today/tomorrow) fetched live from NewBook
- Task completion ticks back to NewBook; room status patches NewBook directly
- 23px border sliver CSS system for adjacent-day booking status
- 3-state filter cycling (off→inclusive→exclusive) for categories and flow types
- Stat filters for outstanding tasks and clean/dirty status
- Rolling 48h activity log with checkout/checkin/status/tasks events
- newbook_pings event bus for future NewBook poller integration
- Room modal with permission-gated guest/rate/notes, task checkboxes, status buttons
- Placeholder sections for future linen-count and routine-tasks modules
- Settings page: task type colours, twin/extra-bed detection, category exclusions
- Mobile-first layout (sidebar desktop, compact top bar mobile)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>