【第1回】クローズドコミュニティ向けグルメ共有マップを作った — 概要・機能・技術スタック
目次
はじめに
「友人や知人など、限られたメンバーの間で『行ってよかった飲食店』を気軽に共有したい」——そんな思いから、React + TypeScript + Firebase + Google Maps API を使ったクローズドコミュニティ向けのグルメ共有マップアプリを自作しました。
Google マップ上の店舗情報をそのまま活用しながら、コミュニティメンバーが投稿したコメント・写真・評価を地図上に重ねて表示できるのが特徴です。閲覧やリアクションは誰でも可能、投稿のみ Google ログインが必須という設計にすることで、運用の手間をかけずに荒れにくいコミュニティを維持できるようにしています。
今回はアプリの概要・主要機能・技術スタックを紹介します。
アプリの主要機能と画面構成
アプリは大きく「地図表示」「マップモード切替」「投稿フロー」「リアクション」の4つの機能で構成されています。
地図表示:投稿を集約したマーカーと評価による色分け
Google Maps 上にコミュニティメンバーの投稿をマーカーとして表示します。
- 同じ店舗への投稿は1つのマーカーに集約し、件数バッジを表示
- 投稿の平均評価(おすすめ度)に応じてマーカーの色が変化(未評価は白、評価が上がるほど色が濃くなる)
- 評価が登録されている店舗はマーカー上部に★の数値を表示
- マーカータップ → 投稿一覧シート → 投稿タップ → 詳細スライドアップという2段階の表示フロー

マップモード切替:コミュニティ向け表示とGoogleマップ標準表示
上部のトグルで2つの表示モードを切り替えられます。
- コミュニティマップモード(デフォルト): カテゴリフィルターチップを表示し、コミュニティの投稿マーカーのみを表示
- Googleマップモード: 店舗検索バー(Places Autocomplete)を表示し、通常のGoogleマップ表示に切り替わる
- 投稿モード(+ボタン押下中): 「お店をタップして選択」という案内バナーを表示し、地図上の店舗タップから投稿フローが始まる

投稿フロー:Googleマップの店舗タップから始める
未ログイン状態で投稿しようとすると、ログインを促すシートが表示されます。
- 右下の「+」ボタンをタップ → 自動でGoogleマップモードに切り替わり「お店をタップして選択」バナーが表示
- 地図上の飲食店・酒場をタップ → 店名・住所を確認するシートが表示
- その店への初投稿の場合のみカテゴリを選択(ラーメン・焼肉・寿司・海鮮・丼もの・中華・その他)
- 「おすすめ度」「1人での行きやすさ」を★1〜5で評価(任意)
- コメント・写真(最大3枚、任意)を追加し、ニックネーム(初回のみ)を入力して投稿完了
- 投稿後は自動でコミュニティマップモードに戻り、地図上に投稿したマーカーが表示される

