Round-6 follow-up: UX polish + client-IP fix #26

Merged
developer merged 8 commits from feature/ux-polish-ipfix into development 2026-06-08 21:40:13 +00:00
Owner

Follow-up to the round-6 batch (single PR → one deploy). #4 and #5 are deferred to the next PR as agreed.

(3) Client IP — the admin Messages list showed 172.18.0.3 (the docker-network caddy hop), not the real client. The compose caddy (Caddy 2.7+) wasn't trusting the host caddy's X-Forwarded-For. Fix: trusted_proxies static private_ranges in deploy/caddy/Caddyfile — test contour trusts the private-IP host caddy → real client IP; prod (no host caddy) clients are public → untrusted → real peer used, so the one config is correct and spoof-safe in both. This also fixes the gateway's per-IP rate limiter, which was bucketing on the same hop. peerIP unit-tested; Caddyfile validated.

(2) Ad banner gated off behind a compile-time SHOW_AD_BANNER=false — the {#if} branch, the AdBanner import and banner.ts are tree-shaken out of the prod bundle (verified); code kept for later.

(8) Landing Telegram entry → just the 64px logo (clickable, no button/caption).

(9) TG-fullscreen header → title + menu as a centred pair (hamburger right of the title), pinned to the bottom of the TG nav band.

(6) Edge-swipe back → a left-edge rightward drag navigates back (touch/pen only, armed from ≤24px so it never fights the board; skipped inside Telegram).

(7) Chat soft-keyboard → a bottom-sheet Modal lifted above the keyboard by a visualViewport-driven transform (compositor-only — the board behind and the sheet no longer relayout). iOS-specific; needs on-device fine-tuning. Native Keyboard.setResizeMode('none') awaits Capacitor (not wired yet).

(1) Tests backfilled for the merged round-6 work: e2e for the in-game "✓ in friends" item + a board→board tile relocation; codec units for last_activity_unix + OutgoingRequestList.

Green locally: gofmt/build/vet, gateway tests; svelte-check 0, 116 unit, 64 e2e, build (banner tree-shaken).

Follow-up to the round-6 batch (single PR → one deploy). #4 and #5 are deferred to the next PR as agreed. **(3) Client IP** — the admin Messages list showed `172.18.0.3` (the docker-network caddy hop), not the real client. The **compose caddy** (Caddy 2.7+) wasn't trusting the host caddy's `X-Forwarded-For`. Fix: `trusted_proxies static private_ranges` in `deploy/caddy/Caddyfile` — test contour trusts the private-IP host caddy → real client IP; **prod (no host caddy)** clients are public → untrusted → real peer used, so the one config is correct **and spoof-safe** in both. This also fixes the gateway's **per-IP rate limiter**, which was bucketing on the same hop. `peerIP` unit-tested; Caddyfile validated. **(2) Ad banner** gated off behind a compile-time `SHOW_AD_BANNER=false` — the `{#if}` branch, the `AdBanner` import and `banner.ts` are **tree-shaken out of the prod bundle** (verified); code kept for later. **(8) Landing** Telegram entry → just the **64px logo** (clickable, no button/caption). **(9) TG-fullscreen header** → title + menu as a **centred pair** (hamburger right of the title), pinned to the **bottom** of the TG nav band. **(6) Edge-swipe back** → a left-edge rightward drag navigates back (touch/pen only, armed from ≤24px so it never fights the board; skipped inside Telegram). **(7) Chat soft-keyboard** → a **bottom-sheet** `Modal` lifted above the keyboard by a `visualViewport`-driven `transform` (compositor-only — the board behind and the sheet no longer relayout). iOS-specific; **needs on-device fine-tuning**. Native `Keyboard.setResizeMode('none')` awaits Capacitor (not wired yet). **(1) Tests backfilled** for the merged round-6 work: e2e for the in-game **"✓ in friends"** item + a **board→board** tile relocation; codec units for `last_activity_unix` + `OutgoingRequestList`. Green locally: gofmt/build/vet, gateway tests; svelte-check 0, **116 unit**, **64 e2e**, build (banner tree-shaken).
developer added 1 commit 2026-06-08 19:32:04 +00:00
Round-6 follow-up: UX polish + client-IP fix
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 32s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m8s
645df52c0b
- Client IP: the compose caddy trusts X-Forwarded-For from private-range
  upstreams (trusted_proxies private_ranges), so the real client IP survives
  the host-caddy hop (it was logging the docker caddy hop 172.18.0.x for chat
  moderation and bucketing the gateway per-IP rate limiter on it). Correct and
  spoof-safe in both contours (prod has no host caddy); peerIP unit-tested.
- Ad banner gated off behind a compile-time SHOW_AD_BANNER=false (the if-branch,
  the AdBanner import and banner.ts are tree-shaken out of the prod bundle).
- Landing: the Telegram entry is just the 64px logo (clickable, no button/text).
- TG-fullscreen header: title + menu centred as a pair (hamburger right of the
  title), pinned to the bottom of the TG nav band.
- Edge-swipe back (Screen): a left-edge rightward drag navigates to back
  (touch/pen only, armed from <=24px; skipped inside Telegram).
- Chat soft-keyboard: a bottom-sheet Modal lifted above the keyboard by a
  visualViewport-driven transform (compositor-only, no page/sheet relayout).
  iOS-specific, needs on-device tuning; native resize=none awaits Capacitor.
- Tests: e2e for the in-game '✓ in friends' item and a board→board tile
  relocation; codec units for last_activity_unix + OutgoingRequestList.

Deferred to the next PR (agreed): #4 enrich the your-turn/game-end push; #5 hide
finished games from the lobby.
developer added 1 commit 2026-06-08 20:01:46 +00:00
Review fixes: swipe (capture-phase, enabled in TG), TG header aligns to the nav band, DnD zoom delay 1s->0.7s
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 32s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m8s
7e34897d6d
- Edge-swipe back now listens at the window in the CAPTURE phase (the board's
  pointer handlers can't swallow it) and is no longer skipped inside Telegram
  (where the owner tests it).
- TG-fullscreen header: expose the device safe-area top (--tg-safe-top) and
  centre the title + menu pair within Telegram's nav band ([safe-top,
  content-top]) below the notch, keeping the band's height — lining up with
  Telegram's own controls.
