Files
galaxy-game/ui/PLAN-finalize.md
T
Ilia Denisov 53fb4f5f76 docs(ui): finalize docs sync — README finalized-web summary + topic links (F7)
The de-archaeology and the ui/docs index landed in the earlier reorg
(0 "Phase N" refs in ui/docs/; 24 topic docs linked). This finishes the
sync: ui/README.md gains a finalized-web-target summary and links the new
topic docs (design-system, a11y, error-state-ux, pwa-strategy).
docs/ARCHITECTURE.md and docs/FUNCTIONAL.md need no change — they cover
the backend/gateway/cross-service contracts with no stale UI statements;
the finalized UI is client-local UX documented under ui/docs/. Marks F7
done.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 16:06:27 +02:00

9.9 KiB
Raw Blame History

UI Client — Finalization Plan

The MVP web client (Phases 130, PLAN.md) is functionally complete. This plan finalizes the web experience — visual consistency, accessibility, localisation, error UX, installability, and documentation — before the native platform wrappers in ROADMAP.md. It absorbs the original Phases 33 (PWA) and 35 (Polish), which were pulled forward to here.

This is a finalization pass, not the final word. After it ships, the owner exercises the whole UI by hand and brings small-nuance fixes; the last stage (F8) is an explicit, open-ended owner-driven refinement loop. The earlier stages are "done" when their acceptance holds; the feature set is "final" only when the owner signs off.

Each stage ends with a runnable, reviewable artifact and is gated on the per-stage CI rule (push, watch go-unit / ui-test to green) before being marked done.


F1 — Visual design system — done

Merged to development via PR #26 (2026-05-22): a shared design-token system (ui/frontend/src/lib/theme/), light/dark theming with a picker and pre-paint guard, and the whole UI migrated onto the tokens. Documented literal exceptions: the battle-scene data-viz palette, overlay scrims, and directional/deliberate drop shadows. The default theme follows the OS (system); the account-menu picker pins light or dark. Tokens and conventions live in ui/docs/design-system.md.

