New platform/telegram connector (own container, bot token only there):
- go-telegram/bot long-poll loop: /start deep-links + Mini App launch button.
- gRPC API pkg/proto/telegram/v1 (Telegram service): ValidateInitData, Notify
(renders a localized message + deep-link button), SendToUser/SendToGameChannel
(admin, wired in Stage 10). Generic methods are platform-agnostic (external_id).
- Bot API base override for Telegram's test environment; Dockerfile + compose
(VPN sidecar, no public ingress); README.
Gateway:
- initData validation relocated from the gateway into the connector; the gateway
calls ValidateInitData over gRPC (GATEWAY_CONNECTOR_ADDR), drops the bot token,
and deletes internal/auth.
- Out-of-app push: runPushPump routes events whose recipient has no live in-app
stream to connector.Notify, gated by /internal/push-target + the in-app-only
flag (race-free de-dup); HasSubscribers added to the push hub.
Backend:
- Migration 00007 accounts.notifications_in_app_only (default true) + jetgen.
- ProvisionTelegram seeds a new account's language/display name from the launch
fields; IdentityExternalID reverse lookup; /internal/push-target handler.
UI:
- Telegram Mini App launch: detect initData, apply themeParams, authTelegram,
route the deep-link start_param (g/i/f); /telegram/ guard redirects outside
Telegram. Vite relative base + telegram-web-app.js. In-app-only profile toggle;
share-to-Telegram link for a friend code. Vitest + Playwright coverage.
Wire/docs/CI: fbs Profile/UpdateProfileRequest gain notifications_in_app_only
(Go + TS); go.work uses ./platform/telegram; go-unit.yaml covers it; PLAN,
ARCHITECTURE, FUNCTIONAL (+ru), UI_DESIGN, READMEs updated.
Owner-review follow-up on the Stage 8 branch:
- Friend code is copyable (📋 + toast). The lobby notification badge is fixed —
it had inherited the hamburger-bar style — into a proper round count dot.
- Safari: min-width:0 on flex text inputs (friend code, profile, chat) so they
shrink instead of pushing the adjacent button off-screen.
- Profile editing is validated on both the UI and the backend: display-name format
(letters joined by single space/./_ separators, no leading/trailing/adjacent
separators, <=32 runes), a UTC-offset timezone picker (account.ResolveZone parses
±HH:MM or a legacy IANA name), a 10-minute away grid capped at 12h (wrap-aware),
and email format; Save is disabled and invalid fields red-bordered until valid.
Language stays in Settings.
- In a game, an "add to friends" menu item flips to a disabled "request sent"; chat
send/nudge became ⬆️/🛎️ icon buttons.
- A finished game drops its last-word highlight, hides Check word / Drop game,
disables zoom, and draws an inert (greyed) footer instead of hiding it.
Tests: account validators (name/away/zone), UI profileValidation, e2e for the
finished-game footer/menu and the copy control. Docs (PLAN, ARCHITECTURE,
FUNCTIONAL +ru, UI_DESIGN) updated for the display-name rule, UTC-offset timezone
and the 12h away window.
Engine: multi-player drop-out-and-continue with a per-game tile disposition (remove default / return), resigned seats skipped and excluded from the win, leaver rack never revealed; 2-player behaviour unchanged.
New domains (service/store, no HTTP yet): internal/social (friend request/accept graph, per-user blocks, per-game chat with nudge as a message kind, content filter via mvdan.cc/xurls/v2 + leet/separator normaliser + phone heuristic) and internal/lobby (in-memory variant-keyed matchmaking pool, friend-game invitations invite->accept with lazy 7-day expiry). account gains profile editing and the email confirm-code flow (Mailer seam: SMTP or log mailer).
Migration 00003_social.sql + regenerated jet. main wires the new services into the server (accessors for the Stage 6 handlers); robot substitution stays in Stage 5, REST/stream/push in Stage 6/8. Docs (PLAN, ARCHITECTURE, FUNCTIONAL+ru, TESTING, README) updated.