- DnD auto-zoom-on-hover delay reduced 1000ms -> 700ms.

(Client-IP: diagnosed as the owner's home-router SNAT — the host caddy already
receives 192.168.0.1 with no XFF, so the real IP is lost upstream of our stack;
correct in prod. No code change.)
developer added 1 commit 2026-06-08 20:07:35 +00:00
Admin Messages: CSV export of the whole filtered list
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 33s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m14s
c96d714fec
A right-aligned 'Export CSV ↓' link in the filter row downloads /_gm/messages.csv
with the active filters (game / sender / name / ext masks), exporting every matching
message (capped at 100k) regardless of the page window — columns time, source,
sender_id, sender, ip, message, game_id.
developer added 1 commit 2026-06-08 20:09:28 +00:00
Admin Messages CSV: defuse spreadsheet formula injection
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 13s
CI / ui (pull_request) Successful in 33s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m15s
461e330bfc
The sender name and message body are user-controlled; a leading =, +, -, @, tab or
CR in the CSV export would execute as a formula when a moderator opens it in a
spreadsheet. csvSafe() prefixes such values with a single quote. Unit-tested.
developer added 1 commit 2026-06-08 20:10:45 +00:00
TG-fullscreen header: +6px band height so native controls aren't flush (owner tweak)
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 12s
CI / ui (pull_request) Successful in 33s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 2m14s
a132edd40a
developer added 1 commit 2026-06-08 20:22:45 +00:00
TG-fullscreen header: add height via padding (min-height wasn't binding), +12px breathing room
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 12s
CI / ui (pull_request) Successful in 33s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m10s
295e45486d
developer added 1 commit 2026-06-08 21:23:07 +00:00
Chat + word-check as their own screens; in-game unread badge (review item 7)
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 14s
CI / ui (pull_request) Successful in 34s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m6s
70110effd9
- Chat and word-check are now routed screens (/game/:id/chat, /game/:id/check) with a
  header back to the game and no tab-bar, replacing their modals. The soft keyboard just
  resizes the visible viewport (tracked into --vvh, which the Screen height uses since iOS
  does not shrink dvh for the keyboard) with the input pinned to the bottom: no modal
  relayout, no page jump. Supersedes the earlier bottom-sheet Modal attempt.
- A new chat message raises an unread badge on the in-game hamburger + the Chat menu row
  (per game, cleared on opening the chat), mirroring the lobby badge.
- TG native back + the header back chevron return chat/check to their game.
- Exposes --tg-safe-top (device notch) for the finalised TG-fullscreen header.

Tests: e2e for chat/check opening as their own screens + back. Docs: PLAN, FUNCTIONAL(+ru).
owner approved these changes 2026-06-08 21:30:22 +00:00
Dismissed
developer added 1 commit 2026-06-08 21:37:02 +00:00
Fix screen-slide direction: by route depth, so back from chat/check slides back
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 8s
CI / integration (pull_request) Successful in 12s
CI / ui (pull_request) Successful in 35s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m7s
a84e9d8cb7
The 'lobby is back' rule slid the chat/check back-to-the-game forward. Direction is now
computed from route depth (lobby < game < chat/check): shallower = back, deeper = forward.
developer dismissed owner's review 2026-06-08 21:37:02 +00:00
Reason:

New commits pushed, approval review dismissed automatically according to repository settings

owner approved these changes 2026-06-08 21:37:43 +00:00
developer merged commit a7c566d2d1 into development 2026-06-08 21:40:13 +00:00
developer deleted branch feature/ux-polish-ipfix 2026-06-08 21:40:13 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#26