• #nuxt
  • #vue
  • #leaflet
  • #地図
  • #仕様書
開発アクティブ

東京散歩ルートマップ - Nuxt/Vue移行プロジェクト

📋 要件定義書

1. プロジェクト概要

東京の散歩ルートを地図上に表示し、各スポットの情報を可視化するインタラクティブなWebアプリケーション。 alt text

1.1 ターゲット顧客

セグメント優先度ニーズ
観光協会・自治体◎ 主要地域PRコンテンツとして配布・埋め込み
地域メディア・Webマガジン◎ 主要記事への埋め込み、差別化コンテンツ
旅行会社・ツアー企画○ 副次ツアールート説明資料
個人ブロガー△ 補助無料版での認知拡大(リード獲得)

1.2 収益モデル(B2B SaaS)

プラン月額内容
Free無料3ルートまで、透かしあり、コミュニティサポート
Pro¥4,980無制限ルート、透かしなし、CMS利用、優先サポート
Enterprise個別見積ホワイトラベル、専用ドメイン、SLA保証、オンボーディング

追加収益オプション:

  • ルート制作代行: ¥30,000〜/ルート
  • カスタム開発: 時間単価

1.3 コスト構造・スケール方針

項目現状(MVP)スケール時
地図タイルOpenStreetMap公開サーバーCloudflareキャッシュまたはMapTiler有料
ルーティングOSRM公開サーバー(ビルド時のみ)自前OSRM Docker or 事前生成JSON
ホスティングCloudflare Pages(無料枠)Workers有料プラン
想定限界月10万PV程度100万PV以上は要検討

🔍 競合分析・市場調査

既存サービスとの比較

サービス道沿いルートスポット常時表示編集可能料金
本プロジェクト無料
NAVITIME Travel△(電車メイン)無料〜
ALKOO by NAVITIME無料〜
プラチナマップ月7,980円〜
TOKYO WALKING MAP無料
Googleマイマップ無料

既存サービスの課題

  1. NAVITIME Travel / ALKOO
    • 健康・移動効率が目的で、観光ガイドとしてのストーリー性がない
    • スポットの解説が地図上に表示されない
  2. プラチナマップ
    • 高機能だがB2B向けで月額課金
    • 個人や小規模メディアには高コスト
  3. Googleマイマップ
    • 自由にピンは立てられるが道沿いルート表示ができない
    • スポット情報はクリックしないと見えない
  4. 従来の観光記事(テキスト+画像)
    • インタラクティブ性ゼロ
    • 読者が自分でGoogleマップにマッピングする手間

本プロジェクトの差別化ポイント

  1. OSRMによる実際の道路に沿ったルート表示
  2. スポット情報(名前・説明・タグ)を地図上に常時表示
  3. ツールチップの重なり回避アルゴリズムで視認性確保
  4. KMLエクスポートでGoogleマップ連携可能
  5. 完全無料・オープンソースでカスタマイズ自由
  6. ストーリー性のある観光ガイドとして活用可能

想定ユースケース

  • 地域の観光協会が「おすすめ散歩ルート」を配布
  • 個人ブロガーが「私の散歩ルート」を記事に埋め込み
  • 旅行者が自分用にルートをカスタマイズ
  • 地域メディアがインタラクティブな観光コンテンツを制作

🛠️ コア技術: OSRM (Open Source Routing Machine)

OSRMとは

OpenStreetMapのデータを使ったオープンソースのルーティングエンジン。 Googleマップのルート検索と同等の機能を、無料で利用できる。

API仕様

GET https://router.project-osrm.org/route/v1/{profile}/{coordinates}

profile: foot(徒歩), driving(車), bike(自転車)
coordinates: 経度1,緯度1;経度2,緯度2;経度3,緯度3...

リクエスト例

https://router.project-osrm.org/route/v1/foot/139.7706,35.7279;139.8107,35.7101?overview=full&geometries=geojson

レスポンス例

{
  "routes": [{
    "geometry": {
      "type": "LineString",
      "coordinates": [[139.7706, 35.7279], [139.7710, 35.7275], ...]
    },
    "distance": 5234.5,
    "duration": 3920.2
  }]
}

主要パラメータ

パラメータ説明
overviewfull詳細なルート座標を取得
geometriesgeojsonGeoJSON形式で座標を取得
stepstrueターンバイターン案内を取得(オプション)

