コミュニティメンバー表示ポリシーUXモック

コミュニティメンバー表示ポリシー — UXモック

メンバー一覧を「チャンネルに権限のある全員表示」に改め、匿名デフォルト名と参加認知モーダルをセットで導入する案。
コース受講で自動参加する現行モデルは変えない。

現状の仕様
  • 受講生に見えるメンバー一覧・メンション候補は「表示名(display_name)を設定した受講生」+講師+自分のみ
  • チャンネルの権限(コース受講権)があっても、表示名が未設定なら一覧に存在しない
  • これは表示名未設定時に本名・メールへフォールバックして露出するのを防ぐ暫定フィルタで、下記3つの問題を生んでいる
問題1:メンバーが見えない・メンションできない
  • 権限はあるのに一覧に出ない受講生がいて、誰と同じ場にいるのか分からない
  • メンション候補にも出ず、メンバー詳細の取得は404
  • 人数データ(channel_members_count)は全員を数える定義のため一覧と食い違う(合計を表示した時点で不一致が露見)
問題2:本名・メールの露出
  • account.name には本名のほか Stripe 連携等でメールアドレスが入っている場合がある
  • display_name 自体にメールを設定しているケースもある
  • 投稿者名・メンションでは現在もそのまま露出している
問題3:参加の認知がない
  • コース受講と同時に自動でコミュニティメンバーになる
  • 参加した認識のないまま他メンバーから見える状態になっている
変更方針

メンバー一覧を「各チャンネルにアクセス権のあるメンバーは全員表示」に変更する。
それを安全に行うために、下記①〜⑤をセットで導入する(①だけ先行すると問題2が悪化するため分離不可)。

1 権限ベースの全員表示:display_name の有無による除外フィルタを撤廃
2 匿名デフォルト名:未設定・メール形式の表示名は「メンバー + ID由来6桁」で統一表示(本名・メールへのフォールバック廃止)
3 講師にだけ本名・メール併記:本文に入るラベルは共通表示名のまま
4 参加の認知:「どこに・なぜ・どう見えるか」を1枚のモーダルで(非ブロッキング・未設定の間は1日1回・状態で文言出し分け)
5 常設導線:「あとで」後も表示名未設定の間は控えめな設定導線を常設

現状 → 変更後の対応表(どの問題がどう解消されるか)

  • メンバー一覧 API はチャンネル単位の権限スコープをすでに持っている(会員公開チャンネル=コミュニティ会員 / コース限定チャンネル=該当コースの受講生+担当講師・幹事等)
  • 今回の要点は、受講生視点だけにある「表示名未設定の受講生を除外するフィルタ」の撤廃と、それを安全にする匿名デフォルト名の導入
