Availability Check
Query available facility resources for a specific time window.
Purpose
The availability check allows you to find resources that are:
- Active (not soft-deleted)
- Not currently assigned during the requested time window
- Within operating hours
- Not in a blackout window
- Not reserved by an active facility reservation
- Of a specific type (optional)
Request
REST API
POST /facility-resources/availability
Content-Type: application/json
{
"tenantId": 1,
"clubId": 10,
"type": "SIMULATOR",
"start": "2025-01-15T10:00:00Z",
"end": "2025-01-15T12:00:00Z"
}
GraphQL API
mutation FacilityAvailability {
facilityAvailability(request: {
tenantId: 1
clubId: 10
type: SIMULATOR
start: "2025-01-15T10:00:00Z"
end: "2025-01-15T12:00:00Z"
}) {
resourceId
name
type
available
}
}
Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
tenantId | number | Yes | Tenant scope |
clubId | number | No | Club scope |
type | ResourceType | No | Filter by resource type |
start | DateTime | Yes | Start of time window |
end | DateTime | Yes | End of time window |
Response
[
{
"resourceId": 5,
"name": "Simulator Bay 1",
"type": "SIMULATOR",
"available": true
},
{
"resourceId": 6,
"name": "Simulator Bay 2",
"type": "SIMULATOR",
"available": true
}
]
Validation
The service validates:
startmust be beforeend- Time window must be in the future (configurable)
typemust be a valid ResourceType
{
"statusCode": 400,
"message": "start must be before end",
"error": "Bad Request"
}
Availability Logic
A resource is considered available if:
active = true(not soft-deleted)maintenanceRequired = false(optional, configurable)- No overlapping
ResourceUsagerecords exist where:assignedAt < requestedEndreleasedAt IS NULL OR releasedAt > requestedStart
- No overlapping
MaintenanceLogrecords exist in the window - The request falls within
FacilityHours(when hours are defined) - No overlapping
FacilityBlackoutentries apply (resource/type/club/tenant) - No overlapping active
FacilityReservationentries exist
SELECT fr.*
FROM facility_resources fr
WHERE fr.tenant_id = $tenantId
AND fr.active = true
AND fr.type = $type
AND NOT EXISTS (
SELECT 1 FROM resource_usage ru
WHERE ru.resource_id = fr.id
AND ru.assigned_at < $end
AND (ru.released_at IS NULL OR ru.released_at > $start)
)
Reservations, blackouts, and operating hours are enforced in the service layer and are not shown in the SQL above.
Use Cases
1. Booking Flow
Check available simulators before creating a booking:
# Step 1: Check availability
POST /facility-resources/availability
{ "tenantId": 1, "type": "SIMULATOR", "start": "...", "end": "..." }
# Step 2: Create booking with selected resource
POST /bookings
{ "resourceId": 5, ... }
# Step 3: Record resource usage
POST /resource-usage
{ "resourceId": 5, "bookingId": 123, "assignedAt": "..." }
2. Maintenance Planning
Find available time slots for maintenance:
POST /facility-resources/availability
{
"tenantId": 1,
"type": "DRIVING_RANGE",
"start": "2025-01-20T06:00:00Z",
"end": "2025-01-20T10:00:00Z"
}
3. Capacity Dashboard
Check current availability across all resource types:
const types = ['SIMULATOR', 'GOLF_CART', 'DRIVING_RANGE'];
const now = new Date();
const endOfDay = /* ... */;
const availability = await Promise.all(
types.map(type =>
fetch('/api/facility-resources/availability', {
method: 'POST',
body: JSON.stringify({ tenantId, type, start: now, end: endOfDay })
})
)
);