観戦中チャット フローチャート v1(観戦者同士)

4人プレイ(A,B,C,D)+観戦者 S1〜Sn。観戦者同士だけが使えるチャット機能の流れ(参加〜発言〜ログ保持〜退出)を、既存の観戦モード仕様 v1 に沿って整理したもの。

観戦者 S1〜Sn プレイヤー A〜D ロビー/部屋 サーバー(Socket.IO)
段階
観戦者 S1(代表)
他の観戦者 S2〜Sn
プレイヤー A〜D
サーバー(chat)
サーバー(観戦ルーム)
① ロビー
(観戦準備)
S1(観戦予定者)
ロビー(部屋一覧・部屋ID入力欄)
【アクション】部屋IDを入力し「観戦する」ボタンを押す
【送信】spectate_room(room_id, name)
S2〜Sn
ロビー or 観戦中(まだ参加していない)
A〜D
部屋 or ゲーム中
観戦チャットはプレイヤーには表示しない(UIもイベントも無し)
サーバー(chat)
特に処理なし
サーバー(観戦ルーム)
spectate_room を受信するまで、room["spectators"] に S1 は含まれない
↓ spectate_room 正常受理 → S1 が観戦ルームに join
② 観戦参加
(snapshot+chat_history)
S1
観戦画面(盤面+右側にチャット欄)
【受信】spectate_room_ok(..., snapshot?, chat_history[最近N件])
chat_history は発言者名・本文・時刻のみ。最大 N 件で古いものは切り捨て
S2〜Sn
既に観戦中ならチャット欄が表示済み
S1 参加時にサーバーから chat_join 通知を受け取る場合がある
A〜D
ゲーム画面(自分のプレイのみ)
観戦チャットの join/発言イベントは受信しない
サーバー(chat)
room["spectator_chat"][room_id] にバッファを保持(最大 N 件・TTL あり)
サーバー(観戦ルーム)
S1 を room["spectators"] に追加し Socket.IO ルームに参加させる
↓ 観戦者がチャット入力欄からメッセージ送信
③ チャット送信
(観戦中)
S1
観戦画面+チャット欄
【アクション】メッセージを入力し「送信」ボタン
【送信】spectator_chat_send(room_id, message, client_msg_id)
クライアント側で長さ制限・連投制限(クールダウン)・NGワード簡易チェック
S2〜Sn
メッセージ欄はそのまま(まだ新着なし)
A〜D
ゲームのみ。チャット UI なし
サーバー(chat)
【受信】spectator_chat_send → rate limit・NGワード・長さチェック → OKならメッセージを room["spectator_chat"] に追加
弾かれた場合は spectator_chat_error(client_msg_id, reason) を S1 のみへ返す
サーバー(観戦ルーム)
OK 時: spectator_chat_message(room_id, sender_name, text, ts) を観戦ルーム内の全観戦者へ broadcast
↓ spectator_chat_message を S1〜Sn が受信して表示更新
④ チャット表示
(観戦者全員)
S1
観戦画面+チャット欄(自分の発言が追加・スクロール)
【受信】spectator_chat_message(room_id, sender_name, text, ts)
client_msg_id が一致する pending 発言があれば「送信中」状態を解除
S2〜Sn
観戦画面+チャット欄(S1 の名前とメッセージを追加表示)
【受信】spectator_chat_message(...)
A〜D
影響なし
サーバー(chat)
room["spectator_chat"][room_id] にメッセージを記録(最大 N 件。古いものから削除)
サーバー(観戦ルーム)
特別な処理なし(通常の broadcast のみ)
↓ ゲームが進行し、game_ended → 再戦 or ロビーへ
⑤ ゲーム終了後
(再戦待機中のチャット)
S1
終了オーバーレイ+再戦状況メッセージ+チャット欄
【アクション】チャット継続 or 「ロビーに戻る」クリック
観戦を続ける間は spectator_chat_send / spectator_chat_message をそのまま利用
S2〜Sn
同様に終了画面+チャット欄
A〜D
再戦ポップアップ(プレイヤーのみ)。チャットは見えない
サーバー(chat)
room["state"] が rematch_pending でも spectator_chat_* は利用可能
サーバー(観戦ルーム)
観戦者がロビーに戻るまで S1 を room["spectators"] に残す
↓ 観戦者が「ロビーに戻る」→ 観戦を終了
⑥ 観戦終了
(S がロビーに戻る)
S1
ロビーに戻る前の最終画面
【アクション】「ロビーに戻る」クリック
【送信】leave_room(room_id)
S2〜Sn
チャット欄はそのまま(S1 の発言は履歴に残る)
A〜D
変化なし
サーバー(chat)
room["spectator_chat"] は room が残っている間は保持。S1 退出で削除はしない
サーバー(観戦ルーム)
S1 を spectators から除外し Socket.IO ルームから leave。必要なら spectator_leave 通知を他の観戦者へ broadcast
↓ S1 の画面はロビーへ戻る。必要であれば再度観戦+chat_history を取得可能

