Skip to content

007 コミュニケーション設計

ユーザーと開発者が、連絡先を交換せずに 1 対 1 の掲示板としてやりとりするための UI とデータフローを定義します。

コミュニケーション設計 v2.6 / 2026-06-02


1 目的

これまでのフィードバック機能は、ユーザーから開発者へ一方向に届く仕組みでした。
前案では、開発者からの返信を付箋としてユーザーの画面に出す案を検討しましたが、これは体験として強すぎます。ユーザーの作業空間に開発者の返信が突然現れるため、誤配信時の心理的な負担も大きくなります。

本章では、返信を付箋として出すのではなく、設定画面内に「開発者とのやりとり」掲示板を作ります。ユーザーは必要なときだけ設定画面を開いて会話を確認します。

1.1 登場人物と用語

本章では「サーバー」という曖昧な言葉を使わず、次の名前で役割を区別します。

表 1.1-1 登場人物と責務

No名前役割保持してよい情報
1PCアプリユーザーが投稿し、自分の会話ログを表示するconversation_id、生の secret_token、最終確認時刻
2Vercel APIPCアプリ、Firestore、DiscordをつなぐAPI処理Firebase Admin SDK認証情報、Discord Bot Token、ingest secret
3Firebase / Firestore会話データの正本を保存するDBsecret_token_hash、会話本文、開発者返信、Discord通知ID
4Discordサーバー開発者が通知を見て返信する場所Discord通知メッセージ、開発者返信
5Discord WebhookVercel APIからDiscordサーバーへ通知を投稿する入口Webhook URL
6Discord BotDiscordサーバー上の返信をVercel APIへ取り込むために読む主体Bot Token

2 方針

表 2-1 方式の決定

No採否理由
1開発者返信を付箋として出す不採用ユーザーの作業空間に突然表示され、体験として踏み込みすぎる
2Discord チャンネルをユーザー数分作る不採用チャンネル数、権限、API制限、削除、運用管理が重すぎる
3設定画面内に 1 対 1 掲示板を作る採用ユーザーが見に行く形なので自然で、誤表示時の影響範囲も設定画面内に閉じる
4ユーザーごとに会話ファイルを作って自前同期する将来候補考え方は近いが、初期実装では Vercel API + Firebase / Firestore で会話データを管理する方が単純

3 ユーザー体験

設定画面に「開発者とのやりとり」を追加します。見た目は、シンプルな掲示板またはチャットログです。

表 3-1 ユーザー側 UI

No画面・状態表示操作
1設定画面「開発者とのやりとり」メニューユーザーが開く
2初回表示まだやりとりがない旨、入力欄、送信ボタンメッセージを書く
3送信後自分の投稿が会話ログに追加される必要なら続けて投稿する
4返信あり「アプリ開発者」名義の返信が会話ログに表示される読む、必要なら返信する
5未読返信あり右クリックメニューの「開発者とのやりとり」に ● 新着あり を付ける開いて確認する
6返信なし何も割り込んで表示しない通常利用を続ける
7通信失敗設定画面内に控えめな再試行表示付箋や通常操作には影響しない

表 3-2 会話ログの表示例

発言者表示例
ユーザーこんにちは
アプリ開発者こんにちは
ユーザー付箋の色を増やしてほしいです。
アプリ開発者ありがとうございます。検討します。

4 全体構成

ユーザー側は設定画面だけを使います。開発者側は Discord を返信入力 UI として使います。Discord はユーザーに直接見せません。

図 4-1 1 対 1 掲示板方式の全体構成

表 4-1 責務

領域責務
PCアプリ匿名会話IDの保持、掲示板UI表示、投稿、1日1回程度の新着確認
Vercel APIsecret token 照合、Firestore保存、Discord通知、Discord返信取り込み
Firebase / Firestore会話本文、開発者返信、既読状態、Discord通知との対応を永続保存
Discord開発者が確認・返信するための裏側 UI
開発者Discord上で対象投稿に返信する

5 データモデル

ユーザーをメールアドレスや Discord ID で識別しません。アプリがローカルに保持する匿名の conversation_id と、本人確認用の secret_token で会話を守ります。

表 5-1 ローカルに保存する情報

