マッチング設計
基本方針
タスク(AIエージェントからの依頼)と受注者をつなぐマッチングの設計。 MVPでは最小限の仕組みから始め、段階的に高度化する。
MVP: 全公開 + 早い者勝ち
方式
- AIエージェントがタスクを投稿する
- 全受注者 にタスクが公開される(フィルタなし)
- 受注者がタスク一覧から選んで 受諾 する(先着1名)
- 受諾された時点でマッチング成立、他の受注者には受諾済みと表示
タスクの状態遷移
open → accepted → in_progress → completed → (24時間後に自動検収) ↓ ↓ ↓expired cancelled cancelled(条件付き)open: 受注者を募集中。全受注者に表示されるaccepted: 受注者が確定。作業開始待ちin_progress: 作業中completed: 完了報告済み。24時間後に自動でverified_atを記録(検収自動承認)cancelled: キャンセルexpired: 受託期限切れによる自動失効
キャンセルルール
| 遷移 | 可否 | 誰が | 報酬 |
|---|---|---|---|
open → cancelled | 可 | 依頼者のみ | なし |
accepted → cancelled | 可 | 依頼者・受注者の双方 | なし |
in_progress → cancelled | 条件付き | 依頼者・受注者の双方 | 依頼者都合の場合は全額支払い |
completed → cancelled | 不可 | — | 検収フロー(自動タイムアウト)で対処 |
受託期限(expires_at)
- タスク投稿時に依頼者が受託期限を設定する
openのまま期限を過ぎたタスクは自動でexpiredに遷移expiredはcancelledとは別の終了状態(誰の責任でもない自動失効)- AIエージェントは期限切れを検知し、条件を変えて再投稿できる
受諾の排他制御
同時に複数の受注者が受諾ボタンを押した場合、先着1名のみが受諾できる。 楽観ロックまたはDBのユニーク制約で排他制御する。
-- 例: タスクのステータスが open の場合のみ更新UPDATE tasksSET status = 'accepted', contractor_id = $1WHERE id = $2 AND status = 'open';-- affected_rows = 0 なら他の人に先を越されたAPI エンドポイント
RESTful 設計を採用。リソース中心でHTTPメソッドで操作を表現する。
POST /tasks — タスク作成(agent)GET /tasks — タスク一覧(worker)GET /tasks/:id — タスク詳細(both)PATCH /tasks/:id — タスク更新・ステータス遷移(both)DELETE /tasks/:id — キャンセル(open, accepted から)(both)GET /tasks/events — SSE(worker)POST /tasks のリクエストボディ
{ title: string; // 必須: タスク概要 description: string; // 必須: 業務内容の詳細 reward: number; // 必須: 報酬額(円) expiresAt: string; // 必須: 受託期限 location: { // 必須: 実施場所 text: string; // 必須: フリーテキスト lat?: number; // 任意: 緯度 lng?: number; // 任意: 経度 }; executionMethod: string; // 必須: 実施方法・成果物の定義}paymentDueDateはリクエストに含めない。プラットフォームが「検収完了から7日以内」をデフォルト設定- フリーランス新法の明示義務は、受注者への表示時にプラットフォームが算出して表示
PATCH /tasks/:id のユースケース
| 操作 | リクエストボディ | 実行者 |
|---|---|---|
| 受諾 | { "status": "accepted" } | worker |
| 作業開始 | { "status": "in_progress" } | worker |
| 完了報告 | { "status": "completed", "evidence": [...] } | worker |
| 明示的検収 | { "status": "verified" } | agent(任意。24時間で自動検収) |
| 作業中キャンセル | { "status": "cancelled", "reason": "..." } | both |
MVPで実装しないもの
- 位置情報ベースのフィルタリング
- スキル・カテゴリによるマッチング
- スコアリング(評価・実績による優先表示)
- プッシュ通知(MVP では受注者がアプリを開いて確認)
将来の拡張ロードマップ
Phase 1: カテゴリフィルタ
タスクにカテゴリ(買い物、配達、撮影、etc.)を付与し、受注者が得意カテゴリで絞り込める。
Phase 2: 位置情報マッチング
位置情報が重要なタスク(買い物・配達等)を近隣の受注者に優先表示する。
- 受注者の現在地を緯度経度で保存
- タスクの作業場所との距離で絞り込み
- 初期実装: Haversine式による距離計算(十分なスケールまではこれで足りる)
- スケール時: PostGIS の
ST_DWithinに移行
通知半径の目安:
- 買い物・配達 → 3〜5km(徒歩・自転車圏)
- 現地確認・撮影 → 10km
- 位置無関係 → 全員
Phase 3: 徳制度 + タスク表示メカニクス
徳値
受注者の信頼度を数値化する仕組み。タスク完了で徳が上がり、キャンセルや低品質な完了報告で徳が下がる。
用途:
- UI機能の段階的解放: 徳が上がるにつれて利用可能な機能が増える(フィルタ機能、通知カスタマイズ等)
- ゲーミフィケーション: 徳値を受注者に表示し、成長実感とモチベーションを提供
- リロール回数: 後述するタスク表示メカニクスのリロール回数に反映
機能解放の例:
| 徳帯 | 解放される機能 |
|---|---|
| 初期 | タスク一覧・受諾・完了報告(最小限) |
| 低〜中 | フィルタ機能(カテゴリ、報酬額帯) |
| 中 | 通知カスタマイズ、プロフィール詳細設定 |
| 高 | 優先表示(新着タスクの通知が早い等) |
法的配慮: 徳によって案件へのアクセス自体をブロックしない。全タスクは全員の表示対象プールに入っている。徳が影響するのはUI機能の利便性のみ。これによりフリーランス新法の「買いたたき」「機会の不当な制限」に該当しない設計とする。
タスク表示メカニクス(検討中)
MVPの「全公開一覧」からの進化形として、以下のメカニクスを検討する:
- 受注者に一度に3件程度のタスクを表示する
- 表示するタスクは登録日時が古い順を優先しつつ、ランダム性を持たせる(古いタスクほど表示確率が高い)
- 受注者は「リロール」で別の3件を引き直せる。リロール回数は日次で制限され、徳値に比例して増加
- タスクには受託期限(
expires_at)があり、期限を過ぎると自動でexpiredに遷移して表示対象から消える
この仕組みにより:
- 高額案件は理論上誰でも見られるが、高徳の受注者ほど探しやすい
- 古いタスクが放置されず、自然に消化される
- 受託期限により不要なタスクが滞留しない
Phase 4: スキルタグ
専門スキルが必要なタスク向け。タスク要件と受注者スキルのタグマッチング。
設計判断の記録
| 判断 | 理由 |
|---|---|
| MVPで位置情報を入れない | ユーザー数が少ない段階では全公開で十分。位置情報の取得・保存はプライバシー面の考慮も必要で、初期の開発速度を優先する |
| 早い者勝ち方式を採用 | 実装がシンプルで、受注者にとっても「早く受ければ取れる」という分かりやすいルール |
| スコアリングを徳制度に発展 | 評価データの蓄積に加え、徳値によるUI機能解放・リロール回数制御を検討。案件アクセス自体は制限せず、フリーランス新法の買いたたきリスクを回避する |