段階ごとの詳細:利用者のアクション/プログラムの反応/画面表示

段階 利用者のアクション プログラムの反応 画面に表示する内容
観戦予定のユーザー S1 がロビーで部屋IDを入力し、「観戦する」を押す。他の観戦者 S2〜Sn はまだロビーか別の部屋を見ている。 S1 から spectate_room(room_id, name) を受信するまでサーバー側の chat 状態は変化しない。 S1: ロビー(部屋一覧・部屋ID入力欄・「観戦する」ボタン)。チャット欄はまだ表示しない。プレイヤー A〜D は部屋/ゲーム画面のみを見ている。
S1 が観戦参加に成功する。 サーバーは S1 を room["spectators"] に追加し、Socket.IO ルームに join。room["spectator_chat"][room_id] から最近 N 件の chat_history を取り出し、盤面 snapshot と一緒に spectate_room_ok(...) として返却する。 S1: 観戦画面(盤面・ポイント・ターン情報)+右側に過去のチャット N 件を表示。S2〜Sn が既に観戦中なら、以後 S1 からのメッセージも同じ欄に流れてくる。
観戦中の S1 がチャット欄にテキストを入力し、「送信」を押す。 クライアントはローカルで連投制限(例: 1〜2秒のクールダウン)と文字数上限をチェックし、問題なければ spectator_chat_send(room_id, message, client_msg_id) を送信。サーバーは rate limit・NGワード・長さを再チェックし、OKなら room["spectator_chat"][room_id] に追加し spectator_chat_message(...) を観戦ルームの全観戦者へ broadcast。NG の場合は spectator_chat_error(client_msg_id, reason) を S1 に返す。 S1: 送信直後は自分のチャット欄に「送信中」表示(client_msg_id 紐付け)。エラー時はメッセージの横に「送信失敗(理由)」などを表示。S2〜Sn: まだ画面は変わらない。
S1・S2〜Sn が spectator_chat_message(room_id, sender_name, text, ts) を受信する。 各クライアントは受信したメッセージをチャット欄の末尾に追加し、必要であれば自動スクロールする。S1 のブラウザは client_msg_id に対応する「送信中」状態を解除する。 S1: 自分の発言が確定して表示される。S2〜Sn: S1 の名前と本文が新着メッセージとして表示される。プレイヤー A〜D には一切影響しない。
ゲーム終了後も観戦を続ける観戦者が、再戦待機中に雑談を続ける。 room["state"] が rematch_pending(再戦待機)や playing(再戦開始後)でも spectator_chat_* の扱いは同じ。room が残っている限り、観戦者同士のチャットは継続できる。 終了オーバーレイ(勝敗・ポイントなど)の右側に、観戦チャット欄が残る。「観戦を続ける」を選んだ観戦者は、再戦カウントダウンや再戦状況メッセージを見ながらチャットできる。
観戦を終えたい S1 が終了オーバーレイの「ロビーに戻る」ボタンを押す。 クライアントは leave_room(room_id) を送信。サーバーは S1 を spectators から除外し、Socket.IO ルームから leave。必要であれば残りの観戦者へ spectator_leave 通知を送る。room["spectator_chat"][room_id] の履歴は room が残っている間は保持される。 S1: ロビー画面に戻り、チャット欄は消える。S2〜Sn: チャット欄には S1 の過去メッセージが残りつつ、以降は S1 からの新規メッセージは届かない。必要なら「S1 さんが観戦をやめました」といった1行通知を表示する。