こんにちは〜!コネヒトのソフトウェアエンジニアの まきまき(@_mkmk884)です🦒
先日、ママリに「レシートエール」という新機能をリリースしました!対象商品のレシートを投稿するとコインが還元される、ベータ版のサービスです。
レシートエールは他社事業との連携機能なこともあり、利用のために新規の利用規約へのユーザー同意が必要になります。この記事では、その利用規約まわりをどう設計したかという話を書きます💪
一見目立ちにくい機能ですが、「法的文書は事業の変化や法改正に合わせた更新が必要になる」「誰がいつどのバージョンに同意したかを残す必要がある」を踏まえると、データ設計がじわじわ効いてくる領域だと思っています。同意モーダルを実装しながら考えたことを、設計を中心にまとめます。
サービスの詳しい内容や背景は以下をご覧ください🧾
利用規約まわりで意識したポイント
「利用規約に同意してもらう」と一言で言っても、素朴に「同意フラグを1つ立てる」だけにすると、あとで困ります。改訂の可能性がある利用規約だからこそおさえておかなければならないポイントがあります!
- バージョンを管理する必要がある:規約は文言が変わったり、条件が追加されたりする。そのたびにユーザーに同意を求め直す必要があるため、「どのバージョンの規約か」を区別できるようにしておきたい
- 同意は証跡として残す必要がある:「誰が・いつ・どのバージョンの規約に同意したか」は、あとから確認できる形で保持しておきたい
- 過去の規約内容そのものを残す必要がある:古いバージョンの規約は上書き・削除せず、内容ごと残しておきたい
つまり、規約まわりは「最新の状態」だけでなく「履歴」も大事になると考えました。 これらをおさえるために、このあとに紹介するデータ設計にしました!
データ設計:2テーブル構成
レシートエールでは、利用規約まわりを次の2テーブルで持つことにしました!
termsテーブル:利用規約マスタterm_agreementsテーブル:ユーザーの利用規約同意履歴
利用規約マスタテーブル(terms)
規約そのものを管理するテーブルです。主なカラムは以下のようなイメージです↓
| カラム | 役割 |
|---|---|
| version | 規約の「内容のバージョン」(例: 1.0) |
| body_url | 規約本文の参照先 |
| active_key | 現在有効な規約かどうか(後述) |
【ポイント】
- 有効な規約は常に1バージョンだけ:
active_keyはDBのUNIQUEなフラグ。activeな行には固定値(例:1)、そうでない行はNULLを入れる。UNIQUE制約はNULLを対象外にするDBが多いので、1が入っているのは必ず1件だけになる。アプリ側はWHERE active_key = 1で迷わず取得できる - 基本的に常にINSERT:規約を更新するときも既存行は書き換えず、新しいバージョンをINSERTしていく。フラグの差し替え(旧バージョンの
active_keyをNULLに、新バージョンを1に)だけUPDATEする
同意履歴テーブル(term_agreements)
ユーザーの同意を記録するテーブルです。主なカラムは以下のようなイメージです↓
| カラム | 役割 |
|---|---|
| user_id | 同意したユーザー |
| version | 同意した規約のバージョン |
| agreed_at | 同意日時 |
| app_version | 同意時の環境(証跡として保持) |
| user_agent | app_versionと同様 |
【ポイント】
- 常にINSERT(append-only):同意は履歴として積むだけ。更新も削除もしない
- 同意判定は「activeなversion」と「ユーザーが最後に同意したversion」の比較:両者が違っていたらまだ同意していないと判断して、利用規約画面を表示し、同意されたら新しい行をINSERTする
ユーザーが機能を使おうとしたときの処理フローはこんなイメージです↓

規約本文そのものはmdファイルで持つ
前述のとおり、DBには「どのバージョンがactiveか」「参照先はどこか」「誰がどのバージョンまで同意したか」というような情報を持たせました。
一方で、規約本文そのものは、リポジトリ内のmdファイルで管理することにしました!
この「本文をリポジトリ内のmdで持つ」ことにした背景は、ここまでで挙げた「過去の規約内容そのものを残す」とつながっています。mdをgitで管理すれば、内容そのものが上書き・削除されずに履歴として残り、適用前のドラフト段階の変更履歴まで追えます。
ただし、役割分担は意識しておく必要があります。
- データベース:いつ・どのバージョンがactiveで、誰が同意したかの証跡
- mdファイル(git):規約内容そのものを置いておく
git履歴はsquashやforce-pushで書き換わりうるし、デプロイとも独立しているので、証跡の主役にはしません。あくまで内容を消さずに残すための置き場、という位置づけです。なお、この前提を守るために「内容を変えたら必ずversionを上げる」という運用は崩さないようにしています。
利用規約の改訂をどう安全に回すか
データ設計が「履歴を積む」前提になっていると、規約の改訂も自然に扱えます。とはいえ、改訂は事故が起きやすいオペレーションなので、手順そのものをドキュメント化して仕組みにしています📝
ただ、ドキュメントは開く頻度が少なければ少ないほど更新が滞る経験があります……(遠い目)
ドキュメントを最新化し続けることは難しいと感じている方も多いのではないでしょうか?
対策として、ドキュメントをコードと同じリポジトリに置くことが有効だと思っています。コードに近い場所にあれば、関連する実装を変更したときに「このドキュメントも更新が必要では?」と気づきやすくなります。さらに最近は、Claude Codeなどの AIエージェントがリポジトリ内のファイルを読んで構造を理解するため、仕様変更時に「このドキュメントも更新してください」と依頼すれば一緒に直してもらいやすい、というメリットもあります🙌
そこで、このPJでは、リポジトリの TERMS_REVISION.md に改訂手順をまとめることにしました。新しいバージョン番号の決め方、レビュー(法務・関係者確認)、反映手順などを明文化しておくことで、誰がやっても同じ手順で安全に改訂できる状態を目指しています。
改訂は頻繁に起こらないからこそ、記憶の新しいうちにドキュメントで残しておきましょう。
おわりに
利用規約まわりは目立ちにくい機能かもしれませんが、最初に挙げた「意識したポイント」をおさえておくと、それぞれに対して次のような設計判断が自然と決まりました!
- バージョンを管理する必要がある → バージョンと参照先を分け、どのバージョンの規約かを区別できるようにする
- 同意を証跡として残す → 同意履歴は append-only にして、誰がいつどのバージョンに同意したかを残す
- 過去の内容を残す → 規約マスタは上書きせず常にINSERTし、利用規約内容もgitで管理。active なものは1件だけUNIQUEで担保しつつ、古いバージョンも残す
そして、改訂の運用も無理なく扱えるようになりました!
レシートエールはまだまだ走り始めたばかり、これからもアップデートしていきます💪