// FlatBuffers payloads for the client <-> gateway edge transport (Stage 6). // // Every request and response that rides inside the Connect envelope // (gateway/proto/edge) `payload` field, and every push Event payload, is one of // these tables. They are the binary wire contract shared with the UI, which // generates TypeScript from this same schema (Stage 7). A single namespace keeps // nested tables (GameView inside MoveResult / MatchResult) free of // cross-namespace imports. Keep this schema and the backend JSON DTOs in lockstep // — the gateway transcodes one to the other. // // Generate Go with `make fbs` (flatc, version-pinned). The committed output lives // in fbs/scrabblefb/. namespace scrabblefb; // --- shared building blocks --- // TileRecord is one placed (or to-place) tile: its board coordinate, the concrete // letter ("?" when read from a hand for a blank) and whether it came from a blank. table TileRecord { row:int; col:int; letter:string; blank:bool; } // SeatView is one seat's public standing in a game. display_name is resolved by the // backend from the account store (added trailing — backward-compatible). table SeatView { seat:int; account_id:string; score:int; hints_used:int; is_winner:bool; display_name:string; } // GameView is the shared (non-private) game summary. table GameView { id:string; variant:string; dict_version:string; status:string; players:int; to_move:int; turn_timeout_secs:int; move_count:int; end_reason:string; seats:[SeatView]; } // MoveRecord is one decoded move (a committed play, or a hint preview). table MoveRecord { player:int; action:string; dir:string; main_row:int; main_col:int; tiles:[TileRecord]; words:[string]; count:int; score:int; total:int; } // --- auth (unauthenticated) --- // TelegramLoginRequest carries the platform launch data; the gateway validates // its HMAC before forwarding the extracted identity to the backend. table TelegramLoginRequest { init_data:string; } // GuestLoginRequest bootstraps an ephemeral guest session. locale is an optional // preferred-language hint. table GuestLoginRequest { locale:string; } // EmailRequestRequest asks the backend to send a login confirm-code to email. table EmailRequestRequest { email:string; } // EmailLoginRequest logs in (or provisions) the account owning email, verifying // the confirm-code. table EmailLoginRequest { email:string; code:string; } // Session is the minted credential returned by every auth operation. table Session { token:string; user_id:string; is_guest:bool; display_name:string; } // Ack is a simple success acknowledgement (e.g. an email-code request). table Ack { ok:bool; } // --- profile (authenticated) --- // Profile is the authenticated account's own profile view. away_start/away_end are // 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; preferred_language:string; time_zone:string; hint_balance:int; block_chat:bool; block_friend_requests:bool; is_guest:bool; away_start:string; away_end:string; notifications_in_app_only:bool = true; } // --- game (authenticated) --- // SubmitPlayRequest places tiles in a direction on the player's turn. table SubmitPlayRequest { game_id:string; dir:string; tiles:[TileRecord]; } // MoveResult is the outcome of a committed move: the move and the post-move game. table MoveResult { move:MoveRecord; game:GameView; } // StateRequest asks for the requesting player's view of a game. table StateRequest { game_id:string; } // StateView is a player's view of a game: the shared summary plus their private // rack, the bag size and their remaining hint budget. table StateView { game:GameView; seat:int; rack:[string]; bag_len:int; hints_remaining:int; } // GameActionRequest carries just a game id (pass / resign / hint / history). table GameActionRequest { game_id:string; } // ExchangeRequest swaps the listed rack tiles back into the bag. table ExchangeRequest { game_id:string; tiles:[string]; } // EvalRequest previews a tentative play without committing it. table EvalRequest { game_id:string; dir:string; tiles:[TileRecord]; } // EvalResult is an unlimited move preview: legality, score and the words formed. table EvalResult { legal:bool; score:int; words:[string]; } // CheckWordRequest looks a word up in the game's pinned dictionary. table CheckWordRequest { game_id:string; word:string; } // WordCheckResult is the dictionary lookup outcome. table WordCheckResult { word:string; legal:bool; } // ComplaintRequest disputes a word-check result. table ComplaintRequest { game_id:string; word:string; note:string; } // HintResult is the top-ranked move plus the remaining hint budget. table HintResult { move:MoveRecord; hints_remaining:int; } // History is a game's decoded move journal — the source for client board replay. table History { game_id:string; moves:[MoveRecord]; } // GameList is the caller's games (active and finished) for the lobby. table GameList { games:[GameView]; } // --- lobby (authenticated) --- // EnqueueRequest joins the per-variant auto-match pool. table EnqueueRequest { variant:string; } // MatchResult reports whether the caller has been paired into a game yet. table MatchResult { matched:bool; game:GameView; } // --- chat (authenticated) --- // ChatPostRequest posts a per-game chat message. table ChatPostRequest { game_id:string; body:string; } // ChatMessage is one stored chat message or nudge. table ChatMessage { id:string; game_id:string; sender_id:string; kind:string; body:string; created_at_unix:long; } // ChatList is a game's chat history. table ChatList { messages:[ChatMessage]; } // --- Stage 8: account, statistics, friends, blocks, invitations, history --- // AccountRef is a referenced account with its display name resolved — the shared // shape for friends, blocked users and invitation participants. table AccountRef { account_id:string; display_name:string; } // 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; time_zone:string; away_start:string; away_end:string; block_chat:bool; block_friend_requests:bool; notifications_in_app_only:bool = true; } // --- account linking & merge (Stage 11, authenticated) --- // LinkEmailRequest mails a confirm-code to email for a later link or merge. The // code is always sent (no pre-send "taken" signal), so a probe cannot enumerate // registered addresses. table LinkEmailRequest { email:string; } // LinkEmailConfirm carries the email and its confirm code, for both the confirm // (preview) and the explicit merge step. table LinkEmailConfirm { email:string; code:string; } // LinkTelegramRequest carries Telegram Login Widget data (a URL query string) for // attaching a Telegram identity to the current account. table LinkTelegramRequest { data:string; } // LinkResult is the unified result of a confirm or merge step. status is "linked" // (bound to the caller), "merge_required" (the identity belongs to another account — // the secondary_* fields summarise it for the irreversible confirmation), or // "merged" (done). session is present only when the active account switched (a guest // initiator whose durable counterpart won) — the client adopts it. table LinkResult { status:string; secondary_user_id:string; secondary_display_name:string; secondary_games:int; secondary_friends:int; session:Session; } // StatsView is a durable account's lifetime statistics (games-played and win-rate // are derived client-side). table StatsView { wins:int; losses:int; draws:int; max_game_points:int; max_word_points:int; } // TargetRequest names a single counterpart account (friend request/cancel/unfriend, // block/unblock). table TargetRequest { account_id:string; } // FriendRespondRequest accepts or declines a pending request from a requester. table FriendRespondRequest { requester_id:string; accept:bool; } // FriendList is the caller's accepted friends. table FriendList { friends:[AccountRef]; } // IncomingRequestList is the friend requests awaiting the caller's response. table IncomingRequestList { requests:[AccountRef]; } // FriendCode is a freshly issued one-time add-a-friend code (returned once). table FriendCode { code:string; expires_at_unix:long; } // RedeemCodeRequest redeems a friend code, befriending its issuer. table RedeemCodeRequest { code:string; } // RedeemResult reports the new friend gained by redeeming a code. table RedeemResult { friend:AccountRef; } // BlockList is the accounts the caller has blocked. table BlockList { blocked:[AccountRef]; } // InvitationInvitee is one invitee's seat and response, name resolved. table InvitationInvitee { account_id:string; display_name:string; seat:int; response:string; } // Invitation is a friend-game invitation with its settings and invitees. table Invitation { id:string; inviter:AccountRef; invitees:[InvitationInvitee]; variant:string; turn_timeout_secs:int; hints_allowed:bool; hints_per_player:int; dropout_tiles:string; status:string; game_id:string; expires_at_unix:long; } // CreateInvitationRequest proposes a 2-4 player friend game to the named invitees. table CreateInvitationRequest { invitee_ids:[string]; variant:string; turn_timeout_secs:int; hints_allowed:bool; hints_per_player:int; dropout_tiles:string; } // InvitationActionRequest accepts / declines / cancels an invitation by id. table InvitationActionRequest { invitation_id:string; } // InvitationList is the caller's open invitations. table InvitationList { invitations:[Invitation]; } // GcgExport is a finished game's GCG transcript: a suggested filename and the text. table GcgExport { game_id:string; filename:string; content:string; } // --- push event payloads --- // YourTurnEvent signals that it is now the recipient's turn. table YourTurnEvent { game_id:string; deadline_unix:long; } // OpponentMovedEvent summarises a move another seat just committed; the client // refetches the full state. table OpponentMovedEvent { game_id:string; seat:int; action:string; score:int; total:int; } // NudgeEvent signals that a player nudged the recipient. table NudgeEvent { game_id:string; from_user_id:string; } // MatchFoundEvent signals that an auto-match pairing (or robot substitution) // started a game the recipient is seated in. table MatchFoundEvent { game_id:string; } // NotificationEvent is a lightweight "something changed, re-poll" signal that // drives the lobby badge (incoming friend requests, invitations). kind is a sub- // discriminator ("friend_request", "friend_added", "invitation", "game_started"); // the client re-fetches its lobby counters on any of them. table NotificationEvent { kind:string; }