Files
gw/scheduling.md
T
ponzischeme89 6d44e05de4 v1
2026-04-18 07:23:55 +12:00

8.9 KiB
Raw Blame History

Scheduling Command Centre

Purpose

The admin bookings experience is a desktop-first scheduling command centre for daily operations. It is designed to help admins triage intake, plan upcoming service delivery, spot capacity constraints, and act on bookings with minimal friction from one screen.

The implementation powers:

  • frontend/src/routes/admin/bookings/+page.svelte
  • frontend/src/lib/admin/bookings/planner.js
  • frontend/src/lib/admin/bookings/BookingMetricsBar.svelte
  • frontend/src/lib/admin/bookings/BookingFilterRail.svelte
  • frontend/src/lib/admin/bookings/BookingPlannerWorkspace.svelte
  • frontend/src/lib/admin/bookings/BookingInspector.svelte
  • frontend/src/lib/admin/bookings/BookingCard.svelte
  • frontend/src/lib/admin/bookings/BookingScheduleView.svelte

Architecture

The route file is the state container.

  • It fetches bookings from GET /api/v1/admin/bookings.
  • It persists edits through PUT /api/v1/admin/bookings/{booking_id}.
  • It owns selection, bulk actions, filters, active booking state, and inspector draft state.
  • It manages three view modes: day, week, and block (schedule grid). Default is block.

The planner helper module is the view-model layer.

  • It parses admin_notes into structured planner metadata.
  • It hydrates raw API bookings into operational bookings with derived fields.
  • It computes operational statuses, metrics, segments, filters, conflicts, and workspace lanes.
  • Hydrated bookings expose dogName and dogBreed (from member.onboarding_data) as primary display fields. The dog name is the primary identifier in all views; client name is the subtitle.

The Svelte components are presentation modules.

  • BookingMetricsBar.svelte: compact single-row header — date navigation, inline stat pills, Day / Week / Schedule toggle, refresh.
  • BookingFilterRail.svelte: horizontal segment tabs + search input + collapsible advanced filters.
  • BookingPlannerWorkspace.svelte: flat list of booking rows grouped by section (pending intake, scheduled, needs attention). Used by Day and Week view modes.
  • BookingInspector.svelte: right-panel detail card showing dog identity, status actions, and editable scheduling fields. Auto-saves on field blur. On mobile, replaces the list as a full-screen view with a back button.
  • BookingCard.svelte: slim two-line list row showing dog name (primary), client name + time (subtitle), service chip, and contextual action buttons.
  • BookingScheduleView.svelte: MonFri week capacity grid (the Schedule / block view). See below.

Layout

Desktop (> 900px)

Two-column layout: scrollable booking list or schedule grid on the left/centre, sticky inspector panel on the right.

Mobile (≤ 900px)

Single column. Tapping a booking opens the inspector full-screen. A back button returns to the list. In Schedule view, a bottom-sheet style overlay appears over the grid when a booking is selected.

Views

Compact header bar

Single row containing:

  • Previous / date label / next navigation arrows (moves by 1 day in Day mode, 7 days in Week and Schedule modes)
  • Inline stat pills (only rendered when non-zero): pending count, unassigned count, conflict count
  • Bulk action buttons when bookings are selected
  • Day / Week / Schedule view toggle
  • Refresh button

Horizontal tab strip: Today · This week · Incoming queue · Needs assignment · Conflicts · Recurring. Counts shown per tab. Search input and collapsible Filter button sit to the right.

Schedule view (default)

BookingScheduleView.svelte renders a MonFri week grid with two session rows per day.

Structure:

  • Column headers: day name, date, and Auckland weather (fetched from Open-Meteo, free, no API key required — coordinates -36.85, 174.77). Displays weather emoji + high/low temperatures (e.g. ☀ 22°/15°).
  • Morning row (AM): all bookings for that day where scheduledFor time is before 12:00, or where time is unset (defaults to morning).
  • Afternoon row (PM): all bookings for that day where scheduledFor time is 12:00 or later.

Capacity:

  • Each session (morning and afternoon) has a maximum capacity of 12 dogs.
  • Each booking chip counts as 1 dog toward the session capacity.
  • Capacity is displayed as n/12 with a coloured progress bar per cell:
    • Grey: 0 dogs
    • Green: 18 (under 75%)
    • Amber: 911 (7599%)
    • Red: 12 (full)

