Skip to main content

Crew Availability & Offers — Dev Mock Cutover

This page used to describe a JSON-file-backed dev-mock layer for crew availability and offers. As of the cutover, both availabilityService.ts and crewOfferService.ts call the real api-events REST API in every environment. The dev-mock route, in-process store, and seed JSON files have been removed.

What replaced the dev mock

Files removed during the cutover

  • web/src/app/api/dev-mock/availability/route.ts
  • web/src/lib/server/dev-mock/store.ts
  • web/dev-data/availability.json
The USE_DEV_MOCK branches in availabilityService.ts were also dropped; the service is now a thin wrapper over the generated API core.

Current availability semantics

Availability is org-scoped. Each member_availability row belongs to both a user_id and an organization_id, so a crew member can be available for one organization and unavailable for another at the same date/time. Existing user-level rows were intentionally not backfilled when org scoping was introduced; org-level schedules start fresh. Personal availability CRUD requires both checks:
  • The caller must be editing their own userId.
  • The caller must be an active member of the target orgId.
Org-wide calendar and member availability reads only use availability rows from the target organization. Crew-offer matching and the synthetic UNAVAILABLE block written when an offer is accepted are also scoped to the offer’s organization. UNKNOWN means the member has no overlapping AVAILABLE row for the requested window. Offer auto-add is intentionally looser: a worker with no overlapping UNAVAILABLE row can still match an offer, because many workers do not pre-fill positive availability.

Behaviors carried over to the backend

The dev-mock implemented several behaviors that remain part of the user experience and were ported to api-events:
  • Same-status overlap merge for availability windows
  • Opposite-status overlap split/trim when adding an UNAVAILABLE block over an AVAILABLE one
  • Exact-time storage for UNAVAILABLE windows. A previous dev-mock buffer widened UNAVAILABLE windows, but api-events stores the user-entered window exactly; any future travel buffer should live in matching/conflict logic rather than persisted availability rows.
  • Multi-day availability ranges (per-day window expansion)
  • Auto-add available workers with availability filtering on offer creation
  • Fee type toggle (FIXED / HOURLY) on offers
If you find a discrepancy between the prior dev-mock behavior and what api-events does, file it as a bug — the dev-mock is gone and api-events is the source of truth.

Recently shipped follow-ups

These items closed out the “Availability Offers Remaining Work” plan and are now live behind the crew-availability-offers feature flag:
  • /offers inbox surfaced in the sidebar. Crew members get a “My Offers” entry with a pending-count badge that polls every 60s and on focus.
  • Reminder + cancel UI. OfferDetail exposes a “Send Reminder” action (with optional custom message) and a cancel button for OPEN/DRAFT offers; both call the existing /remind and status-update endpoints.
  • Orphan offers usable on /crew-offers. Offers without an event_id open in the OfferDetail modal in place of the dead-end navigation that previously assumed a gig context.
  • Background sweeper. crewOfferExpirySweep runs on a schedule from api-events, flipping past-deadline OPEN offers to EXPIRED so listings/stats stay consistent without read-time mutation.
  • Accept blocks the calendar. AcceptOffer writes a synthetic UNAVAILABLE window for the accepted offer’s date/time so subsequent matching ignores the user.
  • Recurring availability rendered + enforced. AvailabilityCalendar projects recurring_rule.days onto every weekday in the visible week, and findMatchingWorkers projects recurring UNAVAILABLE rules onto the offer date when filtering candidates (availabilityRepo.GetRecurringByUsers).
  • TimePicker keyboard + wheel nav. ArrowUp/ArrowDown step the focused segment, mouse wheel does the same; Alt+ArrowDown opens the dropdown (matches WAI-ARIA combobox).
  • Design-token color migration. AvailabilityBadge, TeamAvailabilityView, and TimeRangeEditor swapped raw bg-green-100 / text-red-600 palette classes for semantic success / warning / destructive tokens so dark mode and theme overrides Just Work.
  • iCal export from /offers. lib/utils/icalExport.ts builds an RFC 5545 calendar from accepted offers; the page header has an “Export to calendar” button that downloads soundcheck-offers-YYYY-MM-DD.ics.
  • Compensation/rate filtering deferred. Documented in the findMatchingWorkers doc comment — the filter slot is reserved for when UserPosition gains a rate field; no behavior change today.