Stage 17 round 6 (#16-20): landing page, /app/ move, cache + stream fixes
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 11s
CI / ui (pull_request) Successful in 31s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 55s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 11s
CI / ui (pull_request) Successful in 31s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 55s
Close out Stage 17 round 6: - Landing page at / — one Vite build with two entries (index.html = game SPA, landing.html = a lightweight landing reusing the theme/i18n/ aboutContent leaf modules, not the app store). - Move the web game SPA to /app/; the Telegram Mini App stays at /telegram/ (gateway webui.Handler(stripPrefix, indexName): landing at /, SPA at /app/ + /telegram/). Per-language "Play in Telegram" link via new VITE_TELEGRAM_LINK_EN/_RU build vars (button hides when unset). - Cache headers: hash-named /assets/* immutable, HTML shells no-cache (the go:embed zero modtime emitted no validators, so the client re-downloaded the whole bundle every launch). - Live-stream 15s abort fix: an immediate heartbeat on open + a 10s default interval (the first tick at 15s raced the edge idle timeout -> reconnect storm). PLAN/ARCHITECTURE(§13)/FUNCTIONAL(+ru)/gateway+ui+deploy READMEs updated; round 6 closed. Tests: gateway webui/connectsrv units, ui landing unit + e2e, full e2e (60) green.
This commit is contained in:
@@ -1319,23 +1319,35 @@ provided cert) at the contour caddy; prod VPN; rollback.
|
||||
`game_drafts` table (migration 00011) + raw-SQL store/service (`GetDraft`/`SaveDraft`) that, on every
|
||||
committed move, clears the actor's own draft and resets any opponent's board draft whose cell the play
|
||||
overlapped — 5 integration tests.
|
||||
- **Stage 17 round 6 — REMAINING (next pass), designs ready:**
|
||||
1. **Persistence gateway slice + UI (#4/#5/#6).** *FB (lean):* `DraftRequest{game_id, json}` (save) +
|
||||
a game-id request (get) + `DraftView{json}` — one string field; the client serializes/deserializes
|
||||
`{rack_order, board_tiles}` itself (no FB tile array). Regen Go (`make -C pkg fbs`) + TS
|
||||
(`pnpm codegen`); flatc is pinned **23.5.26** (the local one matches). *Gateway* forwards the JSON as
|
||||
`json.RawMessage` (no double-encode). *REST:* `GET`/`PUT /games/:id/draft` (decodes `game.Draft`).
|
||||
*UI:* save the rack order (#4) and board draft (#6) on change (debounced) and restore on load
|
||||
(next to `gameState`); **#5** — allow placing tiles on the opponent's turn (relax the `isMyTurn`
|
||||
gate on placement only; the evaluate-preview and Make-move stay your-turn-only, so an off-turn draft
|
||||
is position-only — never scored/submitted).
|
||||
2. **Landing + `/app/` move (#16–20).** An extra Svelte page at `/`, the game SPA under `/app/` (Vite
|
||||
`base` conditional: `/app/` for web, `./` for Capacitor); the gateway serves the landing at `/` and
|
||||
the SPA at `/app/*`; a bundled Telegram logo (from `.claude/telegram-logo.svg`, **copied into
|
||||
`ui/public/`, the reference itself not committed**) linking to the per-language t.me bot (ru
|
||||
`Erudit_Game` / en `Scrabble_Game`); theme + language switchers reusing the app stores; reuse the
|
||||
`aboutContent` copy. **Note:** moving the game to `/app/` means the Telegram Mini App URL must point
|
||||
to `/app/`.
|
||||
- **Stage 17 round 6 — final pass (#4/#5/#6 + #16–20), shipped:**
|
||||
1. **Draft persistence — gateway slice + UI (#4/#5/#6, PR #20).** FB `DraftRequest{game_id, json}`
|
||||
(save) + `DraftView{json}` (get reuses `GameActionRequest`); the client serializes
|
||||
`{rack_order, board_tiles}` itself (no FB tile array), the gateway forwards it as `json.RawMessage`
|
||||
both ways (no double-encode), and `GET`/`PUT /games/:id/draft` (a server `draftDTO` ↔ `game.Draft`)
|
||||
is the only place that reads the shape. UI: debounced save of the rack order (#4) + board draft (#6)
|
||||
and restore on load (`lib/draft.ts`, reconciling against the committed board); **#5** — tiles may be
|
||||
arranged on the opponent's turn (placement relaxed; the preview and Make-move stay your-turn-only,
|
||||
so an off-turn draft is position-only). Off-turn tiles keep the **existing pending highlight** — no
|
||||
caption, no new style (owner's call). The backend draft endpoint is sub-ms.
|
||||
2. **Landing + `/app/` move (#16–20, this PR).** One Vite build with **two HTML entries** — the game
|
||||
SPA (`index.html`) and a new lightweight landing (`landing.html` → `Landing.svelte`, reusing the
|
||||
theme/i18n/`aboutContent` leaf modules, not the app store, so it stays small). The gateway serves the
|
||||
**landing at `/`** and the **game SPA at `/app/` and `/telegram/`** (`webui.Handler(stripPrefix,
|
||||
indexName)`); relative base keeps one build serving every mount with a shared `dist/assets/` (the
|
||||
planned per-target `base` conditional proved unnecessary). **Correction to the original note:** the
|
||||
Telegram **Mini App stays at `/telegram/`** — only the plain web app moved off `/` to `/app/`, so
|
||||
BotFather is untouched. The landing's "Play in Telegram" link is **per-language** via two new build
|
||||
vars `VITE_TELEGRAM_LINK_EN` / `VITE_TELEGRAM_LINK_RU` (test/prod bots differ → no hardcoding; the
|
||||
button hides when unset). Logo copied `.claude/telegram-logo.svg` → `ui/public/` (source stays
|
||||
untracked).
|
||||
- **Edge robustness (folded into the landing PR).** (a) **Static cache headers** — the embedded
|
||||
`http.FileServer` over `go:embed` has a zero modtime, so it emitted no validators → the client
|
||||
re-downloaded the whole bundle every launch; now hash-named `/assets/*` are `immutable` (a relaunch
|
||||
is a cache hit) and the HTML shells are `no-cache`. (b) **Live-stream 15 s abort** — the `Subscribe`
|
||||
heartbeat only fired after the first 15 s tick, so the stream sat silent and raced a ~15 s edge idle
|
||||
timeout (constant reconnects in the caddy log); now an **immediate heartbeat on open** + a **10 s**
|
||||
default interval. Both surfaced while diagnosing a reported "slow load in Telegram" that was actually
|
||||
the owner's **external network** (the server is sub-ms end-to-end) — not a regression.
|
||||
|
||||
## Deferred TODOs (cross-stage)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user