ノート共有アプリは便利な反面、不適切な投稿や迷惑行為への備えがなければ安心して使えません。
メディカルサークルでは、通報・ブロック・コンテンツ非表示という 3 つの仕組みを土台に、ユーザーが自分で快適さをコントロールできる設計にしました。
本記事では、その実装方針をご説明します。
目次
通報・ブロック・非表示を別コレクションに分離する
3 つの機能は、それぞれ別のコレクションに分離しました。
1 つにまとめるとセキュリティルールの条件が増加し、保守が一気に重くなります。
分離した方が各ルールがシンプルに書け、クライアント側のフィルタ処理も見通しが良くなりました。
また、それぞれの利用頻度やアクセス権限が異なるため、コレクションを分けたことでパフォーマンスも安定しています。
ブロックはクライアント側フィルタ + ストリーム監視で全画面に反映する
ブロックは「相手のファイル・コメント・メッセージが自分から見えなくなる」必要があります。
ここでは Firestore クエリ側で除外するのではなく、クエリ結果をクライアント側でフィルタする方式を採用しました。
漏れ防止のため、ブロックリストの取得は起動時 1 回ではなくストリームで常時監視し、ブロック操作した瞬間に全画面のフィルタが自動で更新されます。
新しい画面を追加する際も「ブロックリストで除外する」1 行を挟むだけで済むため、機能拡張に強い設計になりました。
フィルタとパフォーマンスを両立する
タイムラインや検索結果は、ブロックと非表示を考慮しながらパフォーマンスも保たなければなりません。
メディカルサークルでは、Firestore クエリ自体はシンプルに保ち、フィルタ処理はすべてクライアント側で行う方針を採用しました。
クエリ条件を複雑にして複合インデックスを増やすより、軽い後処理に倒した方が長期の運用コストも低く済みます。
セキュリティルールで公開・非公開を担保する
ファイルの作成・読み取り・更新・削除はすべて Firestore セキュリティルールで制御しています。
苦労したのは、フィールドが未定義の場合のハンドリングです。
古いドキュメントに新しいフィールドが存在しないケースで、ルールが意図せずアクセスを拒否してしまうことがありました。
デフォルト値付きの安全な読み出し構文を使い、null 安全に判定するパターンで解消しています。
通報フローと運営対応を 1 本のデータフローで設計する
ユーザーがアプリ内で通報ボタンを押すと、理由選択と任意コメント付きの通報ドキュメントが Firestore に作成されます。
ドキュメント ID は「通報者 + 対象種別 + 対象 ID」の組み合わせで決定的に生成しており、同じ人が同じ対象を二重通報できない構造です。
運営側は管理画面でこれらを一覧表示し、対応状況を更新できます。
シンプルな構造ですが、運営の処理速度と監査性のバランスが取れており、保守のしやすさがあります。
アップロード前の確認 UI でやさしく誘導する
アップロード画面では、送信ボタンの手前に「私個人のノートです」「教科書・市販教材の複製ではありません」「他者の著作権を侵害していません」の 3 項目のチェックボックスを設置しました。
全てチェックしないとアップロードできない設計です。
さらに、ユーザー名・タイトル・コメント・チャット・自己紹介の入力フォームには NG ワードフィルタをバリデーションに組み込み、不適切な表現が含まれていれば送信前にエラーを出します。
あくまで一次フィルタとしての位置づけで、最終判断は通報機能と運営対応に委ねる二段構えです。
まとめ
コミュニティ機能は「便利さ」より先に「安心」が前提になる領域です。
メディカルサークルでは、通報・ブロック・非表示・ルール・UI 誘導という 5 つのレイヤーを組み合わせ、運用負荷も含めて持続できる設計に整えました。
どれか 1 つに頼らず、複数の手段を重ねて初めて成立する世界観だと感じています。


.webp%3Falt%3Dmedia%26token%3D554beac3-1f0a-4dae-99c0-76320019500f&w=3840&q=75)







.webp%3Falt%3Dmedia%26token%3D087cf100-0101-43ba-a354-dab3bbec04d2&w=3840&q=75)
.webp%3Falt%3Dmedia%26token%3D7c77ae76-450c-48b3-be29-0e949e7116dc&w=3840&q=75)
.webp%3Falt%3Dmedia%26token%3Dd8f3f5bc-41c2-4a1e-ace1-62e9ae72d08b&w=3840&q=75)
.webp%3Falt%3Dmedia%26token%3D679eb351-4808-4d43-8b9d-92f6a88584ef&w=3840&q=75)
.webp%3Falt%3Dmedia%26token%3D5c25485e-7be1-4f95-ad65-2e4c0c2d0ddb&w=3840&q=75)

.webp%3Falt%3Dmedia%26token%3D1875ff54-2eaa-4913-8d8c-9a4855927112&w=3840&q=75)
.webp%3Falt%3Dmedia%26token%3Da7c14698-1b08-4fea-89c6-f77a9121f4c5&w=3840&q=75)
.webp%3Falt%3Dmedia%26token%3D900f385d-12a2-449b-8d1e-83a57cef0088&w=3840&q=75)
.webp%3Falt%3Dmedia%26token%3D0e802fb0-2dda-44a7-bf80-5d39019635ba&w=3840&q=75)
.webp%3Falt%3Dmedia%26token%3D899eeefd-f4c9-44a6-9ec2-3ced0b223ffd&w=3840&q=75)