# マッチングアプリ テンプレート 要件定義書
## プロダクト名：Souzoh Match

> 「Claude Codeでマッチングアプリを開発する方法と費用｜そのまま使えるテンプレート配布【2026年】」記事のデモアプリ。
> **母艦テンプレート（Souzoh SNS）からの2本目**。共通基盤を流用し、固有画面のみ新規実装します。

---

## 1. 目的とゴール

| 項目 | 内容 |
|---|---|
| コンセプト | **「できること」と「力を借りたいこと」で人をつなぐ、共創マッチング**。恋愛・出会い系ではない |
| なぜこの題材か | ①スワイプUIという"マッチングアプリらしさ"を保ったまま恋愛色を外せる ②読者（事業者）が自社に置き換えて発注イメージを持てる ③デモデータそのものが「マッチする仕組み」の説明になる |
| 成功条件 | カードを3枚めくった時点で「これ自社の◯◯に使えるな」と読者が思う |
| 非ゴール | 実在ユーザーの本番マッチング。推薦アルゴリズムの精度 |

**想定シーン**：デザイナーが「フロント実装を手伝ってほしい」、エンジニアが「UIを見てほしい」。この2人が噛み合う。求人でも恋愛でもない、対等な交換のマッチングです。

---

## 2. スコープ

### 2.1 作るもの

| # | 画面 | 優先度 | 母艦との関係 |
|---|---|---|---|
| M1 | 探す（スワイプカードスタック） | A | **新規**（母艦S1タイムラインを置換） |
| M2 | プロフィール詳細 | A | 母艦S2を改修 |
| M3 | 一覧・絞り込み | A | 母艦S3を改修 |
| M4 | マッチ／届いた興味 | A | 母艦S4を改修 |
| M5 | マイプロフィール | B | 母艦S5を改修 |
| M6 | 興味を送るモーダル | A | 母艦S6の枠をほぼ流用 |
| M7 | チャット | B | 母艦S7をそのまま流用 |

### 2.2 作らないもの

- ❌ バックエンド・DB・認証・データ永続化（母艦と同じ）
- ❌ 本物の推薦アルゴリズム（**タグの重なり数**で算出。むしろ仕組みが見えるほうがデモとして良い）
- ❌ 通報・ブロック・本人確認・課金
- ❌ ダークモード切替、多言語、テストコード
- ❌ スワイプの物理演算（慣性・回転は CSS transform で十分）

---

## 3. 技術構成

母艦と完全に同一。Vite + React 18（JSX）／Tailwind CSS v4／lucide-react／Cloudflare Pages。

**1つだけ追加**：スワイプのドラッグ判定に Pointer Events を素で使います（ライブラリ不要、約60行）。

---

## 4. デザイン仕様

### 4.1 方向性

母艦SNSが「明るい背景に浮かぶカード」だったのに対し、こちらは**深いプラム地の"ステージ"に白いカードが1枚だけ立つ**構成。視線をカード1枚に集中させます。

配色は当初案のコーラル×ピンクから変更しました。**あの組み合わせは恋愛マッチングの記号そのもの**で、今回の非恋愛コンセプトと真っ向からぶつかるためです。代わりにアンバー＋エメラルドを採用し、「取引・交換」の温度感に寄せています。

**シグネチャー要素：重なりリング**
カード右上の円弧。自分の「力を借りたいこと」と相手の「できること」が何個重なっているかを弧の長さで表示し、タップすると一致したタグだけが発光します。マッチ率を数字で出すより、**なぜ勧められたのかが一目でわかる**。ここだけに演出を集中させ、他は静かに保ちます。

### 4.2 デザイントークン（`src/theme.css`）

```css
@theme {
  /* ---- Color ---- */
  --color-bg:        #201C2E;  /* ディーププラム：カードが立つ舞台 */
  --color-surface:   #FFFFFF;  /* カード面 */
  --color-surface-2: #2E2842;  /* 背景上のパネル・入力欄 */
  --color-ink:       #17161F;  /* カード内テキスト */
  --color-ink-sub:   #6E6B7E;
  --color-ink-inv:   #F3F1F8;  /* 暗背景上のテキスト */
  --color-line:      #E6E4EC;
  --color-accent:    #FFB020;  /* アンバー：気になる・CTA */
  --color-accent-sub:#2ED3A0;  /* エメラルド：マッチ成立・一致タグ */
  --color-skip:      #8B85A3;  /* 見送る（赤にしない。拒絶の記号を避ける） */

  /* ---- Type ---- */
  --font-display: "Bricolage Grotesque", "Zen Kaku Gothic New", sans-serif; /* 700 */
  --font-body:    "Noto Sans JP", sans-serif;                               /* 400/500 */
  --font-num:     "Space Grotesk", monospace;                               /* 一致数・稼働時間 */

  /* ---- Scale ---- */
  --text-display: 30px/1.25;
  --text-title:   19px/1.45;
  --text-body:    15px/1.75;
  --text-meta:    12px/1.4;

  /* ---- Space ---- */
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px;
  --space-4: 16px; --space-6: 24px; --space-8: 32px;

  /* ---- Shape ---- */
  --radius-card:  24px;   /* 母艦の20pxより大きく：カードが主役なので */
  --radius-input: 14px;
  --radius-pill:  999px;
  --shadow-card:  0 24px 60px rgba(0,0,0,.35);   /* 暗背景なので影は強め */
  --shadow-pop:   0 12px 40px rgba(0,0,0,.45);
}
```

