Skip to main content
The operations module is where a booking stops being a commercial promise and becomes something an operator actually runs. It owns the execution side of fulfillment and ground operations: the concrete inventory units a departure has, the finite assets you assign to deliver a service, the vehicles and drivers that move travelers, and the physical places where everything happens. It ships as @voyant-travel/operations, a headless module with Drizzle schema, services, and Hono routes. New code imports the owner subpaths rather than the package root:
  • @voyant-travel/operations/availability for slots, allocation resources, pickups, and rooming.
  • @voyant-travel/operations/resources for resources and resource pools.
  • @voyant-travel/operations/ground for dispatches, vehicles, and drivers.
  • @voyant-travel/operations/places for shared physical places.

Key concepts

These terms come straight from the glossary. Operations is the module that holds the execution truth behind them.
  • Dispatch. An operational order in ground to move passengers from A to B at a time, assigned to a Driver and a Vehicle.
  • Vehicle. A transport asset (car, van, bus, coach) with capacity, class, and accessibility flags.
  • Driver. A crew member assigned to Vehicles and Dispatches.
  • Resource. A finite assignable asset (guide, equipment, room, driver, vehicle) with a type and availability.
  • Resource Pool. A named collection of interchangeable Resources, such as “French-speaking guides, Cairo”.
  • Resource Holds. Operations-owned execution holds against accommodation capacity (Room Resource Hold) or a function space (Space Resource Hold). These carry the execution truth behind a MICE Program’s room and space blocks.
  • Rooming List. Traveler-to-room grouping or assignment data for a Booking.
  • Place. A shared physical place (meeting point, pickup or dropoff place, airport, station, port, attraction, venue, accommodation location) used across OTA, tour-operator, DMC, and MICE workflows.
Capacity is always a number, never a status. A Slot has a capacity and a status; do not conflate them. Operations enforces capacity at two gates: the slot-level pax check and the per-resource check (see fulfillment and ground ops).

What it owns

Operations is split into four owner areas, each with its own schema, service, and routes.

Availability and allocation resources

Availability owns the concrete dated inventory units a product can sell against, and the resources that break a slot’s gross capacity into typed, individually bookable units.
  • Availability Rules generate concrete Slots from an RFC 5545 recurrence. A scheduled slot is what the catalog and profitability surfaces call a “departure”, exposed as the departureLinkable (idPrefix: "avsl").
  • Closeouts block a date or range (holiday, maintenance, sold-out override).
  • Allocation resources are the per-slot inventory primitive for products where an operator buys a fixed block per departure (a hotel allotment, a coach seat map, a guide roster). A slot’s pax bucket is the gross capacity; resources break it into typed units such as room_dbl or vehicle_seat.
  • Pickup Points and Pickup Groups model where travelers are collected, dropped off, or meet.
  • Rooming and allocation exports turn traveler-to-resource assignments into passenger and rooming CSVs.
Operators describe each option’s resource mix once at the catalog level via productOptionResourceTemplates. When generateAvailabilitySlots() publishes a new slot, materializeSlotResourcesFromTemplateDefaults() seeds resources from those template defaults. The helper is idempotent, so re-running generation never blows away custom inventory. A default_count of null disables auto-materialisation, and vehicle-seat layouts stay out of the default path because they need a pax-aware vehicle-parent and seat-children hierarchy.

Resources and resource pools

The resources area owns finite assignable assets that are not slot inventory: guides, equipment, and other typed resources, grouped into interchangeable Resource Pools. It tracks resource requirements, slot assignments, allocations, and closeouts so you can answer “which guide is free on the 28th” without overbooking a person.

Ground

Ground owns the day-of logistics layer: Dispatches, Vehicles, Drivers, ground operators, transfer preferences, dispatch legs, passengers, checkpoints, and execution events. A dispatch is the operational order; vehicles and drivers are the assets it consumes; execution events record what actually happened on the ground.

Places

Places owns shared physical locations used by every workflow. In the v1 vocabulary these are Places; the underlying tables and routes keep the compatibility name facilities. The module exports both names from the same definitions (places is aliased to facilities, placesService to facilitiesService), so you can use the canonical term in new code without a migration.

