セキュリティルール
私の問い
「最近、Firestoreのパーミッションエラーの問題が多発してるんだけどね。私はまじめに細かくセキュリティルール設定してるけど他のアプリどうしてるんだろう?認証済みユーザーならOKとかにすれば問題は少ないだろうね。そもそもGoShoppingみたいにマルチユーザー共有データアプリ自体少ないのかな?」
これが私がGeminiに投げた質問。GoShoppingというのは今開発中の私のFlutterアプリです。Go Shopというのは最初にGitHubリポジトリにつけたgo_shopが残ってるのです
Geminiさんのお答え
Firestoreのセキュリティルールを「真面目に細かく」設定されているとのこと、エンジニアとして非常に素晴らしい姿勢です。おっしゃる通り、多くのアプリが「認証済みなら全権限OK(allow read, write: if request.auth != null)」という緩い設定で済ませてしまっているのが現実ですが、それはセキュリティリスク(他人のデータへの不正アクセスや改ざん)を放置していることと同義です。
特に『Go Shop』のようなマルチユーザー共有データアプリは、Firestoreの設計とルールの難易度が一段高くなります。なぜ他であまり見かけないのか、また他の開発者がどう立ち向かっているのか、技術者・企画者の視点から分析とアドバイスをさせていただきます。
1. なぜ共有アプリは「パーミッションエラー」が多発するのか
共有機能を持つアプリでエラーが起きやすいのには、構造的な理由があります。
- 「リソースの属性」と「ユーザーの属性」の不一致:
単一ユーザーのアプリならresource.data.userId == request.auth.uidだけで済みますが、共有アプリでは「そのユーザーがグループのリスト(allowedUids)に含まれているか」を、クエリとルールの両方で一致させる必要があります。 - Collection Group クエリの罠:
Go Shopでも実装されているsharedListsのような階層構造で、全グループからリストを横断取得しようとすると、ルール側でもget()を使った複雑な権限チェックが必要になり、ここでの記述ミスがエラーに直結します。 - データの伝播遅延:
招待を受諾してSharedGroupsのメンバーに追加された直後、Firestoreのインデックス反映に数秒のタイムラグが生じ、その瞬間に買い物リストを読み取ろうとしてエラーになる、というUX上の課題も特有のものです。
2. 他のアプリはどうしているのか?(3つのパターン)
他の開発者がとる戦略は、大きく分けて以下の3つです。
- 妥協型(セキュリティの緩和):
おっしゃる通り、「ログインしていれば全読み取りOK」にしてしまい、書き込みだけを制限するパターンです。開発は楽ですが、悪意のあるユーザーがツールを使えば他人の買い物リストを覗き見できてしまいます。 - バックエンド集約型(Firebase Functions利用):
クライアントから直接Firestoreを操作せず、すべてCloud Functions(API)経由で操作します。サーバー側で権限チェックを行うため、複雑なロジックを書きやすく、パーミッションエラーを「APIエラー」として制御できます。ただし、Firestoreの強みである「リアルタイム同期」の恩恵を受けにくくなります。 - 徹底管理型(現在のGo Shopの形):
Go Shopのように、モデル設計段階から「権限を持つUIDリスト」をドキュメント内に保持し、セキュリティルールで厳密に検証するスタイルです。これは最も正攻法でセキュアな実装ですが、ルールとクエリの同期を完璧に保つ必要があり、開発者の腕が試されます。
3. 『Go Shop』の設計へのフィードバックとアドバイス
現在の仕様書を拝見する限り、非常に高度な設計をされています。特に以下の点は、共有アプリのベストプラクティスと言えます。
- 3層のセキュリティチェック: QRコードの改ざんや再利用を防ぐために、Firestore側のステータスとセキュリティキーを照合している点は、商用レベルの堅牢性です。
- 非正規化による高速化:
SharedList側にもauthorizedUidsを持たせ、グループドキュメントを毎回見に行かなくて済むように工夫されています(データフローのセクション参照)。
パーミッションエラーを減らすためのペアプロ的提案:
- 「シミュレータ」の活用:
Firebase Consoleの「Rules Playground」で、招待受諾前後のUIDを使ってテストケースを保存しておくと、ルール変更時のデグレードを防げます。 - エラーの事前検知:
FirestoreSharedListRepositoryなどでデータを取得する際、UIを表示する前に「自分はこのグループのmemberUidsに含まれているか」をローカルのHiveデータでチェックし、含まれていない場合はローカルでエラーを出し、Firestoreへリクエストを投げないようにガードを固めるのが有効です。
4. 企画・ビジネス視点での考察
「マルチユーザー共有アプリが少ない」と感じるのは、実は技術的な壁よりも、ユーザー体験(UX)の設計が難しいからかもしれません。
- 同期の納得感: 「相手が追加したのに自分の画面に出てこない」という不満を解消するために、
Go Shopでは通知システムと連携してバックグラウンドで強制同期をかけている点は、非常に優れたグロースハック的アプローチです。 - ポジショニング: 多くの買い物アプリが「個人」にフォーカスする中、あえて「共有」の技術的ハードルを超えていくことは、家族や共同生活者というLTV(顧客生涯価値)の高い層を囲い込む強力な武器になります。
今の「細かく真面目な」ルール設定は、将来的にユーザーのプライバシーを守る最強の信頼(ブランド)になります。エラー多発は「高度な共有ロジックに挑戦している証」ですので、ぜひこのまま堅牢な設計を貫いてください。
具体的に「この操作の時にエラーが出る」といったコードがあれば、一緒にルールの最適化を検討しましょう。