> **`--color-skip` を赤にしない**のは意図的です。恋愛アプリの「×」は拒絶ですが、ここでは「今回は縁がなかった」だけ。ニュートラルグレーで温度を下げます。

### 4.3 レイアウト

| | 仕様 |
|---|---|
| モバイル（〜768px） | カード幅 = 画面幅 - 32px、高さ = 表示領域の68%。下部にアクションボタン3つ |
| PC（769px〜） | カード 400×560px を中央に固定。左に幅240pxの縦ナビ |
| カードスタック | 3枚重ね。2枚目 `scale(.95) translateY(12px)`、3枚目 `scale(.90) translateY(24px)`、透明度も段階的に |
| `prefers-reduced-motion` | ドラッグ追従は残し、弾け演出とスタックの動きだけ無効化 |

### 4.4 画像

母艦と同一。アバターはIDから決定的に生成したグラデーション円＋頭1文字。`public/images/{id}.jpg` を置けば実写に差し替わります。

---

## 5. 画面仕様

### M1. 探す（スワイプカードスタック）★固有画面

**カードの中身（上から）**
1. アバター（72px）＋ 氏名 ＋ 肩書き ＋ エリア
2. **重なりリング**（右上・48px）：一致数を弧で表示。中央に`--font-num`で数字
3. 一言（1〜2行）
4. `できること` チップ群 — 一致したものは `--color-accent-sub` の地に白文字
5. `力を借りたいこと` チップ群 — 同上
6. 稼働：`週2〜3時間 / 平日夜` など

**操作**
| 操作 | 結果 |
|---|---|
| 右へドラッグ or ♡ボタン | 気になる。カードが右上へ回転しながら退場（`rotate(12deg)`） |
| 左へドラッグ or ×ボタン | 見送る。左下へ退場 |
| 上へドラッグ or ✉ボタン | M6「興味を送る」モーダルを開く |
| カードをタップ | M2 プロフィール詳細へ |
| ↩ボタン | **直前の1枚だけ戻せる**（連続不可） |
| キーボード ← → ↑ | 上記に対応（アクセシビリティ必須） |

**ドラッグ中のフィードバック**：移動量80pxを超えたら、進行方向にラベル（`気になる` / `見送る`）がフェードイン。カードは移動量に応じて最大12度傾く。

**マッチ成立演出**：`u01 / u05 / u09` を右スワイプすると必ず発火。暗転オーバーレイ＋2つのアバターが中央で寄り、`マッチしました` ＋ 一致タグを表示。`メッセージを送る` / `続けて探す` の2択。

**カードが尽きたら**：空状態「今日はここまでです」＋`条件を変えて探す`（M3へ）。

### M2. プロフィール詳細

- カード内容の全量表示。スクロール
- `これまでの共創`：3件を箇条書き（例：「ECサイト構築 × 商品撮影」）
- 一致タグを画面上部にサマリー表示
- 下部固定：`見送る` / `興味を送る`

> ★評価スコアやレビューは**入れません**。実体のない星は信頼を作らず、デモの誠実さを落とします。

### M3. 一覧・絞り込み

- 上部フィルタバー：`分野`（開発／デザイン／映像／士業／その他）・`エリア`（オンライン可を含む）・`稼働時間帯`
- 2列カードグリッド（PCは3列）。カードは縮小版
- 並び替え：`一致数が多い順` / `新着順`
- 空状態：「条件に合う人が見つかりません」＋フィルタを1つ外す提案ボタン

### M4. マッチ／届いた興味

- タブ：`マッチ` / `届いた興味`
- **マッチ**：横スクロールのアバター列（新着）＋ 下に会話一覧
- **届いた興味**：相手のカード＋添えられた一言。`ありがとう、話したい` / `今回は見送る` の2択。承諾するとマッチ成立演出を再利用
- 未対応は左端に3pxのアンバーバー

