feat: match fleet to blueprint targets exactly

Add an optional exact blueprint mode with keep/create/remove previews, atomic queueing, cancellation of unstarted excess creations, and persistent dependencies for safe port reuse. Track removals alongside creations and preserve fill mode as the default.

Validation: type check, production build, and 103 deployment tests passed. The full suite has one telemetry assertion failure also reproduced on the previous commit.

Fixes #42
This commit is contained in:
2026-09-27 13:36:08 -04:00
parent 1aa7f15371
commit 0b0e5b5bdb
13 changed files with 517 additions and 83 deletions
+45 -9
View File
@@ -17,20 +17,53 @@ they appear in both the server registry and active creation queue.
Registered servers count even if stopped or unhealthy; conforming does not
restart or reconfigure them. Failed creation jobs without a registered server,
destroyed records, and servers awaiting removal do not count. Excess servers and
maps outside the blueprint are kept. This action fills deficits; it does not
destroy servers or change existing servers' files.
destroyed records, and servers awaiting removal do not count. The default
**Fill missing servers** mode keeps excess servers and maps outside the blueprint.
It fills deficits without changing existing servers' files.
## Build and launch a collection
1. Choose **Create blueprint** on Deployments and name the lineup.
2. Add maps from Black Ops I or II and set the desired total lobbies for each.
3. Choose **Save & preview** to review every new server ID and game port.
3. Choose **Save & preview** (or **Preview fleet changes** on a saved blueprint).
Choose **Fill missing servers** or **Match blueprint exactly**, then review
the server IDs and game ports.
4. Lobbies with a saved key show **Saved key ready** and reuse it automatically.
Enter a Plutonium key only for lobbies missing one. Update saved keys in **Keys**.
5. Choose **Queue N servers** and follow their collection progress page.
5. Choose **Queue N servers** (or confirm removals and choose **Apply** in exact
mode) and follow the collection progress page.
If every target is already met, choose **Done**; no operation is created.
### Match blueprint exactly
Exact mode applies to the entire registered and queued fleet across both games.
The preview lists servers to keep, create, and remove. It keeps deployed lobbies
before unstarted creations, then the lowest lobby numbers within each game/map
variant. It removes excess lobbies and maps outside the blueprint. Retained
servers keep their containers, files, ports, and configuration without a restart.
The option is chosen per launch; opening another preview defaults to fill mode.
Review the removal list and check its confirmation before applying. Removed
servers lose their containers, files, and registrations; saved keys remain.
Unstarted creations are cancelled without booting a container. Running servers
use the normal removal queue and require a fresh zero-player RCON response.
Occupied or unreachable servers wait. Already pending removals are reused.
Creation reservations and removals are queued in one database transaction. A
missing key or changed fleet rejects the entire request. Any fleet identity,
map, port, or pending-removal change since an exact preview requires a new review.
Servers added after submission are not included. Applying the same preview again
returns the same collection without repeating operations.
Ports belonging to reviewed removals can be reserved for new lobbies even when
the current port range is full. A new lobby waits until its port's removal has
completed; a failed, interrupted, or cancelled removal keeps that launch blocked,
with the reason shown in its progress. Other launches with available capacity can
proceed. Reservations and dependencies survive app restarts. The progress page
tracks creations and removals, including removal-only plans, and lists the servers
that were retained. The existing operation detail page offers removal cancellation
and cleanup recovery where applicable.
Blueprints support up to 40 distinct game/map selections, 1–20 lobbies per map,
and 100 servers total. The host's configured port range and existing fleet may
allow fewer. A blueprint can be saved even when there is insufficient capacity
@@ -48,7 +81,8 @@ A collection preview does not reserve capacity. At submission, all lobby IDs,
ports, and keys are validated again. The entire collection is then queued in one
database transaction. If any server lacks a valid key or capacity has changed,
no jobs, reservations, or key changes from that submission are committed. Refreshing
the preview clears typed keys so they cannot be applied to changed server IDs.
the preview retains typed keys only for unchanged server IDs still missing a saved
key, and resets removal confirmation.
Submitting the same preview again returns the same collection, including after
a lost response or an application restart. Reusing the blueprint with a new
@@ -174,15 +208,17 @@ repeats container creation or deployment as part of this recovery.
- `PUT /api/blueprints/:id`: edit `{ name, description?, entries }`. All entries
use the latest promoted setup when launched.
- `DELETE /api/blueprints/:id`: remove a library entry.
- `POST /api/deployment-collections/preview`: preview `{ blueprintId }`, including
the configured `launchConcurrency`.
- `POST /api/deployment-collections/preview`: preview `{ blueprintId, mode? }`,
where mode is `fill` (default) or `exact`. Returns `mode`, `retainedServers`,
`removals` (name/reason), creation `servers`, and configured `launchConcurrency`.
- `POST /api/deployment-collections`: atomically queue `{ previewId, keys? }`,
where `keys` maps exact preview server IDs to optional replacement keys.
A satisfied preview returns `{ ok: true, collectionId: null }` with HTTP 200,
without creating a collection, saving keys, or kicking the worker.
- `GET /api/deployment-collections`: list collection progress summaries with
separate `queued`, `provisioning`, and `verifying` counts.
- `GET /api/deployment-collections/:id`: collection and per-server progress,
- `GET /api/deployment-collections/:id`: collection mode, retained server IDs,
per-operation progress with `action: create | destroy`,
each waiting server's global `queuePosition`, and the shared queue's concurrency,
active startups, and queued count.
- `POST /api/deployments/preview`: preview `{ game, mapSlug }` or `{ deploymentId }`