Goal: replace the ad-hoc per-component styling (inline hex colors like #0a0e1a, one-off spacing) with a shared design language so every view looks like one product.

  • ui/frontend/src/lib/theme/ (or app.css :root) design tokens: color palette (surface / border / text / accent / danger), spacing scale, radii, typography, focus-ring style — as CSS custom properties.
  • Migrate components to the tokens (calculator, inspectors, sidebar, tables, lobby, auth) — replace literal hex/px with var(--…).
  • Topic doc ui/docs/design-system.md documenting the tokens and usage.

Acceptance: no literal theme colors left in component <style> blocks (spot-checked); a single token change restyles the app coherently. Consider the frontend-design skill for the palette/spacing pass.

F2 — Accessibility (WCAG 2.2 AA) — done

Shared a11y primitives (.sr-only, .skip-link, trapFocus, restoreFocus, the --color-focus ring), keyboard paths and ARIA across login / lobby / in-game shell (skip links + landmarks, WAI-ARIA sidebar tabs with roving + arrow keys, menu Escape + focus restore, the mail compose modal dialog with a focus trap), and the map canvas handled as a labelled accessible-alternative surface (data via the sidebar/tables). Gated by tests/e2e/a11y-axe.spec.ts (axe WCAG 2.2 AA scan of every top-level view, chromium-desktop, zero violations) and tests/e2e/a11y-keyboard.spec.ts. Documented in ui/docs/a11y.md.

(From Phase 35.) Goal: the whole client is usable by keyboard and assistive tech.

  • Keyboard-only paths for login, lobby, and the in-game shell; visible focus rings (from the F1 token); ARIA labels/roles; screen-reader-only text where needed.
  • ui/docs/a11y.md audit results.

Acceptance: WCAG 2.2 AA on lobby, login, and the in-game shell per an axe-core scan; full keyboard reachability with visible focus. Tests: axe-core integration tests on every top-level view; Playwright keyboard-only navigation.

F3 — Localisation completeness — done

An audit found the client already i18n-first (the single hard-coded UI string, the battle-scene aria-label, is now keyed); en/ru already have identical key sets (692 keys). Added locale persistence to the i18n store (localStorage galaxy-locale: stored choice > browser detection

default) so a switch survives reloads, and tests/i18n-completeness.test.ts enforcing en/ru key-set parity, non-empty values, and persistence. A noisy literal-text lint was deliberately skipped — the structural parity test plus the i18n-first convention cover drift. Docs: ui/docs/i18n.md.

(From Phase 35.) Goal: every visible string is translated (en + ru).

  • Audit all components for hard-coded strings; move them into the i18n bundles; missing-key detection test; locale-switch persistence across reloads.

Acceptance: no untranslated visible strings; missing-translation test is green; locale persists. Tests: Vitest i18n bundle-structure + missing-key detection.

F4 — Error & state UX — done

Central error surface src/lib/error/ (classify any error into a stable ErrorKind from the transport signal; map to translated error.* messages via reportError toast — sticky + Retry for retryable kinds — or errorMessageKey for inline). Shared ViewState placeholder (loading/empty/error with a11y roles), adopted by the entity tables. Selected-planet ring on the map (map/selection-ring.ts, fed into buildExtras). Bottom-sheet tap-outside + swipe-down dismissal (lib/ui/sheet-dismiss.ts, hand-rolled pointer events). Error-surface and ViewState adoption continue incrementally across the remaining views. Docs: ui/docs/error-state-ux.md.

(From Phase 35, plus the deferred Phase 13/35 items.) Goal: consistent, actionable feedback everywhere.

  • ui/frontend/src/lib/error/ central error surface with stable codes and retry/escalation guidance; every server-side error mapped to a translated, actionable message (en/ru).
  • Consistent empty / loading / error states across views.
  • Selected-planet visual on the map (ring/halo) off the SelectionStore (deferred from Phase 35).
  • Mobile bottom-sheet swipe-down + tap-outside dismissal (deferred from Phase 13/35).

Acceptance: every server error → a translated actionable message; consistent empty/loading/error states; the selected planet is visually marked.

F5 — PWA (was Phase 33) — done

Installable, offline-tolerant PWA on SvelteKit's native service worker (src/service-worker.ts): a version-keyed cache precaches the shell, build artefacts (incl. core.wasm), and static files; activate purges old caches; the gateway is never intercepted. Adds static/manifest.webmanifest, a generated placeholder icon set (scripts/gen-pwa-icons.mjs, dependency-free), and the manifest / theme-color / apple-touch tags in app.html. Gated by Playwright against a production preview (pnpm test:pwa, wired into ui-test): manifest + installable icons, SW registration + single version-keyed cache, and offline shell load. Docs: ui/docs/pwa-strategy.md.

Acceptance correction: "Lighthouse PWA ≥ 90" is dropped — Lighthouse removed the PWA category in v12 (current line 13.x), so it is no longer a valid gate; the Playwright checks verify the same install/offline behaviour directly.

Goal: the web build is installable and offline-tolerant. Depends on F6 (wasm in CI) so the service worker caches a freshly-built artefact.

  • ui/frontend/src/service-worker.ts cache-first assets with stale-invalidation on app update; manifest.webmanifest; ui/frontend/static/icons/ web icon set; ui/docs/pwa-strategy.md.

Acceptance: installs as a PWA on Chrome, Edge, and iOS Safari; the SW survives an app update without serving stale code. Tests: Lighthouse PWA ≥ 90; Playwright install→offline→cached-login; version-bump invalidation.

F6 — Build hygiene: build core.wasm in CI — done

core.wasm / wasm_exec.js are no longer committed (untracked + gitignored). A reusable composite action .gitea/actions/build-wasm installs TinyGo (actions/cached) and runs make -C ui wasm; it is invoked by all three frontend-building workflows — ui-test (before Playwright; Vitest needs no build, it uses the fake Core), dev-deploy, and prod-build (which build the bundle on the runner via pnpm build, then package it). ui-test gained a Go setup; the deploy workflows already had one. Docs: ui/docs/wasm-toolchain.md, ui/README.md.

(From the PLAN.md TODO; timely — the binary is currently committed and must be rebuilt by hand on every Go-bridge change, which has already bitten us.) Goal: stop shipping the binary in git.

  • Install TinyGo on the gitea Actions runner (Linux tarball / curl … | tar -xz, since brew is macOS-only); add make -C ui wasm ahead of the Vitest step in .gitea/workflows/ui-test.yaml.
  • Remove ui/frontend/static/core.wasm and wasm_exec.js from the repo and re-tighten ui/.gitignore.

Acceptance: CI builds the wasm and Vitest/Playwright pass against the freshly built artefact; the binaries are no longer tracked.

F7 — Documentation finalization — done

The de-archaeology + the ui/docs/README.md index landed in the earlier docs reorganization (PR #25): ui/docs/ has 0 stray "Phase N" references and the index links all 24 topic docs (each F1F6 stage also added/updated its own topic doc). This stage finished the sync: ui/README.md gains a finalized-web-target summary and links the new topic docs (design-system, a11y, error-state-ux, pwa-strategy). docs/ARCHITECTURE.md and docs/FUNCTIONAL.md need no change — they cover the backend / gateway / cross-service contracts and carry no stale UI statements; the finalized UI is client-local UX documented under ui/docs/.

Goal: living docs read as current state, not build archaeology.

  • De-archaeologize the 20 ui/docs/ topic docs: strip "Phase N adds…" history, rewrite as present-tense descriptions of how things work.
  • ui/docs/README.md index (added during this reorganization).
  • Sync ui/README.md, docs/ARCHITECTURE.md, and docs/FUNCTIONAL.md (+ _ru mirror) with the finalized UI.

Acceptance: no stray "Phase N" references in ui/docs/; the index links every topic doc; READMEs/ARCHITECTURE describe current state.

F8 — Owner manual-QA refinement loop

Open-ended, owner-driven. The owner exercises the whole UI by hand and files small-nuance fixes; each is folded in as it surfaces. There is no fixed acceptance gate here — finalization is "done" when the owner signs off and the client moves on to the ROADMAP platform wrappers.