コンテンツにスキップ

データモデル設計決定事項

タスク・決済・マッチングに関するフィールドレベルの設計決定を記録する。


1. タスクの位置情報

項目決定内容
方式location_text (NOT NULL) + lat / lng (nullable)
根拠フリーランス新法で実施場所の明示が義務付けられている
  • location_text — 実施場所をフリーテキストで保持。NOT NULL にすることで法令準拠を強制する
  • lat / lng — 位置ベースマッチング用。任意入力のため nullable
  • 入力 UI は郵便番号入力 → フリーテキスト補完の想定

未決事項

  • users テーブル側の位置情報カラムも同じ方針(location_text NOT NULL + lat/lng nullable)で揃えるか

2. payment_due_days の制約

項目決定内容
方式DB CHECK 制約 + サーバー側バリデーションの二重チェック
上限60日以内(フリーランス新法の支払期限)
  • DB 層: CHECK (payment_due_days <= 60) でデータ整合性を保証
  • サーバー層: アプリケーションバリデーションで同じ制約を適用し、意味のあるエラーメッセージを返す
  • クライアント層: サーバーからのエラーメッセージを受けて表示するだけ(クライアント側に独自バリデーションは持たない)

3. マッチングの粒度

項目決定内容
方式1タスク : 先着1名
テーブルmatches テーブルなし。tasks.contractor_id で対応
  • MVP では tasks.contractor_id に受諾した受注者の ID を直接保持する(1タスク1受注者)
  • CAS(Compare-And-Swap)で排他制御: WHERE id = $1 AND status = 'open' で同時受諾を防ぐ
  • matches テーブルは将来の「複数オファー/オークション形式」への拡張時に追加する

将来の拡張

  • オークション形式など、マッチング形式を選択できるようにする
  • タスク投稿時にマッチング形式(先着 / オークション / 指名)を指定する想定

4. 代理受領型の payments 設計

項目決定内容
決済フローcollected_atpaid_out_at の2段階
支払期限タスク完了日から60日以内
手数料platform_fee カラムを明示的に保持
  • collected_at — 依頼者から代金を回収した日時
  • paid_out_at — 受注者へ報酬を振り込んだ日時
  • due_date — タスク完了日 + 60日以内で算出
  • platform_fee — 集計・分析用に明示的にカラムとして保持する

MVP 実装状況: payments テーブルは MVP 未実装。報酬額は tasks.reward で保持し、実際の決済処理・振込は将来フェーズ(Stripe Connect 導入時)に実装する。


5. 追加テーブル: イベントストア方式

項目決定内容
方式単一のイベントテーブルに各種イベントを格納
目的改ざん防止・紛争対応・監査証跡

以下の要件を1つのイベントテーブルでカバーする:

用途説明MVPスコープ
取引条件スナップショットタスク作成・受諾時点の条件を不変レコードとして保存。紛争時の証拠
notificationsタスクの状態変化に応じた通知イベント
reviewsタスク完了後の評価× (MVP後)

インデックス設計方針

  • イベント種別(event_type)+ 対象エンティティ(entity_id)の複合インデックス
  • 時系列クエリ用に created_at のインデックス
  • 紛争対応の検索用に entity_type + entity_id + created_at の複合インデックス

参考ドキュメント