医療従事者が専門知識を安心して共有・学習できるコミュニティプラットフォーム——それが「メディカルサークル」の開発コンセプトです。一般のSNSとは異なり、医療×学術という領域特有の「信頼感」「安全性」「継続課金」の3つが設計の核心でした。
デザインシステムの構築からRevenueCatによるサブスク実装、コミュニティの安全を守る通報・ブロック機能まで、開発の全体像をまとめます。
目次
- 余白・角丸・色数を制限してUIを揃える
- メディカルブルーで信頼感を、アンバーで CTA を表す
- Noto Sans JP と段階的ウェイトで読みやすさを作る
- 共通ウィジェットを先に作り、画面は組み合わせで構成する
- 空状態・エラー・ローディングを安心感に変える
- ライトモード固定でもコントラスト比は妥協しない
- まとめ
- 通報・ブロック・非表示を別コレクションに分離する
- ブロックはクライアント側フィルタ + ストリーム監視で全画面に反映する
- フィルタとパフォーマンスを両立する
- セキュリティルールで公開・非公開を担保する
- 通報フローと運営対応を 1 本のデータフローで設計する
- アップロード前の確認 UI でやさしく誘導する
- まとめ
- Entitlement Identifier は変更不可
- 課金状態を Firestore とアプリ内 state に二重反映する
- 1 つのプロバイダで有料機能の制御を統一する
- 「購入の復元」は機能というよりテストの問題
- まとめ
- アップロード画面は上から下に進めば終わる導線にする
- 3D アイコンでファイル種別を直感的に区別する
- 有料導線は「気づくが押し付けない」場所に置く
- ゲスト利用で価値を体感してから登録に誘導する
- アカウント削除フローを多段階にして安心と確実を両立する
- ボトムナビと FAB を片手で扱える位置に置く
- 管理画面は俯瞰性を最優先にする
- アプリと管理画面でブランド一貫性と操作体系を使い分ける
- まとめ
- まとめ
医学部生向けという特殊な市場では、UI から伝わる「信頼感」がそのままアプリの選定基準になります。
メディカルサークルでは、デザインシステムを早い段階で固め、画面ごとに揺れない統一感を意識して作りました。
本記事では、その設計判断を共有します。
余白・角丸・色数を制限してUIを揃える
余白は 4 段階、角丸は 3 段階に限定し、画面ごとに独自の値を使わないルールを敷きました。
色はプライマリ(紺系)・セカンダリ・アクセントの 3 色+テキスト 3 階調(メイン・サブ・ヒント)に絞り、エラーや警告色は破壊的アクション専用と決めています。
中立的な操作には必ずプライマリ系を使う配色ガイドラインで、画面が増えても見た目が散らない状態を維持しました。
メディカルブルーで信頼感を、アンバーで CTA を表す
プライマリには深めの紺(メディカルブルー)を据え、「医療×学術」の信頼感を色彩から感じていただけるようにしています。
この色を AppBar・ボタン・選択状態などアプリの骨格に使い、ブランドの中心トーンを固定しました。
アクセントのアンバーは有料プランのバッジやリワード的な要素にだけ限定的に使い、視覚的に「ここは特別」と分かるシグナルにしています。
色数を絞ることで、CTA の存在感を自然に強められる配色設計です。
Noto Sans JP と段階的ウェイトで読みやすさを作る
医学用語が多く、文字情報が密になりがちなアプリです。
フォントは日本語の可読性を重視して Noto Sans JP を採用し、本文 400・ラベル 500・見出し 600・強調 700 の 4 段階で使い分けています。
行間は本文系テキストに 1.45〜1.5 を設定し、長い科目名や教授名が詰まって読みにくくならないよう配慮しました。
フォント選定とウェイト選定は、地味ですが誠実さを伝える要素です。
共通ウィジェットを先に作り、画面は組み合わせで構成する
プロジェクト初期に、ダイアログ・セクションヘッダー・メニュータイル・ソフトカード・空状態表示・エラーバナーといった基本部品を共通ウィジェットとして先に作り切りました。
各画面はそれらを組み合わせるだけで構成するルールにしたことで、見た目と挙動を全画面で統一できています。
コンポーネント化によって、開発速度の向上ならびに不具合の発生率低下を実現しています。
空状態・エラー・ローディングを安心感に変える
空状態には必ず「次に何をすべきか」の CTA ボタンを添えるルールにしました。
「まだノートがありません」で終わらせず「ノートをアップロード」ボタンを置くことで、ユーザーにとって次のアクションが明確になり迷子にならないようにしています。
エラー表示はバナー型に統一し、フォーム上部に赤背景で目立たせつつ、具体的な対処法を含む文言にしました。
たとえば、ログイン失敗時は「メールアドレスまたはパスワードが正しくありません」、退会済みメアドの場合は「このメールアドレスは退会済みです。再登録は新規会員登録からお願いします」のように、次のアクションが分かるメッセージにこだわっています。
ローディングは処理の重さに応じて使い分け、画面遷移程度なら控えめなスピナー、アップロードや削除のような長時間処理は進捗パーセント付きのダイアログで操作をブロックして安心感を出しています。
ライトモード固定でもコントラスト比は妥協しない
ダークモードは現時点では未対応で、ライトモード固定の設計です。
アクセシビリティ面では、テキスト色とバックグラウンド色のコントラスト比を意識し、メインテキストには十分に濃い色、補助テキストにも読める範囲の中間色を使い分けています。
ダークモード対応は、ライト側の体験を仕上げきってから検討する方針です。
まとめ
デザインシステムは作って終わりではなく、運用で守られて初めて意味を持ちます。
メディカルサークルでは、ルール化・配色・タイポ・共通ウィジェット・空状態の作り方まで一貫させたことで、画面ごとに迷わない開発体験と、ユーザーから見て揺れないブランド体験を両立できました。
ノート共有アプリは便利な反面、不適切な投稿や迷惑行為への備えがなければ安心して使えません。
メディカルサークルでは、通報・ブロック・コンテンツ非表示という 3 つの仕組みを土台に、ユーザーが自分で快適さをコントロールできる設計にしました。
本記事では、その実装方針をご説明します。
通報・ブロック・非表示を別コレクションに分離する
3 つの機能は、それぞれ別のコレクションに分離しました。
1 つにまとめるとセキュリティルールの条件が増加し、保守が一気に重くなります。
分離した方が各ルールがシンプルに書け、クライアント側のフィルタ処理も見通しが良くなりました。
また、それぞれの利用頻度やアクセス権限が異なるため、コレクションを分けたことでパフォーマンスも安定しています。
ブロックはクライアント側フィルタ + ストリーム監視で全画面に反映する
ブロックは「相手のファイル・コメント・メッセージが自分から見えなくなる」必要があります。
ここでは Firestore クエリ側で除外するのではなく、クエリ結果をクライアント側でフィルタする方式を採用しました。
漏れ防止のため、ブロックリストの取得は起動時 1 回ではなくストリームで常時監視し、ブロック操作した瞬間に全画面のフィルタが自動で更新されます。
新しい画面を追加する際も「ブロックリストで除外する」1 行を挟むだけで済むため、機能拡張に強い設計になりました。
フィルタとパフォーマンスを両立する
タイムラインや検索結果は、ブロックと非表示を考慮しながらパフォーマンスも保たなければなりません。
メディカルサークルでは、Firestore クエリ自体はシンプルに保ち、フィルタ処理はすべてクライアント側で行う方針を採用しました。
クエリ条件を複雑にして複合インデックスを増やすより、軽い後処理に倒した方が長期の運用コストも低く済みます。
セキュリティルールで公開・非公開を担保する
ファイルの作成・読み取り・更新・削除はすべて Firestore セキュリティルールで制御しています。
苦労したのは、フィールドが未定義の場合のハンドリングです。
古いドキュメントに新しいフィールドが存在しないケースで、ルールが意図せずアクセスを拒否してしまうことがありました。
デフォルト値付きの安全な読み出し構文を使い、null 安全に判定するパターンで解消しています。
通報フローと運営対応を 1 本のデータフローで設計する
ユーザーがアプリ内で通報ボタンを押すと、理由選択と任意コメント付きの通報ドキュメントが Firestore に作成されます。
ドキュメント ID は「通報者 + 対象種別 + 対象 ID」の組み合わせで決定的に生成しており、同じ人が同じ対象を二重通報できない構造です。
運営側は管理画面でこれらを一覧表示し、対応状況を更新できます。
シンプルな構造ですが、運営の処理速度と監査性のバランスが取れており、保守のしやすさがあります。
アップロード前の確認 UI でやさしく誘導する
アップロード画面では、送信ボタンの手前に「私個人のノートです」「教科書・市販教材の複製ではありません」「他者の著作権を侵害していません」の 3 項目のチェックボックスを設置しました。
全てチェックしないとアップロードできない設計です。
さらに、ユーザー名・タイトル・コメント・チャット・自己紹介の入力フォームには NG ワードフィルタをバリデーションに組み込み、不適切な表現が含まれていれば送信前にエラーを出します。
あくまで一次フィルタとしての位置づけで、最終判断は通報機能と運営対応に委ねる二段構えです。
まとめ
コミュニティ機能は「便利さ」より先に「安心」が前提になる領域です。
メディカルサークルでは、通報・ブロック・非表示・ルール・UI 誘導という 5 つのレイヤーを組み合わせ、運用負荷も含めて持続できる設計に整えました。
どれか 1 つに頼らず、複数の手段を重ねて初めて成立する世界観だと感じています。
アプリ単体で収益化する場合、サブスクの実装は事業の生命線です。
メディカルサークルでは、Apple / Google の課金を RevenueCat 経由で統合し、Firestore と同期させる構成を採用しました。
本記事では、その実装で詰まった点と学びを共有します。
Entitlement Identifier は変更不可
RevenueCat の Entitlement Identifier は、ダッシュボードで一度作成すると変更できません。
有料プラン名を改名した際、合わせて Identifier も変えたかったのですが、不可能でした。
結果として、Identifier は「内部的な識別子」、プラン名は「ユーザーに見せる表示名」と完全に分離し、コード側で定数として一元管理する設計に切り替えました。
課金状態を Firestore とアプリ内 state に二重反映する
RevenueCat のリスナーで課金状態の変化を検知し、変化時には Firestore のユーザードキュメントの isPremium フラグを更新します。
同時にアプリ内の状態管理プロバイダも更新し、UI 側はプロバイダを監視するだけで有料機能のロック/アンロックが即座に切り替わるようにしました。
Firestore 側にもフラグを置いているのは、セキュリティルールで参照する必要があるからです。
「クライアントの自己申告だけでルールを書く」のは危険なため、二重反映は必須でした。
1 つのプロバイダで有料機能の制御を統一する
有料機能のロック/アンロックを画面ごとにバラバラに書くと、改修時に必ずどこかが取り残されます。
メディカルサークルでは、課金状態を返すプロバイダを 1 つ定義し、すべての画面からそれを参照する方式に揃えました。
画面ごとの分岐は「プロバイダの値を見て if/else する」だけで済むため、新規プラン追加や条件変更にも追従しやすい構造になっています。
「購入の復元」は機能というよりテストの問題
App Store の審査で必須となる「購入の復元」は、設定画面にボタンを配置し、タップ時に RevenueCat の復元 API を呼んで結果を反映する構成です。
実装自体は数十行で済みますが、本当の論点は「ちゃんと動作するかをどう検証するか」でした。
サンドボックスアカウントを用意し、購入 → アンインストール → 再インストール → 復元、というシナリオを実機で繰り返し検証することで、リリース後のサポート問い合わせを最小化できました。
まとめ
RevenueCat を組み込んだ課金実装は、コードだけ見れば単純です。
しかし「Identifier の不変性」「ルールとの同期」「画面横断の制御」「復元の検証」という、見落としやすい論点が積み重なります。
メディカルサークルでは、最初の数日でこれらをまとめて潰しておいたことで、その後の機能開発を課金まわりに足を引っ張られず進められました。
前回はデザインシステムの話でしたが、今回は各画面の体験設計と、運営側の管理画面のUXについて説明します。
メディカルサークルでは、毎日使われるアプリを目指し、日常導線の中に自然にアップロードや学習体験を組み込む設計を意識しました。
本記事では、その具体的な工夫を紹介します。
アップロード画面は上から下に進めば終わる導線にする
要素が多くなりがちなアップロード画面は、ファイル選択 → タイトル・説明 → 科目・教授名 → 公開設定 → アップロードの順に並べ、自然に上から下へ進めば完了する構成にしました。
さらに、時間割登録済みユーザーが「今日の授業」カードからアップロードに入った場合は、科目名・教授名・曜日・時限がクエリパラメータで自動入力されます。
実質的に、ファイルを選んでタイトルを付けるだけで投稿が完了する導線になりました。
3D アイコンでファイル種別を直感的に区別する
ファイルカードには、ファイル種別ごとに色分けしたアイコンを配置しました。
PDF は赤、画像はプライマリの青、ZIP はアンバーと色を変え、直感的に判別できるようにしています。
さらに、アイコン自体を 3D 表現にすることで、周囲のテキストコンテンツより視覚的に浮かび上がり、一覧画面でも見つけやすくなりました。
小さなディテールですが、視認性の差が日常利用の快適さを生むと考えています。
有料導線は「気づくが押し付けない」場所に置く
検索機能は有料機能なので、ボトムナビの検索アイコンに小さな有料バッジを添える程度の控えめな表示にとどめています。
通常利用の動線上では有料表示が目に入りすぎず、ユーザーが自発的に検索に触れたタイミングでのみアップグレードダイアログが表示される仕組みです。
ダイアログには「今は必要ない」を選べるようにし、押し付けがましさを徹底的に避けました。
コンバージョンと体験の心地よさのバランスを意識した設計です。
ゲスト利用で価値を体感してから登録に誘導する
ゲスト(未登録)でも「自分の非公開ノート管理と時間割登録」は制限なく使えるようにしました。
会員登録を強制する前に、まずアプリの価値を体感してもらう設計です。
フレンド・コメント・チャットなどのソーシャル機能に触れたタイミングでのみ「この機能にはアカウント登録が必要です」というダイアログを表示し、文言は「何が使えないか」ではなく「登録すると何ができるようになるか」を伝えるように設計しました。
アカウント削除フローを多段階にして安心と確実を両立する
アカウント削除フローは「確認ダイアログ → パスワード再入力 → ローディング → 完了」の多段階構成です。
確認ダイアログでは「何が消えるのか」「何が残るのか」を具体的に記載し、チャット履歴は相手側に残ること、この操作は取り消せないことを明示しました。
誤操作を防ぐために手間は増やしつつも、不安を与えないよう情報を十分に開示するバランスを取っています。
ボトムナビと FAB を片手で扱える位置に置く
ボトムナビは「ホーム・マイノート・検索・マイページ」の 4 タブで、利用頻度の高い順に左から並べました。
主要なアクション(ノート追加の FAB、通知ベル、チャットアイコン)は、片手操作で指が届く位置に配置しています。
時間割の保存ボタンのように、最初は右上の AppBar に置いていたものは、実機テストで「押しにくい」と分かった段階で画面下部の大きなボタンに移動しました。
設計より、実機で触ったときの違和感を信じる姿勢を大切にしています。
管理画面は俯瞰性を最優先にする
運営側の管理画面は React + shadcn/ui で構築しました。
ユーザー・ノート・通報・コメント・チャットの各管理機能をサイドバーで切り替えるダッシュボード構成にし、一覧画面ではテーブル形式で一度に多くの情報を俯瞰できるようにしています。
アプリ本体とは違い、デスクトップで業務的に大量データを捌くシーンに最適化することで、運営工数を最小化しました。
アプリと管理画面でブランド一貫性と操作体系を使い分ける
配色はアプリ側と揃え、プライマリの紺やアクセントのアンバーを共通化することで、視覚的な一貫性を保ちました。
一方で使い勝手は意図的に差をつけており、アプリはカード型のモバイルファースト UI、管理画面はテーブル中心のデスクトップ向け UI と、それぞれの利用シーンに最適な操作体系を採用しています。
「同じブランドだが、別の道具」として設計したことで、両者が干渉せず、それぞれの役割を最大化できました。
まとめ
毎日使われるアプリを作るうえで自信があるのは、時間割登録と日常のノート管理を連動させた「今日の授業」セクションです。
時間割を登録するとホームに今日の授業が時限順に並び、各授業カードから直接ノートを追加できます。
科目名・教授名・曜日・時限がすべて自動入力されるため、ユーザーは写真を撮ってタイトルを付けるだけで整理済みのノートが完成します。
生活リズムにアプリの動作を乗せることで「わざわざ整理する」行為そのものを無くす
――この発想こそが、メディカルサークルの UI/UX 設計の核です。
まとめ
メディカルサークルの開発で最も重要だったのは、「医療という文脈にふさわしい信頼感」をUIとシステム設計の両面から実現することでした。デザインシステムで視覚的信頼を作り、課金設計で継続利用の仕組みを整え、安全機能でコミュニティを守る——この三つが揃って初めて機能するサービスです。
micomiaでは、専門領域向けSNS・コミュニティアプリの企画〜開発をトータルでサポートしています。


.webp%3Falt%3Dmedia%26token%3D0aa104f5-928b-4ddf-a535-d8574b7667a8&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%3D6ca2c2ef-9413-4453-b992-55b66b11ed54&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)
.webp%3Falt%3Dmedia%26token%3Dca25fa6b-e233-43f7-90c3-e68e4c5b0bc5&w=3840&q=75)
.webp%3Falt%3Dmedia%26token%3D3fb3dc66-ecca-402e-8fb8-fbec9407f7f5&w=3840&q=75)
.webp%3Falt%3Dmedia%26token%3D7f18e5f1-cfda-4148-ab86-b3d2e6547262&w=3840&q=75)