リアクション:ログイン不要で気軽に反応できる
投稿一覧シートのヘッダーには「行った👍」「行きたい⭐」の2種類のリアクションボタンを用意しています。
- 店舗単位で集計し、ブラウザに保存したセッションIDで重複投票を防止
- 同じリアクションを再タップすると取り消しが可能
- ログイン不要のため、コミュニティの非メンバーでも気軽に参考にできる
技術スタック
| カテゴリ | 技術 | 選んだ理由 |
|---|---|---|
| フロントエンド | React 19 + TypeScript + Vite | 型安全で地図・投稿データなど多様な状態を扱いやすい |
| 地図表示 | Google Maps JavaScript API(@vis.gl/react-google-maps) | Reactコンポーネントとして地図・マーカーを宣言的に扱える |
| 店舗データ | Google Places API (New) | 店舗検索・住所・座標取得を高精度なデータでカバー |
| データベース | Firebase Firestore | 投稿・リアクションをリアルタイム同期できる |
| 認証 | Firebase Authentication(Google ログイン) | 数行の実装でログイン・セッション復元が完結 |
| ストレージ | Firebase Storage | 投稿写真をサイズ制限付きでシンプルに管理 |
| サーバー関数 | Firebase Cloud Functions v2(Node.js 22) | 新着投稿の通知などサーバーレスで処理を拡張できる |
| ルーティング | react-router-dom | 地図画面と管理画面のページ遷移をシンプルに管理 |
| ホスティング | Firebase Hosting | CDN配信・HTTPSが無料かつ設定ゼロで完結 |
フロントエンドからバックエンドまでFirebaseで統一しており、個人開発でもインフラ管理をほぼゼロにできています。Google Maps + Firebase という構成は、地図を使ったコミュニティアプリを作りたい方にとって相性の良い選択肢です。
React + Firebase + Google Maps で実現した3つの技術ポイント
1. 同一店舗への投稿を1マーカーに集約し、評価でマーカーの色を変える
課題:同じ店舗に複数の投稿があると、それぞれを別マーカーで表示すると地図が見づらくなる。また、コミュニティ全体の評価が一目でわからない。
解決策:店舗(placeId)単位で投稿をグループ化し、件数バッジと平均評価をマーカーに反映する。
投稿時・編集時にはstores/{placeId}ドキュメントのavgRecommendation・postCountを自動で再集計します。マーカー側はこの集計値を見るだけでよいため、表示時に投稿を都度集計する必要がありません。
以下は、平均評価からマーカーの色を決定するコードです。
// 平均評価からマーカーの色を決定する例
function getMarkerColor(avgRecommendation: number): string {
if (avgRecommendation === 0) return '#ffffff' // 未評価
if (avgRecommendation < 4.5) return '#fff3cd' // 標準的な評価
return '#ffd6d6' // 高評価
}
2. マップモード切替で「コミュニティ向け表示」とGoogleマップ標準表示を両立
課題:コミュニティの投稿マーカーを目立たせたい一方、店舗を探すときは通常のGoogleマップのPOI情報や検索機能も使いたい。
解決策:1つの地図インスタンスに対して、表示モードに応じてGoogle Mapsのstylesプロパティと表示コンポーネントを切り替える。
コミュニティマップモードでは、POIや交通機関のアイコンを非表示にするスタイル定義を地図に適用し、代わりに投稿マーカーとカテゴリフィルターを重ねて表示します。Googleマップモードに切り替えると、このスタイルを解除して標準のGoogleマップ表示に戻り、店舗検索バーを表示します。
以下は、モードに応じて地図のスタイルと表示コンポーネントを切り替えるコードです。
// マップモードに応じてスタイルと表示コンポーネントを切り替える例
<Map styles={communityMode ? COMMUNITY_MAP_STYLES : undefined}>
{communityMode ? (
<PostMarkers places={placeGroups} />
) : (
<MapSearchBar onPlaceSelected={handlePlaceSelected} />
)}
</Map>
3. 「閲覧・リアクションはログイン不要、投稿だけGoogleログイン必須」のハイブリッド認証設計
課題:誰でも気軽に見られるオープンさを保ちながら、荒れにくいコミュニティを運用したい。
解決策:閲覧・リアクションはログイン不要にし、投稿・編集・削除のみ Google ログインを必須にする。
リアクションはブラウザに保存したセッションIDで重複防止するだけなのでログイン不要です。一方、投稿には Firebase Authentication の Google ログインを必須にし、onAuthStateChangedでセッションを自動復元することで2回目以降の投稿はスムーズに行えます。Firestore のセキュリティルールでは、投稿の更新・削除をauthorId === request.auth.uidの場合のみ許可しており、本人以外の投稿を編集できないようにしています。
以下は、投稿時にログインしていなければ Google ログインを促すコードです。
// 投稿時のみGoogleログインを要求する例
const handleCreatePost = async () => {
if (!user) {
await signInWithPopup(auth, new GoogleAuthProvider())
return
}
// 投稿フローへ進む
}
まとめ:クローズドコミュニティ向けマップに Google Maps + Firebase が最適な理由
今回の記事で紹介したポイントをまとめます。
- 店舗単位で投稿を集約し、平均評価をマーカーの色と★表示に反映することで地図を見やすく保てる
- 1つの地図インスタンスでコミュニティ向け表示とGoogleマップ標準表示を切り替えられる
- 閲覧・リアクションはログイン不要、投稿のみGoogleログイン必須というハイブリッド認証で、オープンさと荒れにくさを両立
- Google Maps + Firebase のフルスタック構成により、個人開発でもインフラ管理をほぼゼロにできる
次回は、このアプリのGoogle Maps + Places API でお店を探す仕組みを詳しく解説します。地図上のPOIをタップして投稿を始めるフローや、Places Autocompleteによる店舗検索、検索結果がエリア内かどうかを判定する処理など、Google Maps を使ったアプリ開発で参考になる実装を紹介します。





ディスカッション
コメント一覧
まだ、コメントがありません