Files
galaxy-game/pkg/schema/fbs/diplomail.fbs
T
Ilia Denisov fed282f2d2
Tests · UI / test (push) Has been cancelled
Tests · Go / test (pull_request) Successful in 2m4s
Tests · Go / test (push) Successful in 2m5s
Tests · Integration / integration (pull_request) Successful in 1m54s
Tests · UI / test (pull_request) Successful in 2m50s
Phase 28 (Step 2): FBS schemas + message-type constants for mail
Adds the wire schema for the eight `user.games.mail.*` ConnectRPC
commands together with the shared payload types (`MailMessage`,
`MailRecipientState`, `MailBroadcastReceipt`). Send-request tables
carry the optional `recipient_race_name` introduced in Step 1.

Drops:

- `pkg/schema/fbs/diplomail.fbs` — schema sources;
- `pkg/schema/fbs/diplomail/*.go` — generated Go bindings (flatc
  `--go --go-module-name galaxy/schema/fbs`);
- `pkg/model/diplomail/diplomail.go` — message-type catalog used by
  the gateway router;
- `ui/frontend/src/proto/galaxy/fbs/diplomail/*.ts` — generated TS
  bindings consumed by the upcoming UI client wrapper;
- `ui/Makefile` `FBS_INPUTS` extended to pick the new schema up on
  the next `make -C ui fbs-ts` run.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 22:21:23 +02:00

197 lines
5.9 KiB
Plaintext

// diplomail contains FlatBuffers payloads used by the authenticated
// gateway boundary for the in-game diplomatic-mail subsystem. The
// wire shapes here mirror the trusted internal
// `/api/v1/user/games/{game_id}/mail/*` REST surface; gateway derives
// the calling `user_id` from the verified session and forwards it as
// `X-User-Id` to backend.
include "common.fbs";
namespace diplomail;
// MailMessage stores one inbox / sent-list / message-detail row. The
// fields mirror `UserMailMessageDetail` in `backend/openapi.yaml`
// with the following encoding rules:
//
// - `*_user_id` fields are RFC 4122 string UUIDs ("" means absent
// for nullable fields such as `sender_user_id`).
// - `*_at_ms` fields carry Unix milliseconds; `0` means the
// timestamp is absent (e.g. an unread message has
// `read_at_ms == 0`).
// - `translated_*`, `translation_lang`, and `translator` are set
// when the backend served a cached rendering into the caller's
// preferred language; empty otherwise.
// - `sender_race_name` is the snapshot of the sender's race name
// in this game at send time. Present for `sender_kind="player"`
// messages when the sender had an active membership; absent for
// admin and system messages. The in-game UI keys per-race
// threading on this field.
table MailMessage {
message_id:string;
game_id:string;
game_name:string;
kind:string;
sender_kind:string;
sender_user_id:string;
sender_username:string;
sender_race_name:string;
subject:string;
body:string;
body_lang:string;
broadcast_scope:string;
created_at_ms:int64;
recipient_user_id:string;
recipient_user_name:string;
recipient_race_name:string;
read_at_ms:int64;
deleted_at_ms:int64;
translated_subject:string;
translated_body:string;
translation_lang:string;
translator:string;
}
// MailRecipientState mirrors the `UserMailRecipientState` payload
// returned from mark-read and soft-delete endpoints. Same timestamp
// conventions as `MailMessage`.
table MailRecipientState {
message_id:string;
read_at_ms:int64;
deleted_at_ms:int64;
}
// MailBroadcastReceipt mirrors `UserMailBroadcastReceipt`. Returned
// from broadcast sends (paid-tier and admin); `recipient_count` is
// the number of recipient rows the server materialised.
table MailBroadcastReceipt {
message_id:string;
game_id:string;
game_name:string;
kind:string;
sender_kind:string;
subject:string;
body:string;
body_lang:string;
broadcast_scope:string;
created_at_ms:int64;
recipient_count:int32;
}
// InboxRequest stores the read-side request for the caller's inbox
// in `game_id`. Backend filters to messages with `available_at` set
// (translation completed when the recipient's preferred language
// differs from the body language).
table InboxRequest {
game_id:common.UUID (required);
}
// InboxResponse stores the resulting inbox list, newest first.
// `items` is empty when the caller has no available messages in
// this game.
table InboxResponse {
items:[MailMessage];
}
// SentRequest stores the read-side request for the caller's sent
// personal messages in `game_id`. Admin / system rows are not
// included.
table SentRequest {
game_id:common.UUID (required);
}
// SentResponse stores the caller's outgoing personal-message list.
// Each `MailMessage` carries the original recipient snapshot.
table SentResponse {
items:[MailMessage];
}
// MessageGetRequest stores the read-side request for a single
// message detail. The caller must be a recipient of the message.
table MessageGetRequest {
game_id:common.UUID (required);
message_id:common.UUID (required);
}
// MessageGetResponse stores the fully decorated message detail
// including any cached translation into the caller's preferred
// language.
table MessageGetResponse {
message:MailMessage;
}
// SendRequest stores the write-side request for a single-recipient
// personal send. Exactly one of `recipient_user_id` /
// `recipient_race_name` must be supplied; the empty string means
// "use the other field".
table SendRequest {
game_id:common.UUID (required);
recipient_user_id:string;
recipient_race_name:string;
subject:string;
body:string;
}
// SendResponse echoes the freshly inserted message detail.
table SendResponse {
message:MailMessage;
}
// BroadcastRequest stores the paid-tier player broadcast. The
// recipient set is always "every other active member of the game".
table BroadcastRequest {
game_id:common.UUID (required);
subject:string;
body:string;
}
// BroadcastResponse stores the receipt returned by the server.
table BroadcastResponse {
receipt:MailBroadcastReceipt;
}
// AdminRequest stores the owner-only admin send. `target="user"`
// requires exactly one of `recipient_user_id` / `recipient_race_name`;
// `target="all"` accepts the optional `recipients` scope (default
// `active`).
table AdminRequest {
game_id:common.UUID (required);
target:string;
recipient_user_id:string;
recipient_race_name:string;
recipients:string;
subject:string;
body:string;
}
// AdminResponse carries the result of an admin send. When the
// request had `target="user"`, `message` is set; when `target="all"`,
// `receipt` is set. Callers branch on which field is present.
table AdminResponse {
message:MailMessage;
receipt:MailBroadcastReceipt;
}
// ReadRequest stores the mark-read intent for a single message. The
// caller must be a recipient. Idempotent.
table ReadRequest {
game_id:common.UUID (required);
message_id:common.UUID (required);
}
// ReadResponse echoes the recipient state after the operation.
table ReadResponse {
state:MailRecipientState;
}
// DeleteRequest stores the soft-delete intent for a single message.
// The message must already be marked read (HTTP 409 otherwise).
table DeleteRequest {
game_id:common.UUID (required);
message_id:common.UUID (required);
}
// DeleteResponse echoes the recipient state after the operation.
table DeleteResponse {
state:MailRecipientState;
}