Part 1 of #43 "Add ability to chain flights in queue" (backend only; UI + map rendering land in part 2).
What changed
Data model: new queue TEXT NOT NULL DEFAULT '[]' column on planes — an ordered JSON array of ICAOs = the not-yet-started legs. The active leg stays as today (destIcao + departureSimTime). Guarded migration in migrateColumns() for existing DBs; seed sets [].
Auto-chain: in deliverPackages(), on arrival a plane with a non-empty queue auto-starts the next queued leg (stays 'flying') if fuel covers it; otherwise grounds safely with the remaining queue intact. Cargo delivery still runs first, unchanged. Composes correctly with v0.24.0 pause-on-landing — a chained plane counts as airborne in the fresh status='flying' select, so no premature pause mid-chain (new regression test).
Endpoints:POST /api/planes/{planeId}/queue {destIcao} (append a not-yet-started leg; works grounded or flying) and POST /api/planes/{planeId}/queue/cancel {index} (remove one queued leg). Both run through performAction (tick-first + lock), mirror the /fly validation, return the full snapshot.
OpenAPI:PlaneState.queue, two new request schemas, both paths — spec updated per AGENTS.md.
Tests
+12 unit tests: queueLeg/cancelQueuedLeg (order, works-while-flying, 404/400, index removal, OOB/negative), auto-chain (chain w/ fuel, ground-on-short-fuel with queue intact, empty-queue unchanged, chained plane does NOT trigger last-plane pause). vitest 303 passing. No e2e in this part (UI lands next).
Version: 0.24.0 → 0.25.0
Part 1 of #43 "Add ability to chain flights in queue" (backend only; UI + map rendering land in part 2).
## What changed
- **Data model:** new `queue TEXT NOT NULL DEFAULT '[]'` column on `planes` — an ordered JSON array of ICAOs = the not-yet-started legs. The active leg stays as today (`destIcao` + `departureSimTime`). Guarded migration in `migrateColumns()` for existing DBs; seed sets `[]`.
- **Auto-chain:** in `deliverPackages()`, on arrival a plane with a non-empty queue auto-starts the next queued leg (stays `'flying'`) if fuel covers it; otherwise grounds safely with the remaining queue intact. Cargo delivery still runs first, unchanged. Composes correctly with v0.24.0 pause-on-landing — a chained plane counts as airborne in the fresh `status='flying'` select, so no premature pause mid-chain (new regression test).
- **Endpoints:** `POST /api/planes/{planeId}/queue {destIcao}` (append a not-yet-started leg; works grounded or flying) and `POST /api/planes/{planeId}/queue/cancel {index}` (remove one queued leg). Both run through `performAction` (tick-first + lock), mirror the `/fly` validation, return the full snapshot.
- **OpenAPI:** `PlaneState.queue`, two new request schemas, both paths — spec updated per AGENTS.md.
## Tests
+12 unit tests: queueLeg/cancelQueuedLeg (order, works-while-flying, 404/400, index removal, OOB/negative), auto-chain (chain w/ fuel, ground-on-short-fuel with queue intact, empty-queue unchanged, chained plane does NOT trigger last-plane pause). vitest 303 passing. No e2e in this part (UI lands next).
Version: 0.24.0 → **0.25.0**
- planes.queue TEXT NOT NULL DEFAULT '[]' — ordered JSON array of not-yet-started
leg ICACs; active leg stays destIcao + departureSimTime. DDL + guarded ALTER
migration for existing DBs; seed sets queue: [] explicitly.
- deliverPackages() auto-chains on arrival: with a non-empty queue and fuel
covering the first queued leg (same requiredFuelFor rule as /fly), the plane
immediately starts that leg from the arrival airport (stays 'flying',
departureSimTime = arrival instant, queue shortened). Short tank → grounds
safely with the queue kept intact; empty queue → unchanged grounding. Cargo
delivery for the reached airport runs first and is unaffected. Ordering kept:
delivery still runs before tickOnce's pause check, so a chained plane counts
as still flying — no premature last-plane pause (ISS-041 preserved).
- New endpoints via performAction(): POST /api/planes/{planeId}/queue {destIcao}
(append; works grounded or flying; 400 bad body/unknown ICAO, 404 unknown
plane) and POST /api/planes/{planeId}/queue/cancel {index} (remove queued leg
by index; active in-flight leg never affected; 400 non-integer/out-of-range,
404 unknown plane). Both return the full state snapshot.
- PlaneState.queue: string[] in /api/state (null/malformed-safe parse helper
shared with the engine); OpenAPI updated (PlaneState.queue, QueueLegRequest,
CancelQueuedLegRequest, both paths) and openapi.test.ts expectations extended.
- Tests: auto-chain block in engine.test.ts (chain / short-fuel ground / empty
queue) + chained-plane-no-pause regression guard; queueLeg/cancelQueuedLeg
blocks in actions.test.ts; type-compat queue: [] fixtures in deriveEvents,
right-pane, mapData and seed tests.
v0.25.0 — part 1 (backend) of ISS-043; UI/map rendering lands in a follow-up.
kamilkrzywda
scheduled this pull request to auto merge when all checks succeed 2026-09-20 12:41:08 +02:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Part 1 of #43 "Add ability to chain flights in queue" (backend only; UI + map rendering land in part 2).
What changed
queue TEXT NOT NULL DEFAULT '[]'column onplanes— an ordered JSON array of ICAOs = the not-yet-started legs. The active leg stays as today (destIcao+departureSimTime). Guarded migration inmigrateColumns()for existing DBs; seed sets[].deliverPackages(), on arrival a plane with a non-empty queue auto-starts the next queued leg (stays'flying') if fuel covers it; otherwise grounds safely with the remaining queue intact. Cargo delivery still runs first, unchanged. Composes correctly with v0.24.0 pause-on-landing — a chained plane counts as airborne in the freshstatus='flying'select, so no premature pause mid-chain (new regression test).POST /api/planes/{planeId}/queue {destIcao}(append a not-yet-started leg; works grounded or flying) andPOST /api/planes/{planeId}/queue/cancel {index}(remove one queued leg). Both run throughperformAction(tick-first + lock), mirror the/flyvalidation, return the full snapshot.PlaneState.queue, two new request schemas, both paths — spec updated per AGENTS.md.Tests
+12 unit tests: queueLeg/cancelQueuedLeg (order, works-while-flying, 404/400, index removal, OOB/negative), auto-chain (chain w/ fuel, ground-on-short-fuel with queue intact, empty-queue unchanged, chained plane does NOT trigger last-plane pause). vitest 303 passing. No e2e in this part (UI lands next).
Version: 0.24.0 → 0.25.0
- planes.queue TEXT NOT NULL DEFAULT '[]' — ordered JSON array of not-yet-started leg ICACs; active leg stays destIcao + departureSimTime. DDL + guarded ALTER migration for existing DBs; seed sets queue: [] explicitly. - deliverPackages() auto-chains on arrival: with a non-empty queue and fuel covering the first queued leg (same requiredFuelFor rule as /fly), the plane immediately starts that leg from the arrival airport (stays 'flying', departureSimTime = arrival instant, queue shortened). Short tank → grounds safely with the queue kept intact; empty queue → unchanged grounding. Cargo delivery for the reached airport runs first and is unaffected. Ordering kept: delivery still runs before tickOnce's pause check, so a chained plane counts as still flying — no premature last-plane pause (ISS-041 preserved). - New endpoints via performAction(): POST /api/planes/{planeId}/queue {destIcao} (append; works grounded or flying; 400 bad body/unknown ICAO, 404 unknown plane) and POST /api/planes/{planeId}/queue/cancel {index} (remove queued leg by index; active in-flight leg never affected; 400 non-integer/out-of-range, 404 unknown plane). Both return the full state snapshot. - PlaneState.queue: string[] in /api/state (null/malformed-safe parse helper shared with the engine); OpenAPI updated (PlaneState.queue, QueueLegRequest, CancelQueuedLegRequest, both paths) and openapi.test.ts expectations extended. - Tests: auto-chain block in engine.test.ts (chain / short-fuel ground / empty queue) + chained-plane-no-pause regression guard; queueLeg/cancelQueuedLeg blocks in actions.test.ts; type-compat queue: [] fixtures in deriveEvents, right-pane, mapData and seed tests. v0.25.0 — part 1 (backend) of ISS-043; UI/map rendering lands in a follow-up.