利用上の注意

  • 無料で利用可能(公開デモサーバー)
  • 大量リクエストの場合は自前サーバー推奨
  • OpenStreetMapのデータに依存(日本は精度高い)

2. 機能要件

2.1 ルート表示機能

  • 複数の散歩ルートをタブで切り替え表示
  • 各ルートは異なるテーマカラーを持つ
  • ルートは実際の歩行経路(OSRM API使用)で描画
  • スタート地点は赤、ゴール地点は紫、経由地点はテーマカラーで表示

2.2 スポット表示機能

  • 各スポットに番号付きマーカーを表示
  • ツールチップ(吹き出し)でスポット情報を常時表示
    • スポット名
    • 説明文
    • カテゴリタグ(絵文字付き)
  • ツールチップは自動配置で重なりを回避

2.3 ツールチップ重なり回避アルゴリズム

  • 各マーカーのピクセル座標を計算
  • 4方向(右・左・上・下)を評価
  • スコアリング方式で最適な方向を決定
    • 他のツールチップとの重なり: -100点
    • 他のマーカーとの重なり: -80点
    • ルートラインとの重なり: -30点
    • 画面外にはみ出す: -50点
    • 右方向を優先: +5点
    • 上方向を優先: +3点
  • 地図のズーム・移動時に再計算

2.4 スポットリスト機能

  • 画面下部にスポット一覧を表示
  • スクロール可能
  • タップで該当スポットにズーム

2.5 KMLエクスポート機能

  • 現在表示中のルートをKML形式でダウンロード
  • Googleマイマップにインポート可能な形式

KMLフォーマット仕様:

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
  <Document>
    <name>ルート名</name>
    <description>ルートの説明</description>

    <!-- ルートライン用スタイル -->
    <Style id="routeLine">
      <LineStyle>
        <color>FF00FF00</color>  <!-- AABBGGRR形式(アルファ+BGR) -->
        <width>4</width>
      </LineStyle>
    </Style>

    <!-- スポットマーカー用スタイル -->
    <Style id="spotMarker">
      <IconStyle>
        <Icon>
          <href>http://maps.google.com/mapfiles/kml/paddle/red-circle.png</href>
        </Icon>
      </IconStyle>
    </Style>

    <!-- ルートライン -->
    <Placemark>
      <name>ルート</name>
      <styleUrl>#routeLine</styleUrl>
      <LineString>
        <coordinates>
          139.7706,35.7279,0
          139.7904,35.7299,0
          <!-- lng,lat,altitude 形式 -->
        </coordinates>
      </LineString>
    </Placemark>

    <!-- スポット(各ポイント) -->
    <Placemark>
      <name>1. 日暮里駅</name>
      <description><![CDATA[スタート地点<br/>🚃 駅]]></description>
      <styleUrl>#spotMarker</styleUrl>
      <Point>
        <coordinates>139.7706,35.7279,0</coordinates>
      </Point>
    </Placemark>
  </Document>
</kml>