### M5. マイプロフィール

- 自分の `できること` / `力を借りたいこと` をチップで編集（追加・削除は動く）
- **編集すると M1 の重なりリングの数字がリアルタイムで変わる** ← 仕組みが伝わる仕掛け。ここは必ず動かしてください
- 稼働時間帯のセレクト

### M6. 興味を送るモーダル

- ボトムシート（PCは中央モーダル）
- 相手カードの縮小版を上部に固定
- 一言（120字カウンター）。プレースホルダは「一緒にやりたいことを一言で」
- 定型文チップ3つ（`話を聞いてみたいです` / `お互いに補い合えそうです` / `具体的な相談があります`）→ タップで本文に挿入
- 送信 → シート下降 ＋ トースト「興味を送りました」

### M7. チャット

母艦S7をそのまま流用。自分＝右・アンバー地に濃紺文字、相手＝左・白地。送信1.2秒後に `autoReply` から定型返信。

---

## 6. データモデル

```js
// person
{ id:"u01", name:"及川 涼", role:"プロダクトデザイナー",
  area:"東京・中央区", online:true,
  intro:"...",
  canDo:["UIデザイン","Figma","プロトタイピング"],
  wantTo:["フロントエンド実装","個人開発の壁打ち"],
  field:"デザイン",
  availability:"週2〜3時間 / 平日夜",
  works:["ECサイトのUI × 商品撮影","予約システムのUI設計"] }

// me（u00）
{ ...person, canDo:["ノーコード開発","業務自動化","Claude Code"],
  wantTo:["UIデザイン","LPコピー","商品撮影"] }

// 一致数の算出（これだけ。ブラックボックスにしない）
overlap = me.wantTo ∩ person.canDo  →  リングに表示
mutual  = person.wantTo ∩ me.canDo  →  「相互に補える」バッジ

// match
{ personId:"u01", matchedAt:"...", unread:2,
  messages:[{ from:"me"|"them", body:"...", at:"14:02" }],
  autoReply:["ありがとうございます！","来週あたりどうですか？"] }

// incomingInterest
{ personId:"u07", message:"...", receivedAt:"...", status:"pending" }
```

---

## 7. デモデータ

### 7.1 人物（14名）

`できること` と `力を借りたいこと` が**噛み合うペアを意図的に仕込んでいます**（及川↔早瀬、桜庭↔富永、宮下↔千葉）。カードをめくるうちに「あ、この2人つながるな」と読者が気づく設計です。

| id | 氏名 | 肩書き | エリア | できること | 力を借りたいこと | 稼働 |
|---|---|---|---|---|---|---|
| u00 | あなた | ノーコード開発 | 東京・中央区 | ノーコード開発 / 業務自動化 / Claude Code | UIデザイン / LPコピー / 商品撮影 | 週3〜5時間 |
| u01 | 及川 涼 | プロダクトデザイナー | 東京・渋谷 | UIデザイン / Figma / プロトタイピング | フロントエンド実装 / 個人開発の壁打ち | 週2〜3時間 / 平日夜 |
| u02 | 楢崎 健吾 | 管理栄養士 | 大阪 | 献立設計 / 栄養計算 / 監修 | 動画編集 / SNS運用 | 週1〜2時間 / 土日 |
| u03 | 三雲 あさひ | バックエンドエンジニア | オンライン | API設計 / Python / インフラ | ロゴ制作 / LPコピー | 週4〜6時間 |
| u04 | 白鳥 恵理 | 中小企業診断士 | 名古屋 | 事業計画 / 補助金申請 / 資金繰り | 業務自動化 / 自社サイト制作 | 週2時間 / 平日昼 |
| u05 | 桜庭 拓真 | 映像ディレクター | 福岡 | 撮影 / 動画編集 / カラーグレーディング | 音楽制作 / 見積りの相談 | 週3〜4時間 |
| u06 | 泉 みちる | 社会保険労務士 | 札幌 | 就業規則 / 労務相談 / 助成金 | 業務自動化 / 資料デザイン | 週1〜2時間 / 平日夜 |
| u07 | 神谷 拓海 | データアナリスト | 横浜 | SQL / ダッシュボード構築 / 分析設計 | 英語の壁打ち / プレゼン構成 | 週2〜3時間 |
| u08 | 宮下 かなえ | 陶芸家 | 岐阜 | 器の制作 / ワークショップ企画 | ECサイト構築 / 商品撮影 | 週2時間 / 不定 |
| u09 | 早瀬 蓮 | フロントエンドエンジニア | オンライン | React / アニメーション実装 / 保守 | UIデザイン / 企画のネタ出し | 週5〜8時間 |
| u10 | 一之瀬 由紀 | コピーライター | 京都 | LPコピー / ネーミング / 取材記事 | SEO設計 / 表計算の自動化 | 週3時間 / 平日昼 |
| u11 | 富永 廉 | 音楽プロデューサー | 東京・世田谷 | 作編曲 / MA / 音源制作 | 動画編集 / 権利まわりの相談 | 週2〜4時間 / 夜 |
| u12 | 黒木 沙羅 | パーソナルトレーナー | 神戸 | 運動指導 / オンライン指導設計 | 予約システム / 動画撮影 | 週2時間 / 早朝 |
| u13 | 千葉 智也 | 農家（6次産業化） | 長野 | 農作物 / 加工品開発 / 産地の知見 | ブランディング / 商品撮影 / 販路開拓 | 週1〜2時間 |
| u14 | 舞原 詩織 | 通訳・翻訳（英日） | オンライン | 同時通訳 / 技術翻訳 / 字幕 | 音声編集 / 名刺デザイン | 週3〜4時間 |