Working with it

Register the module and use its services against your database handle.
import { createApp } from "@voyant-travel/hono"
import { operationsHonoModule } from "@voyant-travel/operations"

const app = createApp({
  modules: [operationsHonoModule],
})
Generate concrete slots from an availability rule, seeding allocation resources from the option’s templates:
import { generateAvailabilitySlots } from "@voyant-travel/operations/availability"

const result = await generateAvailabilitySlots(db, {
  ruleId: "avrl_…",
  from: "2026-05-01",
  to: "2026-09-30",
})
// Newly created slots whose option has resource templates with a non-null
// default_count are auto-materialised with allocation resources.
Read the resource manifest for a slot before assigning travelers, then validate an allocation against per-resource capacity:
import {
  getSlotResourceAvailability,
  validateSlotAllocationCapacity,
} from "@voyant-travel/operations/availability"

const manifest = await getSlotResourceAvailability(db, { slotId: "avsl_…" })
// manifest.kinds -> [{ kind: "room_dbl", capacity: 40, assigned: 6, available: 34 }]

const check = validateSlotAllocationCapacity(manifest, {
  allocations: { room_dbl: "alrs_…" },
})
// A request that fits the slot's remaining pax but oversells a specific
// resource fails with a resource_capacity_exhausted violation citing the
// offending kind, resourceId, capacity, and existingAssigned.
Place a resource hold for a MICE program’s accommodation demand, then confirm it once the booking firms up:
import { createResourceHold, confirmResourceHold } from "@voyant-travel/operations"

const hold = await createResourceHold(db, {
  kind: "room",
  programId: "prog_…",
  quantity: 20,
})

await confirmResourceHold(db, { holdId: hold.id })
Create a ground dispatch with a vehicle and driver for a transfer:
import { groundService } from "@voyant-travel/operations/ground"

await groundService.createDispatch(db, {
  bookingId: "bkng_…",
  vehicleId: "gveh_…",
  driverId: "gdrv_…",
  pickupPlaceId: "plac_…",
  scheduledAt: "2026-05-28T07:30:00.000Z",
})

Fulfillment and ground ops

Operations is the execution end of the commitment chain. A confirmed booking holds allocations against slots, pickups, or resources, and operations enforces both gates that must pass for a booking to confirm: the slot-level pax check (adjustSlotCapacity) and the per-resource capacity check used both on the read side (the slot resource manifest) and the write side (createTravelerWithTravelDetails). Because both sides use the same distinct-traveler count, the storefront’s “available” number and the booking guard never disagree. Operations stays decoupled and connects to the rest of the platform through links and shared references.
  • Bookings hold the Allocations against operations slots, pickups, and resources. Operations enforces the capacity, bookings owns the commitment.
  • Catalog owns Products and Product Options; operations reads productOptionResourceTemplates to know what resource mix a published slot should have.
  • Finance references a departure (an availability slot, idPrefix: "avsl") through the departureLinkable when allocating supplier cost for per-departure profitability. See Finance.
  • MICE programs carry program-level room and space blocks; the execution truth lives in operations as Room and Space Resource Holds.

React package

@voyant-travel/operations-react provides hooks, clients, query keys, and admin UI, split along the same owner areas as the headless module:
  • @voyant-travel/operations-react/availability (plus /availability/hooks, /availability/allocation, /availability/admin) for slots, the allocation editor, and rooming.
  • @voyant-travel/operations-react/resources for resources and pools.
  • @voyant-travel/operations-react/ground for dispatches, vehicles, and drivers.
  • @voyant-travel/operations-react/places for the places directory.
import { OperationsAvailabilityProvider } from "@voyant-travel/operations-react/availability/provider"

Next steps

Finance

Allocate supplier cost to departures and report per-departure profitability.

Modules

The full catalog of domain modules and how they link.

Data model

How module-owned schemas and cross-module links are authored.

Glossary

The shared vocabulary behind dispatches, resources, and places.