4人プレイ(A,B,C,D)+観戦者 S1〜Sn。観戦者同士だけが使えるチャット機能の流れ(参加〜発言〜ログ保持〜退出)を、既存の観戦モード仕様 v1 に沿って整理したもの。
| 段階 | 利用者のアクション | プログラムの反応 | 画面に表示する内容 |
|---|---|---|---|
| ① | 観戦予定のユーザー 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行通知を表示する。 |