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, bothavailabilityService.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.tsweb/src/lib/server/dev-mock/store.tsweb/dev-data/availability.json
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. Eachmember_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.
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
Recently shipped follow-ups
These items closed out the “Availability Offers Remaining Work” plan and are now live behind thecrew-availability-offers feature flag:
/offersinbox 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.
OfferDetailexposes a “Send Reminder” action (with optional custom message) and a cancel button for OPEN/DRAFT offers; both call the existing/remindand status-update endpoints. - Orphan offers usable on
/crew-offers. Offers without anevent_idopen in theOfferDetailmodal in place of the dead-end navigation that previously assumed a gig context. - Background sweeper.
crewOfferExpirySweepruns on a schedule from api-events, flipping past-deadlineOPENoffers toEXPIREDso listings/stats stay consistent without read-time mutation. - Accept blocks the calendar.
AcceptOfferwrites a syntheticUNAVAILABLEwindow for the accepted offer’s date/time so subsequent matching ignores the user. - Recurring availability rendered + enforced.
AvailabilityCalendarprojectsrecurring_rule.daysonto every weekday in the visible week, andfindMatchingWorkersprojects recurringUNAVAILABLErules 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, andTimeRangeEditorswapped rawbg-green-100 / text-red-600palette classes for semanticsuccess / warning / destructivetokens so dark mode and theme overrides Just Work. - iCal export from
/offers.lib/utils/icalExport.tsbuilds an RFC 5545 calendar from accepted offers; the page header has an “Export to calendar” button that downloadssoundcheck-offers-YYYY-MM-DD.ics. - Compensation/rate filtering deferred. Documented in the
findMatchingWorkersdoc comment — the filter slot is reserved for whenUserPositiongains a rate field; no behavior change today.