Stage 9: Telegram integration (connector side-service, Mini App, out-of-app push)
Tests · Go / test (push) Successful in 7s
Tests · Integration / integration (push) Successful in 12s
Tests · Go / test (pull_request) Successful in 6s
Tests · Integration / integration (pull_request) Successful in 11s
Tests · UI / test (pull_request) Successful in 19s
Tests · Go / test (push) Successful in 7s
Tests · Integration / integration (push) Successful in 12s
Tests · Go / test (pull_request) Successful in 6s
Tests · Integration / integration (pull_request) Successful in 11s
Tests · UI / test (pull_request) Successful in 19s
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.
This commit is contained in:
@@ -104,7 +104,9 @@ table Ack {
|
||||
// --- profile (authenticated) ---
|
||||
|
||||
// Profile is the authenticated account's own profile view. away_start/away_end are
|
||||
// the "HH:MM" daily away-window bounds (added trailing — backward-compatible).
|
||||
// the "HH:MM" daily away-window bounds. notifications_in_app_only (default true)
|
||||
// suppresses out-of-app platform push, leaving only the in-app live stream (both
|
||||
// added trailing — backward-compatible).
|
||||
table Profile {
|
||||
user_id:string;
|
||||
display_name:string;
|
||||
@@ -116,6 +118,7 @@ table Profile {
|
||||
is_guest:bool;
|
||||
away_start:string;
|
||||
away_end:string;
|
||||
notifications_in_app_only:bool = true;
|
||||
}
|
||||
|
||||
// --- game (authenticated) ---
|
||||
@@ -256,6 +259,8 @@ table AccountRef {
|
||||
|
||||
// UpdateProfileRequest overwrites the full editable profile (the client sends the
|
||||
// complete desired profile). away_start/away_end are "HH:MM" bounds.
|
||||
// notifications_in_app_only (trailing — backward-compatible) toggles out-of-app
|
||||
// platform push off when set.
|
||||
table UpdateProfileRequest {
|
||||
display_name:string;
|
||||
preferred_language:string;
|
||||
@@ -264,6 +269,7 @@ table UpdateProfileRequest {
|
||||
away_end:string;
|
||||
block_chat:bool;
|
||||
block_friend_requests:bool;
|
||||
notifications_in_app_only:bool = true;
|
||||
}
|
||||
|
||||
// EmailBindRequest asks the backend to send a confirm-code binding email to the
|
||||
|
||||
@@ -137,8 +137,20 @@ func (rcv *Profile) AwayEnd() []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (rcv *Profile) NotificationsInAppOnly() bool {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(24))
|
||||
if o != 0 {
|
||||
return rcv._tab.GetBool(o + rcv._tab.Pos)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (rcv *Profile) MutateNotificationsInAppOnly(n bool) bool {
|
||||
return rcv._tab.MutateBoolSlot(24, n)
|
||||
}
|
||||
|
||||
func ProfileStart(builder *flatbuffers.Builder) {
|
||||
builder.StartObject(10)
|
||||
builder.StartObject(11)
|
||||
}
|
||||
func ProfileAddUserId(builder *flatbuffers.Builder, userId flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(userId), 0)
|
||||
@@ -170,6 +182,9 @@ func ProfileAddAwayStart(builder *flatbuffers.Builder, awayStart flatbuffers.UOf
|
||||
func ProfileAddAwayEnd(builder *flatbuffers.Builder, awayEnd flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(9, flatbuffers.UOffsetT(awayEnd), 0)
|
||||
}
|
||||
func ProfileAddNotificationsInAppOnly(builder *flatbuffers.Builder, notificationsInAppOnly bool) {
|
||||
builder.PrependBoolSlot(10, notificationsInAppOnly, true)
|
||||
}
|
||||
func ProfileEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
return builder.EndObject()
|
||||
}
|
||||
|
||||
@@ -105,8 +105,20 @@ func (rcv *UpdateProfileRequest) MutateBlockFriendRequests(n bool) bool {
|
||||
return rcv._tab.MutateBoolSlot(16, n)
|
||||
}
|
||||
|
||||
func (rcv *UpdateProfileRequest) NotificationsInAppOnly() bool {
|
||||
o := flatbuffers.UOffsetT(rcv._tab.Offset(18))
|
||||
if o != 0 {
|
||||
return rcv._tab.GetBool(o + rcv._tab.Pos)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (rcv *UpdateProfileRequest) MutateNotificationsInAppOnly(n bool) bool {
|
||||
return rcv._tab.MutateBoolSlot(18, n)
|
||||
}
|
||||
|
||||
func UpdateProfileRequestStart(builder *flatbuffers.Builder) {
|
||||
builder.StartObject(7)
|
||||
builder.StartObject(8)
|
||||
}
|
||||
func UpdateProfileRequestAddDisplayName(builder *flatbuffers.Builder, displayName flatbuffers.UOffsetT) {
|
||||
builder.PrependUOffsetTSlot(0, flatbuffers.UOffsetT(displayName), 0)
|
||||
@@ -129,6 +141,9 @@ func UpdateProfileRequestAddBlockChat(builder *flatbuffers.Builder, blockChat bo
|
||||
func UpdateProfileRequestAddBlockFriendRequests(builder *flatbuffers.Builder, blockFriendRequests bool) {
|
||||
builder.PrependBoolSlot(6, blockFriendRequests, false)
|
||||
}
|
||||
func UpdateProfileRequestAddNotificationsInAppOnly(builder *flatbuffers.Builder, notificationsInAppOnly bool) {
|
||||
builder.PrependBoolSlot(7, notificationsInAppOnly, true)
|
||||
}
|
||||
func UpdateProfileRequestEnd(builder *flatbuffers.Builder) flatbuffers.UOffsetT {
|
||||
return builder.EndObject()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user