No情報保存場所用途
1conversation_idPCローカル設定このアプリの掲示板を識別する
2secret_tokenPCローカル設定他人が会話を読めないようにする
3last_message_check_atPCローカル設定1日1回程度の新着確認に制限する
4has_unread_developer_replyPCローカル設定右クリックメニューの新着表示に使う
5last_unread_check_datePCローカル設定JST 4:00 頃の自動確認を同じ日に重複実行しない

表 5-2 Firebase / Firestore に保存する情報

No情報用途
1conversation_id会話スレッドの識別
2secret_token_hashPCアプリからの読取・送信権限確認
3messages[]ユーザー投稿と開発者返信の本文
4discord_message_idDiscord通知と会話の紐付け
5author_typeuser または developer
6read_by_user開発者返信をユーザーが見たかどうか
7statusshadow accepted、ignored など

表 5-3 `secret_token` の発行と更新

No項目仕様
1発行タイミングPCアプリが開発者とのやりとりを初めて使い、ローカルに secret_token がないときに発行する
2更新タイミング通常は自動更新しない。ローカル保存が消えた、別環境を使った、または値が欠けた場合に新しく発行する
3長さ32バイトの乱数を base64url 文字列にするため、通常は43文字になる
4生成方法暗号用途の乱数生成器で32バイトを作り、URLに含められる base64url 形式へ変換する
5Firestore保存生の secret_token は保存せず、secret_token_hash だけを Firestore に保存する

表 5-4 会話データの分離ルール

Noルール理由
1Firestore の会話正本は feedback_conversations/{conversation_id} 単位で分離するユーザーごとの掲示板をDB上でも別スレッドとして扱う
2conversation_id だけで本人確認しないIDが見えたり推測された場合でも、会話を読ませない
3読み取り、投稿、既読更新は secret_token_hash が一致した場合だけ許可する別ユーザーの会話ログが返る事故を防ぐ
4Discord返信は元の通知メッセージまたは通知内の会話IDから対象会話を確定できた場合だけ保存するDiscord内の無関係な投稿がユーザーの掲示板に混入しないようにする
5対象会話を確定できない、token が一致しない、または重複している場合は保存せず拒否する判断できないものは表示しない fail closed にする
6右クリックメニュー表示時は Firestore へ問い合わせないメニュー表示を遅くせず、通信失敗で右クリックが効かなくなる事故を防ぐ
7掲示板を開いて表示できた開発者返信だけを既読化する見ていない返信を既読にしない

Firestore は Vercel の中にある保存領域ではなく、Firebase が提供する外部の永続データベースです。Vercel API は、Vercelの環境変数に設定した Firebase Admin SDK 認証情報を使って Firestore を読み書きします。PC アプリや iPhone PWA に Firebase の管理用認証情報を配布しません。

txt
feedback_conversations/{conversation_id}
  secret_token_hash
  created_at
  updated_at
  discord_message_id
  delivery_enabled

feedback_conversations/{conversation_id}/messages/{message_id}
  author_type: user | developer
  body
  created_at
  discord_message_id
  read_by_user
  shadow_only

6 シーケンス

図 6-1 掲示板メッセージ送受信シーケンス


7 Discord連携

Discordは、開発者の作業場所としてだけ使います。ユーザーごとのDiscordチャンネルは作りません。 開発者は、1つの開発者用チャンネルに届く通知を見て、対象通知の返信スレッドで返事を書きます。 会話の正本は Firestore に保存し、Discord は「通知を見る場所」と「開発者が返信を書く場所」として扱います。

表 7-1 Discordをユーザー数分作らない理由

No理由内容
1運用負荷ユーザー数分のチャンネル、権限、削除、検索を管理できない
2API制限大量チャンネル作成・更新はDiscord側の制限を受けやすい
3誤操作リスク開発者がチャンネルを間違えると、別ユーザーの会話に返信しやすい
4プライバシーDiscord側の構造にユーザー数や会話単位が露出しやすい

表 7-2 開発者側の確認方法

No項目内容
1確認場所Discord の開発者用フィードバックチャンネル
2会話単位ユーザーごとのチャンネルではなく、通知メッセージまたは通知スレッドを会話単位にする
3返信方法開発者は対象通知への返信として本文を書く
4正本Firestore の conversation_id 単位の会話データ
5Discordの役割開発者が見つけやすく返信しやすい作業UI。ユーザーに直接見せる画面ではない
6過去ログDiscord通知に直近5件のやりとりを添える。久しぶりの相手にも最低限の文脈を持って返せる
7100人規模チャンネルは増やさず、通知とスレッドで扱う。未対応・対応済み・重要などの管理が必要になったら Firestore を読む管理画面を追加する