項目現状変更後解消する問題
一覧に出る人受講生視点 表示名を設定した受講生+講師+自分のみ チャンネルに権限のある全員(未設定者は匿名IDで表示) 問題1
人数カウント channel_members_count は全員を数える定義で一覧と食い違う(現UIは合計未表示のため露見していない) カウント定義を「権限があり一度でも開いた人」に統一し、一覧+畳み行と常に一致させる 問題1
メンション候補受講生視点 表示名を設定した受講生しか候補に出ない 権限のある全員が候補に出る(匿名IDで挿入 問題1
メンバー詳細の取得 表示名未設定の相手は取得できない(404) 匿名IDのプロフィールとして取得できる 問題1
名前の表示 display_name があればそれを表示し、無ければ name にフォールバック(本名・メールが露出しうる)。メール形式の display_name もそのまま表示する display_name(メール形式を除く)があればそれを表示し、無ければ匿名ID。本名・メールに依存しないフォールバックにする 問題2
参加の認知 なし(受講と同時に無通知でメンバー化) 参加認知モーダル(表示名未設定の間は1日1回)+未設定の間の常設導線 問題3
ポイント ——「フィルタを消すだけ」の変更ではない
  • 変更しない:権限スコープ・投稿権限・アクセス可否の判定
  • 新規実装1:講師向けの本名・メール併記(serializer への新規フィールド。現状、他メンバーの email を独立フィールドで返す community API は無い)
  • 新規実装2:人数カウント定義の統一
  • 新規実装3:未オープン/長期未利用フィルタ
  • 新規実装4:メンバー検索と最終利用順ソート(一覧の limit+カーソルページング自体は実装済み。カーソルキーの差し替えで対応)

参加認知フロー(今回の拡張)

  • アクセス権のモデルは変えない(コース受講権からの導出のまま・参加ボタンでのゲートはしない)
  • 「勝手に参加している」感覚を初回の認知見え方の透明化で解消する
1コース受講権の付与
  • 招待URL・決済・講師登録など既存の導線のまま
  • ここでは何も出さない(コミュニティを使わない受講生へのノイズを避けるため)
2コミュニティを初めて開く
  • 最終オープン日時を community_last_opened_at に記録する
  • NULL=未オープンでモーダル対象かつ一覧非表示
  • 以後はオープンごとに touch する
3参加認知モーダル未設定なら1日1回
  • どこに(コミュニティ名)・なぜ(受講中コース)・どう見えているか(匿名ID)を伝える
  • 表示名の設定を促すが、閉じても利用は妨げない
  • 表示名が未設定(メール形式を含む)の間は、1日の最初のオープンで出す(下の表)
4「あとで」の後
  • その日は再表示しない
  • 未設定のままなら翌日の最初のオープンでまた出す
  • 左下の自分アイコンとメンバー一覧の自分行に控えめな設定導線を常設する

モーダルの出し分け

  • 初回オープン(パターン1)は display_name の状態によらず必ず出す(参加の認知が目的のため)。2回目以降は display_name の状態で決まる(未設定・メール形式は出す、設定済みは出さない)
  • 出す場合の頻度は「表示名が未設定の間、1日の最初のオープンで1回」。設定した時点で止まる
対象いつ出るか見出し内容の重心
1新規メンバー コミュニティ初回オープン時 「◯◯のコミュニティへようこそ」 参加の認知(どこに・なぜ参加しているか)+見え方+表示名設定
2既存・表示名 未設定 リリース後、次に開いた時 「名前の表示方法が変わりました」 表示ポリシー変更の告知。「ようこそ」は使わない(すでに使っている人に不自然なため)
3既存・表示名 設定済みメール形式でない 出さない 見え方が変わらないため告知しない。変更したくなったら常設導線から設定する
4既存・メール表示名 リリース後、次に開いた時 パターン2 と同じ+注意文 パターン2 に加えて「メールアドレスは表示名として使えなくなった」ことを明示
52日目以降のリマインド1・2・4 を閉じて未設定のまま 翌日以降、その日の最初のオープン(1日1回) 「表示名を設定しませんか」 告知は繰り返さず設定を促すだけに絞る。設定した時点で出なくなる

実装・仕様メモ

実装メモ表示名の保存・バリデーション
  • 保存は既存の /v2/community/profile を利用(新規 endpoint は不要)
  • 追加が必要なのは表示名の @ 混入バリデーション
実装メモメンバー一覧 API の変更点
  • チャンネル権限でのスコープ(全員公開 / コース限定)は既存のまま
  • 変更の実体は受講生視点の「表示名未設定の除外フィルタ」の撤廃(個別取得の 404・メンション候補の除外も同時に撤廃)
  • 加えて最終オープン状態でのフィルタ(NULL は非表示・1ヶ月以上は畳み。受講生視点の一覧のみ)
  • 一覧の分割取得(limit+カーソル)は実装済みのため追加不要。最終利用順への変更に伴うカーソルキーの差し替えのみ行う
  • 匿名デフォルト名と同一リリースで行う(撤廃だけ先行すると本名・メールの露出が拡大するため)
実装メモcommunity_last_opened_at(新設カラム)
  • モーダルの初回判定と最終利用の記録を兼用(enterprise ごとの account 単位)
  • NULL=未オープン → モーダル対象かつ一覧非表示。オープンごとに touch(1日1回程度に間引き)
  • 既存の chat_reads / chats を一覧クエリで JOIN する案は不採用(ROM 専の受講生を未利用扱いにする・JOIN と index が重い)
  • リリース時は migration で chat_reads.updated_at の MAX 等から一括 backfill。値があれば既存 / NULL のままなら新規として、モーダル出し分けの判定にも使う
実装メモ「1日1回」の判定
  • 表示条件は 表示名が未設定(または @ を含む) かつ その日まだ開いていない
  • 「その日まだ開いていない」は touch 前の community_last_opened_at の日付 ≠ 今日 で判定できる(専用カラムは増やさない)
  • touch を「1日1回程度に間引く」実装と判定タイミングが競合しないよう、オープン時は先に判定→後で touch の順にする
  • 日付境界はユーザーのタイムゾーンで判断する(サーバー TZ 固定だと深夜帯にずれる)
実装メモdisplay_name NULL化 migration との関係
  • 表示時の「@ を含む表示名は匿名ID」判定に一本化すれば、migration は原則不要
  • 併用する場合、users.email と同一の表示名は NULL 化で消えるため、パターン4(既存・メール表示名)の対象が手入力メールのみに縮む(NULL 化された人はパターン2 に移る)
仕様フィルタの適用範囲
  • メンション候補・講師の DM 宛先には適用しない(宛先から消えると連絡手段が失われるため)
  • 畳み・非表示はメンバー一覧の表示だけに閉じる
仕様長期未利用・未オープンの扱い
  • 1ヶ月以上未利用:オフライン欄で畳み表示(人数のみ)
  • 一度も開いていない人:一覧・畳み行・カウントすべてに含めない
  • 講師・自分は対象外で常に表示。受講生視点のみに適用し、講師視点は常に全員表示(名簿として把握が必要なため)
  • 人数カウントは「権限があり一度でも開いた人」に統一 → 一覧+畳み行=カウントで不一致を再発させない
  • 「1ヶ月」の閾値は仮の値で要調整
調査済み・対応不要オンライン表示(緑ドット)
  • コミュニティ画面を開いている間の WebSocket 接続で判定される実装
  • 一度も開いていない受講生がオンライン表示されることは構造的に起こらない → presence 側の追加対応は不要
仕様複数コース参加時のモーダル文言
  • 参加理由は「◯◯」ほか2件と畳んで表示する(先頭1件+残り件数)
  • 1コースのみなら「◯◯」だけ。コース名を全件並べることはしない
  • 04 の画面モックの参加認知モーダルに反映済み

見え方マトリクス(確認済み仕様)

相手の状態受講生視点講師視点
display_name 設定済みメールを含まない メンバー一覧・メンションとも display_name display_name + account.name・user.email を併記(一覧・メンション候補とも)
display_name 設定済みメールを含む 匿名ID(display_name は表示しない=露出解消) 匿名ID + account.name・user.email を併記 +「メール表示名」チップ
display_name 未設定 匿名ID 匿名ID + account.name・user.email を併記 +「未設定」チップ

この変更で満たす要件

一覧・メンションに個人情報を含めない 受講生は他受講生のメール・本名を見えない 講師はメール・本名・表示名を見える name / display_name へのメール混入の露出を解消 一覧+畳み表記が人数カウントと常に一致(未オープンは非表示・長期未利用は除外) どこに・なぜ参加しているかが分かる(参加認知モーダル) 自分がどう見えているかが分かる