**一言（intro）**

| id | 一言 |
|---|---|
| u01 | 作ったものが動いているところが見たいだけの人です |
| u02 | 「体にいい」で終わらせず、続けられる形にするのが仕事です |
| u03 | 裏側は得意ですが、表側が壊滅的なので助けてください |
| u04 | 数字の話をやわらかい言葉に翻訳します |
| u05 | 撮る・切る・整えるまで一人で完結できます |
| u06 | 制度は使えるものを使ったほうがいい、という立場です |
| u07 | データを見て終わりにせず、次の一手まで一緒に考えます |
| u08 | 土日は窯の前にいます。器を全国に届けたい |
| u09 | 動くものを最短で作るのが好きです。設計は苦手 |
| u10 | 一行で説明できないものは、たぶんまだ整理されていません |
| u11 | 映像に音が付くと世界が変わるので、その瞬間が好きです |
| u12 | 続かない運動に意味はないと思っています |
| u13 | 畑はあるのに売り方がわからない、を7年やっています |
| u14 | 訳すというより、伝わる形に置き換える仕事です |

### 7.2 スワイプデッキ初期順

`u09 → u01 → u10 → u05 → u13 → u03 → u08 → u11 → u07 → u04 → u12 → u14`

> 1枚目の `u09（早瀬）` は自分の `wantTo:UIデザイン` と重ならず一致数1、2枚目の `u01（及川）` が一致数2。**最初の2枚で「リングの数字が変わる」ことを体感させる**意図的な並びです。

### 7.3 既存マッチ（4件）

| 相手 | 最新メッセージ | 未読 | autoReply |
|---|---|---|---|
| u10 一之瀬 由紀 | LPの構成案、ざっくり作ってみました | 2 | 「見出しだけ先に決めちゃいましょう」／「今週中なら動けます」 |
| u08 宮下 かなえ | 撮影、来週の火曜はいかがですか？ | 1 | 「岐阜まで来ていただく形でも大丈夫ですか？」／「器は15点ほど用意します」 |
| u03 三雲 あさひ | APIの叩き方、こちらで用意しておきます | 0 | 「認証まわりだけ先に共有しますね」／「詰まったらいつでも」 |
| u13 千葉 智也 | 加工品のラベル、意見もらえますか | 0 | 「写真だけ先に送ります」／「トマトの加工品です。名前がまだ決まっていません」 |

### 7.4 届いた興味（3件・未対応）

| 相手 | 添えられた一言 |
|---|---|
| u06 泉 みちる | 顧問先の労務手続きを自動化したくて、相談だけでもできませんか |
| u12 黒木 沙羅 | オンライン指導の予約まわりを整えたいです。お互いに補い合えそうです |
| u04 白鳥 恵理 | 補助金の申請支援と交換で、業務まわりのご相談ができればと思っています |

---

## 8. ディレクトリ構成

母艦と同一。**新規は `features/swipe/` のみ**です。

```
souzoh-match/
├── public/images/
├── src/
│   ├── theme.css           ★差し替え済み（§4.2）
│   ├── app.config.js       ★差し替え（下記）
│   ├── data/
│   │   ├── people.js  matches.js  interests.js  me.js
│   ├── components/ui/      ← 母艦からそのままコピー。触らない
│   │   └── OverlapRing.jsx          ← ★このアプリで追加
│   ├── components/shell/   ← 母艦からそのままコピー
│   ├── features/
│   │   ├── swipe/          ★新規：CardStack.jsx / SwipeCard.jsx / MatchOverlay.jsx
│   │   ├── person-detail/  browse/  matches/  my-profile/
│   │   ├── interest/       ← 母艦 composer/ を改名
│   │   └── chat/           ← 母艦 dm/ をそのまま
│   ├── store.js
│   └── main.jsx
└── README.md
```