表 7-3 開発者返信の取り込み条件

No条件対策
1元の会話通知に紐付いているdiscord_message_id -> conversation_id の対応表で確認する
2開発者として許可されているALLOWED_DISCORD_USER_IDS に含まれる author_id だけを受け付ける
3Bot自身ではないBot投稿は取り込まない
4空本文ではない空文字、空白だけの返信は取り込まない
5未取り込みである同じDiscord返信IDは一度だけ保存する
6shadow mode を通過している初期運用では保存してもユーザーには返さない

7.1 過去ログの確認

開発者が返信するときは、直近の投稿だけでなく、その conversation_id の直近5件のやりとりを確認できるようにします。
これにより、以前やりとりした相手に「お久しぶりです」と自然に返せます。

表 7.1-1 過去ログ確認の方針

No項目内容
1保存先Firestore の feedback_conversations/{conversation_id}/messages
2並び順created_at 昇順でユーザー投稿と開発者返信を表示する
3開発者の確認方法Discord通知に直近5件の会話ログを含める
4Discord上の限界Discordの過去表示だけを正本にしない。削除・流れ・検索性の問題があるため Firestore を正本にする
5ユーザー側設定画面の掲示板で、自分の会話履歴を確認できる
6全履歴初期実装では開発者向けに全履歴UIは作らない。必要になったら管理画面で追加する

8 安全要求と距離感

この機能で特に守る安全要求は4つです。加えて、ユーザーと開発者の距離感を守ります。
開発者から返信できることは便利ですが、ユーザーの作業空間へ突然入り込む体験にはしません。ユーザーが必要なときに設定画面を開き、自分の意思で確認できる関係にします。

表 8-1 安全要求と対策

No要求失敗した場合対策
1返信は元のユーザーだけに届く別ユーザーの掲示板に返信が表示される。これはセキュリティ事故として扱うconversation_id + secret_token が一致した場合だけ返す。conversation_id だけでは返さない
2開発者の返信だけが届くDiscord内の無関係な投稿が表示される許可済みDiscordユーザーID、返信元メッセージID、重複状態をすべて検証する
3DB上で他人の会話と混ざらないFirestoreから別ユーザーの messages を取得または保存するfeedback_conversations/{conversation_id} 単位で保存し、読み書きのたびに secret_token_hash を照合する
4判断できない返信は表示しない対象会話が不明なDiscord投稿がユーザーの掲示板に出る会話IDを確定できない返信は保存せず、ignored または rejected として扱う

表 8-2 ユーザーとの距離感を守る制約

No制約理由
1付箋として自動表示しない開発者の返信がユーザーの作業中の画面へ割り込まない
2設定画面を開いたときに見るユーザーが自分の意思で確認する関係にする
3JST 4:00 頃に1日1回確認するVercel Cron が JST 3:00 に Discord 返信を取り込んだ後、朝に新着を拾えるようにする
4返信がない日は何も出さない通常利用の流れを邪魔しない
5kill switch を持つ問題があれば Vercel API 側で即停止できる
6shadow mode から始める実配信前にDiscord返信分類を確認できる

9 API設計

表 9-1 API一覧

NoAPI用途
1POST /api/feedback/conversation/messagesユーザー投稿を保存し、Discordへ通知する
2POST /api/feedback/conversation/poll設定画面が会話ログ・未読返信を取得する
3POST /api/feedback/conversation/ackユーザーが見た返信を既読にする
4POST /api/feedback/discord/ingest開発者の管理操作でDiscord返信を取り込む
5GET /api/feedback/discord/cronVercel CronでDiscord返信を取り込む

2 の conversation/poll は、PC アプリが「自分の掲示板を見せる」ために呼びます。右クリックメニュー表示時には呼びません。
PC アプリは JST 4:00 頃に1日1回だけ conversation/poll を呼び、未読の開発者返信があればローカルの has_unread_developer_reply を true にします。
ユーザーが「開発者とのやりとり」を開いた場合は、その時点で最新の conversation/poll を呼び、表示できた開発者返信だけ conversation/ack で既読化します。 4 の discord/ingest は、開発者の管理操作が「Discord に書かれた開発者返信を会話データへ入れる」ために呼びます。
5 の discord/cron は、Vercel Cron が同じ取り込み処理を本番環境で JST 3:00 に1日1回実行するために呼びます。CRON_SECRET による Authorization ヘッダー認証を必須にします。