注意点:

  • KMLの座標は lng,lat,altitude 順(GeoJSONと同じ)
  • 色は AABBGGRR 形式(HEX #RRGGBB から変換が必要)
  • CDATAでHTMLタグを含む説明文をエスケープ

2.6 ルート情報表示

  • ルート名
  • サブタイトル(ルートの特徴)
  • 総距離
  • 所要時間

2.7 CMS(管理画面)機能

対象ユーザー: 観光協会担当者、メディア編集者(非エンジニア)

ルート管理
  • ルート一覧表示(作成日順/更新日順)
  • ルート新規作成
  • ルート編集(タイトル、説明、テーマカラー)
  • ルート削除(確認ダイアログ付き)
  • ルート複製(テンプレートとして再利用)
スポット管理
  • 地図クリックでスポット追加
  • ドラッグ&ドロップで順序変更
  • スポット情報編集(名前、説明、タグ選択)
  • スポット削除
  • 住所・施設名から座標検索(Nominatim API)
プレビュー・公開
  • リアルタイムプレビュー(編集中に地図反映)
  • 下書き保存
  • 公開/非公開切り替え
  • 埋め込みコード生成(iframe)
ユーザー管理(Enterprise向け)
  • チームメンバー招待
  • 権限管理(閲覧のみ/編集可/管理者)
  • 編集履歴・監査ログ

技術方針:

  • 認証: Cloudflare Access または Auth0
  • データ保存: Cloudflare D1 (SQLite)
  • 画像アップロード: Cloudflare R2

3. 非機能要件

3.1 パフォーマンス

指標目標値測定条件
LCP (Largest Contentful Paint)2.5秒以内4G回線、Moto G4相当
FCP (First Contentful Paint)1.8秒以内同上
ルート切り替え500ms以内事前生成済みデータ使用時
ツールチップ再計算100ms以内20スポット以下を前提

制約条件:

  • 1ルートあたりの最大スポット数: 20件
  • ツールチップ再計算: debounce 150ms で発火抑制
  • 地図移動中は再計算スキップ(moveendイベントで実行)

3.2 レスポンシブ対応

ブレークポイントツールチップ表示スポットリスト
モバイル(〜767px)ズームレベル15以上で表示、14以下は非表示ボトムシート形式
タブレット(768px〜1023px)常時表示(最大10件)、残りは折りたたみサイドパネル
デスクトップ(1024px〜)常時表示(全件)サイドパネル

3.3 ブラウザ対応

  • Chrome(最新2バージョン)
  • Safari(最新2バージョン)
  • Firefox(最新2バージョン)
  • Edge(最新2バージョン)

3.4 SSR/CSR方針

Leafletはブラウザ専用のため、クライアントサイドのみで描画する。

<!-- 実装方針 -->
<ClientOnly>
  <LMap :zoom="zoom" :center="center">
    <!-- 地図コンテンツ -->
  </LMap>
  <template #fallback>
    <div class="map-skeleton">地図を読み込み中...</div>
  </template>
</ClientOnly>
  • <ClientOnly> でラップ
  • フォールバックにスケルトンUIを表示
  • Leaflet関連コンポーネントは動的import不要(vue-leafletが対応済み)

3.5 OSRM利用方針

項目方針
実行タイミングビルド時に事前生成(SSG)
保存形式GeoJSON形式でJSONファイルに保存
フォールバックAPI失敗時は直線(スポット間を結ぶPolyline)で描画
キャッシュ生成済みGeoJSONを public/routes/ に配置
更新トリガースポット座標変更時のみ再生成
// ビルドスクリプト例
// scripts/generate-routes.ts
async function generateRoute(spots: Spot[]): Promise<GeoJSON.LineString> {
  const coords = spots.map(s => `${s.lng},${s.lat}`).join(';');
  const url = `https://router.project-osrm.org/route/v1/foot/${coords}?overview=full&geometries=geojson`;

  try {
    const res = await fetch(url);
    const data = await res.json();
    return data.routes[0].geometry;
  } catch {
    // フォールバック: 直線
    return {
      type: 'LineString',
      coordinates: spots.map(s => [s.lng, s.lat])
    };
  }
}

3.6 法的要件

項目対応
OSMクレジット地図右下に © OpenStreetMap contributors を常時表示(必須)
OSRMクレジットフッターに Powered by OSRM を表示(推奨)
タイル利用規約OSM Tile Usage Policyに準拠(過度なアクセス禁止)
プライバシー位置情報は取得しない(ユーザー追跡なし)

4. 技術スタック

項目技術
フレームワークNuxt 3
UIフレームワークVue 3 (Composition API)
地図ライブラリLeaflet + vue-leaflet
スタイリングTailwind CSS または CSS Modules
状態管理Pinia(必要に応じて)
ルーティングAPIOSRM (Project OSRM)
地図タイルOpenStreetMap

5. データ構造

// ========================================
// タグ辞書(アイコン・表示名の一元管理)
// ========================================
const TAG_DICTIONARY = {
  station: { icon: '🚃', label: '' },
  shrine: { icon: '⛩️', label: '神社' },
  temple: { icon: '🛕', label: '寺院' },
  park: { icon: '🌳', label: '公園' },
  shopping: { icon: '🛒', label: '商店街' },
  cafe: { icon: '', label: 'カフェ' },
  bridge: { icon: '🌉', label: '' },
  landmark: { icon: '🗼', label: 'ランドマーク' },
  history: { icon: '🏛️', label: '史跡' },
  food: { icon: '🍛', label: 'グルメ' },
  music: { icon: '🎸', label: '楽器街' },
  books: { icon: '📚', label: '本の街' },
  flower: { icon: '🌸', label: '花の名所' },
} as const;

type TagId = keyof typeof TAG_DICTIONARY;

// ========================================
// ルート型定義
// ========================================
interface Route {
  id: string;                    // UUID形式推奨
  title: string;
  subtitle: string;
  distance: number;              // メートル単位(表示時に変換)
  duration: number;              // 秒単位(表示時に変換)
  color: string;                 // HEX形式 #RRGGBB
  spots: Spot[];
  geometry?: GeoJSON.LineString; // 事前生成されたルート
  createdAt: string;             // ISO8601
  updatedAt: string;             // ISO8601
}

// ========================================
// スポット型定義
// ========================================
interface Spot {
  id: string;                    // UUID形式推奨
  order: number;                 // 表示順(1始まり)
  name: string;
  lat: number;
  lng: number;
  description: string;
  tags: TagId[];                 // 複数タグ対応(配列)
  role: 'start' | 'waypoint' | 'end';
}

// ========================================
// マーカー色の優先順位
// ========================================
// role による色決定(テーマカラーより優先)
const MARKER_COLORS = {
  start: '#e74c3c',    // 赤(固定)
  end: '#9b59b6',      // 紫(固定)
  waypoint: null,      // ルートのテーマカラーを使用
} as const;

// ========================================
// ツールチップ位置計算用
// ========================================
interface TooltipPosition {
  direction: 'top' | 'bottom' | 'left' | 'right';
  offset: [number, number];
  score: number;
}

interface PixelRect {
  left: number;
  right: number;
  top: number;
  bottom: number;
}

// ========================================
// 座標形式の統一ルール
// ========================================
// - データ定義: { lat, lng } オブジェクト形式
// - Leaflet: [lat, lng] 配列(LatLngTuple)
// - GeoJSON: [lng, lat] 配列(Position)
//
// 変換ユーティリティ:
// const toLeaflet = (s: Spot): [number, number] => [s.lat, s.lng];
// const toGeoJSON = (s: Spot): [number, number] => [s.lng, s.lat];

6. コンポーネント設計

src/
├── components/
│   ├── map/
│   │   ├── WalkingMap.vue        # メイン地図コンポーネント
│   │   ├── RouteMarker.vue       # マーカーコンポーネント
│   │   ├── RoutePolyline.vue     # ルート線コンポーネント
│   │   └── SpotTooltip.vue       # ツールチップコンポーネント
│   ├── ui/
│   │   ├── RouteTabs.vue         # ルート切り替えタブ
│   │   ├── RouteHeader.vue       # ルート情報ヘッダー
│   │   ├── SpotList.vue          # スポット一覧
│   │   ├── SpotListMobile.vue    # モバイル用ボトムシート
│   │   └── KmlDownloadButton.vue # KMLダウンロードボタン
│   ├── admin/                    # CMS用コンポーネント
│   │   ├── RouteEditor.vue       # ルート編集フォーム
│   │   ├── SpotEditor.vue        # スポット編集フォーム
│   │   ├── MapEditor.vue         # 地図上でのスポット編集
│   │   ├── TagSelector.vue       # タグ選択UI
│   │   ├── ColorPicker.vue       # テーマカラー選択
│   │   └── EmbedCodeGenerator.vue # 埋め込みコード生成
├── composables/
│   ├── useRouteData.ts           # ルートデータ管理
│   ├── useTooltipPlacement.ts    # ツールチップ配置計算
│   ├── useOsrmRoute.ts           # OSRM API呼び出し(ビルド時)
│   ├── useKmlExport.ts           # KMLエクスポート
│   ├── useGeocode.ts             # 住所→座標変換(Nominatim)
│   └── useResponsiveTooltip.ts   # レスポンシブ対応制御
├── stores/                       # Pinia ストア
│   ├── route.ts                  # ルート状態管理
│   └── editor.ts                 # CMS編集状態管理
├── data/
│   └── routes.ts                 # ルートデータ定義
├── types/
│   └── index.ts                  # 型定義
├── pages/
│   ├── index.vue                 # 公開ビュー(ルート一覧)
│   ├── routes/[id].vue           # ルート詳細ページ
│   └── admin/                    # CMS管理画面
│       ├── index.vue             # ダッシュボード
│       ├── routes/index.vue      # ルート一覧
│       └── routes/[id].vue       # ルート編集
└── server/
    └── api/
        ├── routes/               # ルートCRUD API
        └── geocode.ts            # 住所検索プロキシ

7. 初期ルートデータ

ルート1: 日暮里→スカイツリー

#スポット名緯度経度説明タグ
1日暮里駅35.7279139.7706スタート地点🚃 出発
2ジョイフル三の輪35.7299139.7904昭和レトロな商店街🛒 商店街
3浄閑寺35.7264139.7930吉原遊女の歴史🛕 寺社
4山谷堀公園35.7186139.7993江戸時代の船着場跡🌳 公園
5今戸神社35.7166139.8017招き猫・縁結び⛩️ 神社
6隅田公園35.7117139.8030桜の名所🌸 公園
7すみだリバーウォーク35.7105139.80502020年開通の橋🌉 橋
8東京ミズマチ35.7095139.8075高架下カフェ☕ カフェ
9東京スカイツリー35.7101139.8107634mのランドマーク🗼 ゴール

ルート2: 神田→上野

#スポット名緯度経度説明タグ
1神田駅35.6918139.7709ビジネス街🚃 出発
2神田古書店街35.6958139.7580世界最大級130店舗📚 本の街
3神保町35.6959139.7574カレーの聖地🍛 グルメ
4御茶ノ水35.6998139.7651楽器店街🎸 楽器街
5聖橋35.7010139.7680美しいアーチ橋🌉 橋
6湯島聖堂35.7020139.7690江戸の学問所🏛️ 史跡
7湯島天神35.7079139.7687学問の神様⛩️ 神社
8不忍池35.7120139.7710蓮の名所🌺 公園
9アメ横35.7074139.7747食べ歩き天国🛒 商店街
10上野駅35.7141139.7774文化施設も多い🚃 ゴール

🤖 実装プロンプト

以下をClaude等のAIに渡してください:


プロンプト

Nuxt 3 + Vue 3 (Composition API) + Leafletで、東京の散歩ルートマップアプリを作成してください。

## 要件

### 基本機能
1. 複数の散歩ルートをタブで切り替え表示
2. 各スポットに番号付きマーカーを表示
3. スポット情報(名前・説明・タグ)をツールチップで常時表示
4. スポットリストをタップで該当地点にズーム
5. KMLファイルをダウンロードできるボタン

### 重要な実装ポイント:ツールチップの重なり回避

ツールチップが他のツールチップ、マーカー、ルートラインと重ならないよう、
ピクセル座標ベースで自動配置を計算してください。

アルゴリズム:
1. 各マーカーの画面上のピクセル座標を取得
2. 4方向(右・左・上・下)それぞれにツールチップを置いた場合の矩形を計算
3. スコアリングで最適な方向を決定
   - 他のツールチップとの重なり: -100点
   - 他のマーカーとの重なり: -80点
   - ルートラインとの重なり: -30点
   - 画面外にはみ出す: -50点
   - 右方向を優先: +5点
4. 地図のズーム・移動時に再計算

### 技術スタック
- Nuxt 3
- Vue 3 Composition API
- @vue-leaflet/vue-leaflet
- Tailwind CSS
- OSRM API(歩行ルート取得)

### ルートデータ

ルート1: 日暮里→スカイツリー(テーマカラー: #2ecc71)
- 日暮里駅 (35.7279, 139.7706) - スタート
- ジョイフル三の輪 (35.7299, 139.7904) - 昭和レトロな商店街
- 浄閑寺 (35.7264, 139.7930) - 吉原遊女の歴史
- 山谷堀公園 (35.7186, 139.7993) - 江戸時代の船着場跡
- 今戸神社 (35.7166, 139.8017) - 招き猫・縁結び
- 隅田公園 (35.7117, 139.8030) - 桜の名所
- すみだリバーウォーク (35.7105, 139.8050) - 2020年開通の橋
- 東京ミズマチ (35.7095, 139.8075) - 高架下カフェ
- 東京スカイツリー (35.7101, 139.8107) - ゴール

ルート2: 神田→上野(テーマカラー: #3498db)
- 神田駅 (35.6918, 139.7709) - スタート
- 神田古書店街 (35.6958, 139.7580) - 世界最大級130店舗
- 神保町 (35.6959, 139.7574) - カレーの聖地
- 御茶ノ水 (35.6998, 139.7651) - 楽器店街
- 聖橋 (35.7010, 139.7680) - 美しいアーチ橋
- 湯島聖堂 (35.7020, 139.7690) - 江戸の学問所
- 湯島天神 (35.7079, 139.7687) - 学問の神様
- 不忍池 (35.7120, 139.7710) - 蓮の名所
- アメ横 (35.7074, 139.7747) - 食べ歩き天国
- 上野駅 (35.7141, 139.7774) - ゴール

### ファイル構成
composables/でロジックを分離し、再利用可能な形にしてください。
特にuseTooltipPlacement.tsでツールチップ配置ロジックを切り出してください。

📁 参考:元のHTMLファイル

tokyo-walk-routes-v3.html を同梱しています。 このファイルの実装を参考にNuxt/Vue版を作成してください。

特に以下の関数が重要です:

  • updateTooltipPositions() - ツールチップ配置計算
  • getTooltipRect() - 方向ごとの矩形計算
  • rectsOverlap() - 矩形の重なり判定
  • lineIntersectsRect() - ルートと矩形の交差判定
  • generateKML() - KML生成
  • fetchRoute() - OSRM API呼び出し

✅ 実装チェックリスト

Phase 1: プロジェクトセットアップ(1-2日)

  • Nuxt 3プロジェクト作成(別リポジトリ)
  • vue-leaflet インストール・ClientOnly設定
  • Tailwind CSS設定
  • 型定義作成(types/index.ts)
  • タグ辞書定義(TAG_DICTIONARY)
  • ESLint/Prettier設定

Phase 2: ビルドスクリプト(1日)

  • scripts/generate-routes.ts 作成
  • OSRM API呼び出し・GeoJSON保存
  • フォールバック(直線描画)実装
  • npm script追加(pnpm generate:routes

Phase 3: 地図基本機能(2-3日)

  • 地図表示(OpenStreetMapタイル)
  • OSMクレジット表示
  • マーカー表示(role別色分け)
  • ルートライン表示(事前生成GeoJSON読み込み)
  • ルートデータのJSON定義

Phase 4: ツールチップ(2-3日)

  • 基本表示(名前・説明・タグ)
  • 重なり回避アルゴリズム(useTooltipPlacement.ts)
  • debounce 150ms 実装
  • ズーム・移動時の再計算(moveend イベント)

Phase 5: レスポンシブUI(2日)

  • デスクトップ:サイドパネル+全ツールチップ
  • タブレット:サイドパネル+10件制限
  • モバイル:ボトムシート+ズーム連動表示
  • タブ切り替えUI
  • ルート情報ヘッダー

Phase 6: エクスポート機能(1日)

  • KML生成ロジック(useKmlExport.ts)
  • 色変換(HEX→AABBGGRR)
  • ダウンロードボタンUI
  • Googleマイマップでの動作確認

Phase 7: CMS基盤(3-4日)

  • Cloudflare D1スキーマ設計
  • ルートCRUD API(server/api/routes/)
  • 認証設定(Cloudflare Access)
  • 管理画面ルーティング(/admin/)

Phase 8: CMS編集機能(4-5日)

  • ルート一覧ページ
  • ルート編集フォーム(タイトル、説明、色)
  • 地図クリックでスポット追加
  • スポットドラッグ&ドロップ順序変更
  • タグ選択UI
  • 住所検索(Nominatim連携)
  • リアルタイムプレビュー

Phase 9: 公開・埋め込み(2日)

  • 公開/非公開切り替え
  • 埋め込みコード生成(iframe)
  • 埋め込み用軽量ビュー(/embed/id

Phase 10: 仕上げ(2-3日)

  • Lighthouse パフォーマンス測定
  • ユニットテスト(Vitest)
  • E2Eテスト(Playwright)
  • ドキュメント整備

📊 工数見積もり

Phase内容見積もり
1-6MVP(公開ビューのみ)10-12日
7-9CMS機能9-11日
10品質保証2-3日
合計21-26日(1人月程度)

優先順位:

  1. Phase 1-6 を先行リリース(MVP)
  2. ユーザーフィードバック収集
  3. Phase 7-10 でCMS追加