```js
// app.config.js
export default {
  appName: "Souzoh Match",
  tagline: "「できる」と「借りたい」で、人はつながる",
  nav: [
    { key:"swipe",   label:"探す",         icon:"Layers" },
    { key:"browse",  label:"一覧",         icon:"LayoutGrid" },
    { key:"matches", label:"マッチ",       icon:"Handshake" },
    { key:"chat",    label:"メッセージ",   icon:"Mail" },
    { key:"me",      label:"プロフィール", icon:"User" },
  ],
  labels: {
    listTitle: "あなたと補い合える人",
    itemNoun: "人",
    createCta: "興味を送る",
    primaryAction: "気になる",
  },
};
```

---

## 9. 実装手順（Claude Codeへの投げ方）

**母艦があるので3セッションで足ります。**

| Session | やること | 冒頭で読ませるもの |
|---|---|---|
| 0 | 母艦リポジトリを複製 → `theme.css` `app.config.js` `data/` を差し替え。**画面は一切触らない**。この時点で一度ビルドを通す | §4.2・§7・§8 |
| 1 | M1 スワイプ（CardStack / SwipeCard / OverlapRing / MatchOverlay） | §4.1・§4.3・§5(M1) |
| 2 | M2 詳細 ＋ M3 一覧 ＋ M4 マッチ | §5(M2〜M4) ＋ 既存 `ui/` |
| 3 | M5 マイプロフィール ＋ M6 モーダル ＋ 仕上げ | §5(M5,M6)・§10 |

**Session 0 を必ず独立させてください。** ここでビルドが通ることを確認してから画面に入ると、後段のエラーが「新規実装のせい」だと確定でき、原因切り分けの往復が消えます。母艦方式で一番効くのがこの一手です。

**Session 1 の指示文テンプレ**：

```
添付の要件定義書 §4.1・§4.3・§5(M1) を実装してください。
src/components/ui/ と src/store.js は完成済みです。新規作成せず import して使ってください。
スワイプは Pointer Events のみで実装し、ライブラリを追加しないでください。
色・余白・角丸は src/theme.css の変数のみを使ってください。
実装前に、作成・変更するファイルの一覧だけ先に提示してください。
```

---

## 10. 受け入れ基準

- [ ] ドラッグ・ボタン・キーボードの3経路でスワイプできる
- [ ] ドラッグ量に応じてカードが傾き、方向ラベルが出る
- [ ] 重なりリングの数字が、M5でタグを編集すると即座に変わる
- [ ] `u01 / u05 / u09` の右スワイプでマッチ演出が出る
- [ ] ↩で直前の1枚だけ戻せる（2連続は不可）
- [ ] デッキが尽きると空状態が出て、M3への導線がある
- [ ] 届いた興味を承諾するとマッチに移り、チャットが開ける
- [ ] 375px幅と1440px幅で崩れない
- [ ] 生の色コードがJSX内に1つも無い
- [ ] `prefers-reduced-motion: reduce` で弾け演出が止まる
- [ ] `npm run build` が警告なく通り、Cloudflare Pagesで表示される

---

## 11. 母艦テンプレからの再利用率

| 領域 | 扱い |
|---|---|
| `components/ui/` 8点 | **そのまま**（OverlapRing のみ追加） |
| `components/shell/` | **そのまま**（`app.config.js` のnavが変わるだけ） |
| `store.js` | 骨格そのまま。アクション名のみ変更（like/skip/sendInterest） |
| チャット（M7） | **そのまま** |
| モーダル（M6） | 枠そのまま。中身のフォームだけ差し替え |
| 一覧・詳細・通知 | 構造流用、中身差し替え |
| スワイプ（M1） | **完全新規**（このアプリ唯一の固有実装） |

実質的な新規実装は**1画面＋1コンポーネント**です。§9のSession 0を守れば、ここまで圧縮できます。

---

## 12. 補足：コスト感

母艦がある分、SNS初回より軽くなります。ただし**スワイプのドラッグ挙動だけは調整の往復が発生しやすい**箇所です。「もう少し軽く」「戻りが速すぎる」といった感覚的な指示は費用がかさむので、閾値を数値で指定してください（判定80px / 傾き最大12度 / 復帰アニメ180ms / 退場220ms）。§4.3と§5(M1)にすでに数値で書いてあるので、そのまま渡せば1〜2回で決まります。
