Stage 15: dual Telegram bots & language-gated variants
Tests · Go / test (push) Successful in 9s
Tests · Integration / integration (push) Successful in 10s
Tests · UI / test (push) Successful in 20s
Tests · Go / test (pull_request) Successful in 8s
Tests · Integration / integration (pull_request) Successful in 11s
Tests · UI / test (pull_request) Successful in 19s
Tests · Go / test (push) Successful in 9s
Tests · Integration / integration (push) Successful in 10s
Tests · UI / test (push) Successful in 20s
Tests · Go / test (pull_request) Successful in 8s
Tests · Integration / integration (pull_request) Successful in 11s
Tests · UI / test (pull_request) Successful in 19s
Service-agnostic refinement of the owner's idea: the sign-in service returns a set of supported game languages with the user identity, and the lobby gates the New Game variant choice by it (en -> English; ru -> Russian + Эрудит). - Connector hosts two bots in one container (one per service language, each its own token + game channel; the same telegram_id spans both). ValidateInitData tries each token and returns the validating bot's service_language + supported_languages. Per-language config (TELEGRAM_BOT_TOKEN_EN/_RU, channels). - supported_languages rides the Session (fbs, session-scoped, not persisted); the UI offers only the matching variants on New Game — gating only the START of a new game (auto-match + friend invite), not accept/open/play; backend does not enforce. - service_language persisted (accounts.service_language, migration 00010, written every login, last-login-wins) and routes the user-facing Notify push back through the right bot (push-target coalesces with preferred_language). - Admin SendToUser/SendToGameChannel gain an operator-chosen language selector in the console (unrelated to ValidateInitData). - Non-Telegram logins carry the gateway default set (GATEWAY_DEFAULT_SUPPORTED_LANGUAGES, all variants). Wire (committed regen): ValidateInitDataResponse +service_language +supported_languages; Session +supported_languages; SendToUser/SendToGameChannel +language. Docs (ARCHITECTURE/FUNCTIONAL/_ru/READMEs) + PLAN updated; stage marked done.
This commit is contained in:
@@ -1,9 +1,22 @@
|
||||
# scrabble/platform/telegram — Telegram connector
|
||||
|
||||
The Telegram platform side-service. It is the **only** component that holds the bot
|
||||
token: it runs the Bot API long-poll loop (Mini App launch + deep-links) and serves
|
||||
the connector gRPC API that the gateway and backend call over the trusted internal
|
||||
network. See [`docs/ARCHITECTURE.md`](../../docs/ARCHITECTURE.md) §1/§3/§10/§12.
|
||||
tokens: it runs a Bot API long-poll loop **per service language** (Mini App launch +
|
||||
deep-links) and serves the connector gRPC API that the gateway and backend call over
|
||||
the trusted internal network. See
|
||||
[`docs/ARCHITECTURE.md`](../../docs/ARCHITECTURE.md) §1/§3/§10/§12.
|
||||
|
||||
## Service languages (dual bots)
|
||||
|
||||
The connector hosts **one bot per service language** (`en`, `ru`) — each its own
|
||||
token + game channel, configured by the `*_EN` / `*_RU` env vars; at least one is
|
||||
required. The **same Telegram user id spans both bots**. `ValidateInitData` tries
|
||||
each bot's token in turn (none validates ⇒ invalid) and reports which bot validated:
|
||||
its **`service_language`** (persisted by the backend to route the user's later push)
|
||||
and its **`supported_languages`** set (which the UI gates the New Game variant choice
|
||||
by — `en` → English, `ru` → Russian + Эрудит). The user-facing `Notify` routes by the
|
||||
recipient's persisted service language; the admin `SendToUser` / `SendToGameChannel`
|
||||
route by an **operator-chosen** `language` (unrelated to login).
|
||||
|
||||
## Responsibilities
|
||||
|
||||
@@ -13,7 +26,8 @@ network. See [`docs/ARCHITECTURE.md`](../../docs/ARCHITECTURE.md) §1/§3/§10/
|
||||
backend internal API — so the bot token never leaves this process.
|
||||
- **Out-of-app push.** `Notify` renders a backend push event (your_turn, nudge,
|
||||
match_found, and the invitation / friend_request notify sub-kinds) into a
|
||||
localized message with a Mini App launch button and sends it. The gateway calls it
|
||||
localized message with a Mini App launch button and sends it **through the bot for
|
||||
the request's `language`** (the recipient's service language). The gateway calls it
|
||||
**only** for a recipient with no live in-app stream and the
|
||||
`notifications_in_app_only` flag off, so the platform push never duplicates in-app
|
||||
delivery.
|
||||
@@ -21,7 +35,8 @@ network. See [`docs/ARCHITECTURE.md`](../../docs/ARCHITECTURE.md) §1/§3/§10/
|
||||
launch button; a deep-link payload routes the launch to a game / invitation /
|
||||
friend code.
|
||||
- **Admin messaging** (wired in Stage 10). `SendToUser` and `SendToGameChannel` send
|
||||
arbitrary text to one user or the configured game channel.
|
||||
arbitrary text to one user or a game channel through the bot the request selects by
|
||||
`language` (an operator choice in the admin console).
|
||||
|
||||
The generic methods (`Notify`, `SendToUser`, `SendToGameChannel`) address a
|
||||
recipient by the identity `external_id` (as in the backend `identities` table), so a
|
||||
@@ -56,12 +71,14 @@ The bot turns a `/start <payload>` or a notification target into a launch-button
|
||||
|
||||
| Env var | Default | Meaning |
|
||||
| --- | --- | --- |
|
||||
| `TELEGRAM_BOT_TOKEN` | — (required) | Bot API token + the initData HMAC secret |
|
||||
| `TELEGRAM_MINIAPP_URL` | — (required) | Mini App HTTPS origin (BotFather-registered) |
|
||||
| `TELEGRAM_BOT_TOKEN_EN` | — | English bot's API token + initData HMAC secret |
|
||||
| `TELEGRAM_BOT_TOKEN_RU` | — | Russian bot's API token + initData HMAC secret (≥ 1 of EN/RU required) |
|
||||
| `TELEGRAM_GAME_CHANNEL_ID_EN` | — | English bot's game channel chat id for `SendToGameChannel` |
|
||||
| `TELEGRAM_GAME_CHANNEL_ID_RU` | — | Russian bot's game channel chat id |
|
||||
| `TELEGRAM_MINIAPP_URL` | — (required) | Mini App HTTPS origin, shared by all bots (BotFather-registered) |
|
||||
| `TELEGRAM_GRPC_ADDR` | `:9091` | connector gRPC listen address |
|
||||
| `TELEGRAM_API_BASE_URL` | `https://api.telegram.org` | Bot API host override (mock / self-hosted) |
|
||||
| `TELEGRAM_TEST_ENV` | `false` | route to the Bot API **test environment** (`/bot<token>/test/METHOD`) |
|
||||
| `TELEGRAM_GAME_CHANNEL_ID` | — | game channel chat id for `SendToGameChannel` |
|
||||
| `TELEGRAM_LOG_LEVEL` | `info` | zap log level |
|
||||
| `TELEGRAM_SERVICE_NAME` | `scrabble-telegram` | OpenTelemetry `service.name` |
|
||||
| `TELEGRAM_OTEL_TRACES_EXPORTER` | `none` | `none`, `stdout` or `otlp` (gRPC; endpoint from `OTEL_EXPORTER_OTLP_*`) |
|
||||
@@ -76,7 +93,7 @@ builds `<host>/bot<token>/<method>`).
|
||||
```sh
|
||||
go build ./platform/telegram/...
|
||||
go test ./platform/telegram/... # unit tests use an httptest fake Bot API
|
||||
go run ./platform/telegram/cmd/telegram # needs a real TELEGRAM_BOT_TOKEN
|
||||
go run ./platform/telegram/cmd/telegram # needs a real TELEGRAM_BOT_TOKEN_EN or _RU
|
||||
```
|
||||
|
||||
## Deploy
|
||||
|
||||
Reference in New Issue
Block a user