-
Notifications
You must be signed in to change notification settings - Fork 0
Scheduling and Dispatch
Schedule requests let a pilot state when they are available and how many flights they want. Dispatch converts a request into canonical flight records; the request itself remains the historical planning record.
A schedule request contains:
- tenant and pilot membership IDs;
- optional title and notes;
- overall
windowStartandwindowEnd; -
desiredFlightCount, from 1 to 50; - flexible JSON
preferences; - numeric
version, status, rejection/cancellation reason, and linked-flight counts; and - creation/update timestamps.
The current web form stores detailed availability as:
{
"availability": [
{
"startAt": "2026-09-10T08:00:00.000Z",
"endAt": "2026-09-10T12:00:00.000Z"
},
{
"startAt": "2026-09-11T15:00:00.000Z",
"endAt": "2026-09-11T19:00:00.000Z"
}
]
}The intervals are sorted before submission. The earliest start becomes windowStart; the latest end becomes windowEnd. This preserves a simple query window while keeping the precise intervals available to dispatch.
The schedule form and API enforce:
- at least one interval;
- a valid start and end for every interval;
- end later than start;
- no overlapping intervals;
- 1–50 desired flights;
- title up to 120 characters; and
- notes up to 2,000 characters.
All datetime-local values are converted as UTC / Zulu. The API normalizes and
sorts detailed intervals, rejects overlaps or invalid ranges, and verifies the
overall window matches the detailed availability. Request-linked flights must
fit a detailed interval.
stateDiagram-v2
[*] --> pending
pending --> in_review: dispatcher starts review
pending --> rejected: dispatcher rejects
pending --> cancelled: pilot or dispatch cancels
in_review --> fulfilled: complete offer created
in_review --> partially_fulfilled: partial historical result
in_review --> rejected: dispatcher rejects
in_review --> cancelled: pilot or dispatch cancels
partially_fulfilled --> fulfilled: backend transition exists
partially_fulfilled --> cancelled: pilot or dispatch cancels
fulfilled --> [*]
rejected --> [*]
cancelled --> [*]
fulfilled, rejected, and cancelled are terminal. A
partially_fulfilled request remains active and can receive another atomic
batch until its requested capacity is reached.
The pilot dashboard refreshes requests and flights every 30 seconds. It separates:
- active requests:
pending,in_review,partially_fulfilled; - offered flights needing a decision;
- upcoming accepted or briefed flights; and
- recent terminal history.
A pilot can version-edit an owned pending request until dispatch starts review.
If another actor changes it first, the editor reloads the current version and
requires review before retrying.
A pilot can cancel an owned request in pending, in_review, or
partially_fulfilled state. The cancellation dialog requires one of two linked-
flight policies: keep every linked flight, or cancel eligible pre-departure
flights atomically. Active and terminal history is never silently rewritten.
The dispatcher queue is tenant-wide and cursor-paginated, with filters for:
- pending;
- in review;
- fulfilled;
- rejected;
- cancelled; and
- historical partial.
Dispatchers can start review from the queue or open the full request workspace. The workspace displays pilot identity, overall window, precise availability slots, notes, request actions, offer builder, and linked canonical flights.
For an in-review or partially fulfilled request, the offer builder shows the remaining capacity and lets dispatch choose a batch size from one through that remainder. Each row requires:
- flight number;
- four-letter departure ICAO;
- four-letter arrival ICAO;
- ETD in UTC;
- ETA in UTC and after ETD; and
- optional aircraft type.
One submission calls POST /flights/bulk with the current request version and
a stable Idempotency-Key. The backend locks the request before linked flights,
rechecks cumulative capacity and normalized availability, assigns the owning
active pilot, links each flight, and creates it as offered.
The request becomes partially_fulfilled while capacity remains and fulfilled
when complete. An exact same-key retry returns the original ordered result;
reusing a key for a different payload is a conflict.
- Every edit, transition, fulfillment, and cancellation compares the stored request version.
- Request fulfillment and its flights/audits commit atomically.
- The required cross-domain lock order is schedule request before flights.
- Single-flight creation is ad-hoc only; clients cannot bypass cumulative request fulfillment by attaching a request ID there.
Dispatch can reject a pending or in_review request with an optional explanation. Rejection is terminal and the reason is visible to the pilot.
Dispatch can cancel the same states a pilot can cancel. Cancellation is operationally distinct from rejection:
- Rejected means dispatch made a terminal decision not to fulfill the request.
- Cancelled means the request was withdrawn or stopped.
Neither action deletes history.
The flight-management view can create a flight without a schedule request. A dispatcher enters route, schedule, aircraft, notes, pilot, and initial status.
- A draft may be unassigned.
- An offered flight requires an active pilot membership from the same tenant.
- Request-linked creation is rejected here and must use the bulk workflow.
See Flights and State Machines for the operational lifecycle after creation.
The API writes audit events for:
- request creation;
- every request status transition;
- single-flight creation;
- bulk flight creation;
- flight edits; and
- flight transitions.
Administrators can search the audit viewer and request a bounded, access-audited export. Audit metadata records version changes without copying secrets.
When extending request or generation behavior:
- Preserve tenant and pilot ownership checks.
- Define allowed states and concurrent-update behavior first.
- Validate detailed interval semantics on the server.
- Preserve idempotency for create/generate operations.
- State explicitly whether cancellation cascades, and make it transactional.
- Keep canonical flights separate from transient generator output.
- Update API serializers, OpenAPI, web Zod schemas, UI action matrices, audit metadata, and tests together.
VA Dispatch repository · OpenAPI source · Security policy · AGPL-3.0-or-later · Simulation use only
VA Dispatch
Using the application
Building and operating
- Architecture
- Authentication and Multi-Tenancy
- Data Model
- API Guide
- Local Development
- Configuration Reference
- Deployment and Operations
- Testing and Quality
- Security and Privacy
Maintaining the project