ui/phase-14: rename planet end-to-end + order read-back
Wires the first end-to-end command through the full pipeline:
inspector rename action → local order draft → user.games.order
submit → optimistic overlay on map / inspector → server hydration
on cache miss via the new user.games.order.get message type.
Backend: GET /api/v1/user/games/{id}/orders forwards to engine
GET /api/v1/order. Gateway parses the engine PUT response into the
extended UserGamesOrderResponse FBS envelope and adds
executeUserGamesOrderGet for the read-back path. Frontend ports
ValidateTypeName to TS, lands the inline rename editor + Submit
button, and exposes a renderedReport context so consumers see the
overlay-applied snapshot.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+139
-24
@@ -1522,27 +1522,138 @@ Targeted tests:
|
||||
inspector content, and on `chromium-mobile-iphone-13` asserts the
|
||||
bottom-sheet appears and the close button clears it.
|
||||
|
||||
## Phase 14. First End-to-End Command — Rename Planet
|
||||
## ~~Phase 14. First End-to-End Command — Rename Planet~~
|
||||
|
||||
Status: pending.
|
||||
Status: done.
|
||||
|
||||
Goal: prove the entire pipeline (inspector → composer → submit →
|
||||
server → state refresh) by wiring up exactly one action: renaming a
|
||||
planet.
|
||||
|
||||
Artifacts:
|
||||
Decisions taken with the project owner during implementation:
|
||||
|
||||
- `ui/frontend/src/lib/inspectors/planet.svelte` adds a `Rename` action
|
||||
that opens a small inline editor and adds a `RenamePlanet` command
|
||||
to the order draft on confirm
|
||||
- `ui/frontend/src/sync/submit.ts` `submitOrder()` function that POSTs
|
||||
the entire draft via `GalaxyClient.execute('user.games.order', ...)`
|
||||
and applies per-command results
|
||||
- `ui/frontend/src/lib/sidebar/order-tab.svelte` adds a `Submit order`
|
||||
button calling `submitOrder()` and renders accepted / rejected
|
||||
status per command after submit
|
||||
- on successful submit, refresh game state so the rename appears on the
|
||||
map and in the inspector
|
||||
1. **Optimistic overlay over `user.games.order`.** The plan's
|
||||
acceptance criterion ("name change within one second") is
|
||||
inconsistent with the engine's order endpoint, which only
|
||||
validates and stores; rename takes effect at turn cutoff.
|
||||
Phase 14 keeps `user.games.order` for the wire path and adds a
|
||||
pure projection `applyOrderOverlay(report, commands, statuses)`
|
||||
in `api/game-state.ts`. Inspector, mobile sheet, and map
|
||||
renderer read a derived `renderedReport` (context key
|
||||
`RENDERED_REPORT_CONTEXT_KEY`) that swaps planet names in for
|
||||
every applied or in-flight rename. Raw `gameState.report`
|
||||
stays available for debugging / history mode.
|
||||
2. **Read-back endpoint `user.games.order.get`.** Without a
|
||||
server snapshot of stored orders the optimistic overlay would
|
||||
not survive a cache wipe. Phase 14 adds the new authenticated
|
||||
message type with a backend route
|
||||
`GET /api/v1/user/games/{game_id}/orders?turn=N` (pass-through
|
||||
to the engine's existing `GET /api/v1/order`). The frontend
|
||||
calls it from `OrderDraftStore.hydrateFromServer` only when
|
||||
the local cache row is *absent* — an explicitly empty cache
|
||||
row honours the user's empty draft. The `turn` query is
|
||||
required (the frontend always knows the current turn from the
|
||||
lobby record).
|
||||
3. **Per-command results from real engine response.** The engine
|
||||
now answers `PUT /api/v1/order` with `202 Accepted` and a
|
||||
populated `UserGamesOrder` body (per-command `cmdApplied`,
|
||||
`cmdErrorCode`, plus an engine-assigned `updatedAt`). The
|
||||
gateway parses that JSON into the extended FBS
|
||||
`UserGamesOrderResponse` envelope and the frontend reads the
|
||||
per-command outcome through `submitOrder`. A defensive
|
||||
batch-level fallback covers an empty `commands` array.
|
||||
4. **Applied commands stay in the draft.** Per the gameplay
|
||||
model, the order is the player's intent surface — submitted
|
||||
commands stay until the user removes them or until turn
|
||||
cutoff (Phase 24 wires the auto-clear). Statuses are
|
||||
runtime-only; on reload the draft re-validates as `valid` and
|
||||
the overlay re-applies.
|
||||
5. **Validator parity through a TS port.** `ValidateTypeName`
|
||||
from `pkg/util/string.go` is mirrored in
|
||||
`ui/frontend/src/lib/util/entity-name.ts`. The inspector's
|
||||
inline editor disables the confirm button until the input
|
||||
passes; the draft store re-runs the validator on every `add`
|
||||
and exposes per-row `valid` / `invalid` to the order tab.
|
||||
6. **`updatedAt` plumbing without enforcement.** Phase 14 sends
|
||||
`0` on every submit (no client-side stale-order detection
|
||||
yet); the engine still writes a real timestamp, the gateway
|
||||
surfaces it in the FBS response, and the draft stashes it.
|
||||
Future phases can wire conditional updates without a wire
|
||||
change.
|
||||
|
||||
Artifacts (delivered):
|
||||
|
||||
- `pkg/schema/fbs/order.fbs` — extended `UserGamesOrderResponse`
|
||||
(`game_id`, `updated_at`, `commands`); new
|
||||
`UserGamesOrderGet` / `UserGamesOrderGetResponse` tables.
|
||||
- `pkg/model/order/order.go` — `MessageTypeUserGamesOrderGet` and
|
||||
`UserGamesOrderGet` typed payload.
|
||||
- `pkg/transcoder/order.go` — `JSONToUserGamesOrder`,
|
||||
`UserGamesOrderResponseToPayload`,
|
||||
`UserGamesOrderGetToPayload`,
|
||||
`PayloadToUserGamesOrderGet`,
|
||||
`PayloadToUserGamesOrderResponse`,
|
||||
`UserGamesOrderGetResponseToPayload`,
|
||||
`PayloadToUserGamesOrderGetResponse`. Replaces the old
|
||||
`EmptyUserGamesOrderResponsePayload` helper.
|
||||
- `backend/internal/server/handlers_user_games.go` — new
|
||||
`GetOrders` handler. `engineclient.GetOrder` forwards to the
|
||||
engine's `GET /api/v1/order` with the player rebound.
|
||||
`backend/openapi.yaml` documents the new GET operation;
|
||||
`contract_test.go` extended with a `queryParamStubs` map for
|
||||
required query parameters.
|
||||
- `gateway/internal/backendclient/games_commands.go` — updated
|
||||
`executeUserGamesOrder` (parses real engine JSON via
|
||||
`JSONToUserGamesOrder`); new `executeUserGamesOrderGet` and
|
||||
`projectUserGamesOrderGetResponse`.
|
||||
`gateway/internal/backendclient/routes.go` registers the new
|
||||
message type.
|
||||
- `ui/Makefile` — `order.fbs` joins `FBS_INPUTS`; regenerated TS
|
||||
bindings under `ui/frontend/src/proto/galaxy/fbs/order/`.
|
||||
- `ui/frontend/src/sync/order-types.ts` — `PlanetRenameCommand`
|
||||
variant added to the discriminated union.
|
||||
- `ui/frontend/src/sync/submit.ts` — `submitOrder` posts the FBS
|
||||
request and parses per-command verdicts.
|
||||
- `ui/frontend/src/sync/order-load.ts` — `fetchOrder` issues
|
||||
`user.games.order.get`.
|
||||
- `ui/frontend/src/sync/order-draft.svelte.ts` — extended with
|
||||
per-command `statuses`, `validate` / `markSubmitting` /
|
||||
`applyResults` / `markRejected` / `revertSubmittingToValid` /
|
||||
`hydrateFromServer`, and the `needsServerHydration` flag.
|
||||
- `ui/frontend/src/lib/util/entity-name.ts` — TS port of
|
||||
`ValidateTypeName`.
|
||||
- `ui/frontend/src/api/game-state.ts` — pure
|
||||
`applyOrderOverlay(report, commands, statuses)` projection
|
||||
plus the `currentTurn` rune on `GameStateStore`.
|
||||
- `ui/frontend/src/lib/rendered-report.svelte.ts` — derives the
|
||||
overlay-applied report and exposes it through
|
||||
`RENDERED_REPORT_CONTEXT_KEY`.
|
||||
- `ui/frontend/src/lib/galaxy-client-context.svelte.ts` —
|
||||
`GalaxyClientHolder` so command-driven UI can resolve the
|
||||
per-game `GalaxyClient` via context.
|
||||
- `ui/frontend/src/lib/inspectors/planet.svelte` — Rename action
|
||||
+ inline editor with `validateEntityName`-driven feedback.
|
||||
- `ui/frontend/src/lib/sidebar/order-tab.svelte` — per-row
|
||||
status, Submit button with disabled-state matrix, refresh on
|
||||
success, surfaces batch errors inline.
|
||||
- `ui/frontend/src/lib/sidebar/inspector-tab.svelte` and
|
||||
`ui/frontend/src/lib/active-view/map.svelte` — switched to
|
||||
`renderedReport`.
|
||||
- `ui/frontend/src/routes/games/[id]/+layout.svelte` — wires the
|
||||
rendered report and galaxy-client contexts; runs
|
||||
`orderDraft.hydrateFromServer(...)` after the boot
|
||||
`Promise.all` resolves when `needsServerHydration`.
|
||||
- `ui/frontend/src/lib/i18n/locales/{en,ru}.ts` — keys for
|
||||
rename action / editor / order statuses / submit copy.
|
||||
- Tests: `entity-name.test.ts`, `submit.test.ts`,
|
||||
`order-load.test.ts`, `order-overlay.test.ts`,
|
||||
`order-tab.test.ts`, extended `order-draft.test.ts` and
|
||||
`inspector-planet.test.ts`. New Playwright spec
|
||||
`tests/e2e/rename-planet.spec.ts`.
|
||||
- Documentation: `docs/ARCHITECTURE.md` §9, `docs/FUNCTIONAL.md`
|
||||
§6.2 (and `docs/FUNCTIONAL_ru.md` mirror), `ui/docs/order-composer.md`
|
||||
with the new "Submit pipeline", "Optimistic overlay", and
|
||||
"Server hydration on cache miss" sections.
|
||||
|
||||
Dependencies: Phases 12, 13.
|
||||
|
||||
@@ -1550,19 +1661,23 @@ Acceptance criteria:
|
||||
|
||||
- the user can select a planet, click `Rename`, type a new name, see
|
||||
the command appear in the order tab, click `Submit`, and observe the
|
||||
planet's name change everywhere within one second;
|
||||
- attempting an empty or invalid name is blocked locally (button
|
||||
disabled with tooltip);
|
||||
- a server-side rejection (race condition) is surfaced as `rejected`
|
||||
status in the order tab.
|
||||
planet's name change everywhere within one second (overlay applies
|
||||
immediately on the inspector / mobile sheet / map; server-side state
|
||||
catches up at turn cutoff);
|
||||
- attempting an empty or invalid name is blocked locally (Submit
|
||||
button disabled, inline error message under the input);
|
||||
- a server-side rejection is surfaced as `rejected` status on every
|
||||
in-flight row, with the gateway's error message inline.
|
||||
|
||||
Targeted tests:
|
||||
|
||||
- Vitest unit tests for `submitOrder` with mocked `GalaxyClient`;
|
||||
- Vitest component test for the inline rename editor including
|
||||
validation;
|
||||
- Playwright e2e: rename a seeded planet, reload, confirm the new name
|
||||
persists.
|
||||
- Vitest unit tests for `submitOrder`, `fetchOrder`,
|
||||
`applyOrderOverlay`, `validateEntityName`, and the extended
|
||||
`OrderDraftStore`.
|
||||
- Vitest component tests for the inline rename editor and the
|
||||
Submit button states.
|
||||
- Playwright e2e: rename a seeded planet, reload, confirm the new
|
||||
name persists; rejected path keeps the old name.
|
||||
|
||||
## Phase 15. Inspector — Planet Production Controls
|
||||
|
||||
|
||||
Reference in New Issue
Block a user