管理者ツールの手動 discord/ingest では、開発者PCの localStorageFEEDBACK_CONVERSATION_INGEST_SECRET を保存できます。これは開発者PCでの入力補助だけに使い、Vercel や Firestore へ secret の生値を保存しません。CRON_SECRET は通常PCアプリで入力しないため、保存対象にしません。

図 9-1 APIごとの役割と実行タイミング

表 9-2 環境変数

No環境変数用途
1FEEDBACK_CONVERSATION_ENABLED掲示板機能の有効・無効
2FEEDBACK_CONVERSATION_SHADOW_MODE返信を保存するがユーザーへ返さない運用
3FEEDBACK_CONVERSATION_INGEST_SECRETDiscord取り込みAPIの認証
4DISCORD_BOT_TOKENDiscord返信の読み取り
5DISCORD_FEEDBACK_CHANNEL_ID監視対象チャンネル
6ALLOWED_DISCORD_USER_IDS返信を許可する開発者ID
7FIREBASE_PROJECT_IDFirestore のプロジェクト識別子
8FIREBASE_CLIENT_EMAILVercel API が使う Firebase サービスアカウント
9FIREBASE_PRIVATE_KEYFirestore 読み書き用の秘密鍵
10FIREBASE_DATABASE_IDFirestore のデータベースID。通常は (default)

10 実装境界

表 10-1 今回実装するもの・しないもの

区分内容
実装する設定画面内の掲示板、匿名会話ID、secret token、Firestore保存、Discord通知、Discord返信取り込み、新着確認
実装しない返信付箋、ユーザー数分のDiscordチャンネル、自動プッシュ通知、Google Drive内の会話ファイル同期
将来検討通知バッジ、ユーザーによる会話削除、添付画像、既読表示、サポート対応ステータス

11 リリース手順

表 11-1 リリース手順

No手順確認
1FEEDBACK_CONVERSATION_ENABLED=false でデプロイ既存フィードバック送信が壊れない
2Discord通知だけ有効化開発者に投稿が届く
3shadow mode で返信分類誤分類がない
4自分のテスト会話だけで取得確認正しい会話にだけ返信が出る
5public delivery 有効化設定画面内に返信が表示される
6監視rejected理由、重複、誤配信ゼロを確認する

12 改版履歴

表 12-1 改版履歴

Noバージョン日付変更内容
11.026-06-01ユーザーと開発者の 1 対 1 会話、ありがとう付箋、開発者返信付箋、日次確認、安全制約を定義
21.126-06-01返信が元ユーザーだけに届くこと、開発者返信だけが届くことの安全要求を追加
32.026-06-01返信付箋方式を廃止し、設定画面内の 1 対 1 掲示板方式へ変更
42.126-06-01会話ストアを Firebase / Firestore 前提に変更し、API図と環境変数を更新
52.226-06-01「怖くないための制約」を「ユーザーとの距離感を守る制約」に変更し、開発者が作業空間へ割り込まない意図を明確化
62.326-06-01開発者がDiscordで会話を確認する方法、100人規模でもチャンネルを増やさない運用、管理画面追加の判断基準を追加
72.426-06-01開発者が直近5件の過去ログを確認して返信できる方針を追加し、Firestoreを会話履歴の正本と明記
82.526-06-02secret_token の発行仕様と、Firestore上で他人の会話を混在させない分離ルールを追加
92.626-06-02登場人物の用語を定義し、曖昧な「サーバー」表現を Vercel API、Firebase / Firestore、Discordサーバーに分解
102.726-06-04Vercel Cron は JST 3:00、PCアプリは JST 4:00 頃に1日1回確認する運用を追加。右クリックメニューは通信せずローカル未読状態だけで新着表示し、掲示板表示時に既読化する仕様を追加
112.826-06-05管理者ツールの手動 ingest 用に、開発者PCの localStorage へ FEEDBACK_CONVERSATION_INGEST_SECRET を保存できる仕様を追加。CRON_SECRET は保存対象外と明記。