> ## Documentation Index
> Fetch the complete documentation index at: https://docs.soundchecklive.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Crew Availability & Offers — Dev Mock Cutover

> Historical record of the dev-mock layer that bridged the gap until the real api-events API shipped. Both surfaces now talk to the real API.

# 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

| Surface | Real API entry point |
| - | - |
| User availability CRUD | `GET/POST/PUT/DELETE /api/v1/organizations/{orgId}/users/{userId}/availability` (`api-events/src/systems/availability/endpoints/availabilityEndpoints.ts`) |
| Org-wide member availability | `GET /api/v1/organizations/{orgId}/members/availability` |
| Member conflicts | `GET /api/v1/organizations/{orgId}/members/{memberId}/conflicts` |
| Crew offers CRUD + send/remind/accept/decline | `/api/v1/organizations/{orgId}/offers/...` (`api-events/src/systems/crew-offers/endpoints/crewOffersEndpoints.ts`) |
| Auto-add matching preview | `GET /api/v1/organizations/{orgId}/offers/matching-workers` |

## 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.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.