Booking chips:

Each booking is shown as a clickable chip inside the cell. The chip displays:

  • Dog name (primary, bold)
  • Dog breed (abbreviated, if available)
  • Coloured by service type accent colour
  • Active (inspector open): filled with the accent colour
  • Conflict: red border tint

Clicking any chip selects that booking and opens the inspector panel.

Weather fetch: BookingScheduleView calls Open-Meteo on mount with a 14-day forecast window. Failure is silent; cells show when no weather is available. Only future/forecast dates receive weather data.

List workspace (Day and Week modes)

Flat scrollable list of BookingCard rows grouped by section:

  • Pending intake: bookings with status === 'pending'.
  • Scheduled: non-pending bookings in the selected time window.
  • Needs attention: bookings flagged as conflicts or unassigned.

Booking inspector

Right-side sticky panel (desktop) or full-screen overlay (mobile). Shows:

  • Dog name + breed as primary identity, client name as subtitle
  • Status pill + service pill
  • Conflict alert if flagged
  • Requested vs scheduled stat row
  • Quick action buttons: Confirm / Mark done / Cancel (context-aware)
  • Editable scheduling fields: scheduled datetime, route, recurring pattern, priority cue
  • Operational notes textarea
  • Auto-saves on field blur; explicit Save button also available

Data

API fields

The GET /api/v1/admin/bookings response includes:

  • id, member_id, service_type, requested_date, status, notes, admin_notes, created_at
  • Joined member fields: member_first_name, member_last_name, member_email
  • Dog fields (joined from member.onboarding_data): member_dog_name, member_dog_breed

Planner metadata format

Planner-only scheduling fields are stored inside admin_notes to avoid backend schema changes.

Reserved format: ::planner::<json>

Optional freeform notes may follow on the next line.

Structured planner keys:

  • walker — assigned walker name (single-walker operation; field is preserved but not exposed in the UI)
  • route — route or session label (e.g. "Central AM pack")
  • recurring — recurrence description (e.g. "Weekly Tue / Thu")
  • scheduledFor — ISO datetime for the planned session
  • priority — freeform priority cue (e.g. "High touch, trial")

If admin_notes does not use the reserved prefix it is treated as plain human notes.

Statuses

Backend statuses:

  • pending — waiting for ops decision
  • confirmed — accepted, not yet scheduled
  • completed — finished
  • cancelled — closed

Operational (view-model) statuses derived in planner.js:

  • pending — raw pending
  • confirmed — confirmed but no walker assigned
  • assigned — confirmed with walker set
  • in_progress — assigned, scheduled for today, inside a 2-hour live window
  • completed — raw completed
  • cancelled — raw cancelled

assigned and in_progress are view-model states only, not backend enums.

Conflict logic

A booking is flagged as a conflict when:

  • A confirmed or assigned booking has no scheduledFor date set
  • A non-pending, non-cancelled booking has no walker assigned
  • Two active bookings share the same day, walker, and scheduled time slot

Conflicts are intentionally conservative so admins see risk early.

Filtering

Applied in this order:

  1. Segment (today / week / incoming / unassigned / conflicts / recurring)
  2. Search text (dog name, dog breed, client name, email, service, status, notes, route, recurring)
  3. Operational status filters
  4. Service filters
  5. Advanced flags (conflicts only, unassigned only, recurring only)

The Schedule view bypasses the segment filter and always shows confirmed/assigned/in-progress/completed bookings for the current week, with search and service filters still applied.

Session capacity rules

  • Morning session: max 12 dogs
  • Afternoon session: max 12 dogs
  • Capacity counted from all active (non-cancelled) bookings in that day/session
  • Morning = scheduledFor hour < 12, or time unset (defaults to morning)
  • Afternoon = scheduledFor hour ≥ 12

Future improvements

  • Add true backend fields for assigned_walker, scheduled_for, and recurrence instead of storing in admin_notes.
  • Add drag-and-drop chip reordering within sessions.
  • Make session capacity configurable per route or per day.
  • Add a day-column view within the schedule grid (single-day detail).
  • Add weather alerts for bookings on days with rain or high winds.
  • Add audit entries for planner field changes.
  • Add keyboard shortcuts for bulk scheduling workflows.
  • Add saved filter views per admin user.