Skip to content

システム構成図

全体アーキテクチャ

┌─────────────────────────────────────────────────────────┐
│                     ユーザー (ブラウザ / PWA)              │
└────────────────────────────┬────────────────────────────┘


┌─────────────────────────────────────────────────────────┐
│                  React + Vite (SPA)                      │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐   │
│  │ 地図表示  │ │ 検索UI   │ │ プラン管理│ │ ダッシュ  │   │
│  │ (Leaflet)│ │          │ │ (D&D)    │ │ ボード    │   │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘   │
│                    Zustand (状態管理)                     │
└────────────────────────────┬────────────────────────────┘
                             │ REST API

┌─────────────────────────────────────────────────────────┐
│                 Node.js + Express                        │
│  ┌───────────┐ ┌───────────┐ ┌───────────┐             │
│  │ 認証      │ │ マイル検索 │ │ プラン管理│             │
│  │ (JWT)     │ │ サービス   │ │ サービス  │             │
│  └───────────┘ └───────────┘ └───────────┘             │
│  ┌───────────┐ ┌───────────┐                            │
│  │ 宿泊検索  │ │ レコメンド │                            │
│  │ サービス   │ │ エンジン   │                            │
│  └─────┬─────┘ └───────────┘                            │
│        │                                                │
│  ┌─────▼─────────────────────────────────┐              │
│  │         SQLite (better-sqlite3)        │              │
│  │  マイルチャート / 空港 / ユーザー / プラン  │              │
│  └───────────────────────────────────────┘              │
└────────────────────────────┬────────────────────────────┘
                             │ 外部API呼び出し

┌─────────────────────────────────────────────────────────┐
│                   外部サービス                            │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐   │
│  │楽天トラベル│ │ agoda    │ │ trip.com │ │booking   │   │
│  │ API      │ │ API      │ │ API      │ │.com API  │   │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘   │
└─────────────────────────────────────────────────────────┘

データフロー

マイル検索フロー

ユーザー入力(所持マイル、出発空港、日程)


フロントエンド: 検索パラメータのバリデーション


API: GET /api/v1/search/destinations

  ├── マイルチャートDB から候補路線を抽出
  │   (所持マイル ≥ 必要マイル数)

  ├── シーズン判定(日程 → L/R/H)

  ├── 各目的地の宿泊情報を並行取得
  │   ├── 楽天トラベル API
  │   ├── agoda API
  │   ├── trip.com API
  │   └── booking.com API


レスポンス: 目的地リスト
  ├── 必要マイル数
  ├── 航空券の通常価格(マイル効率算出用)
  ├── 宿泊最安値(4社比較済み)
  └── 総コスト概算

逆引きレコメンドフロー

ユーザー入力(予算上限、日数、出発空港)


API: GET /api/v1/search/recommend

  ├── 全路線から候補を抽出

  ├── 各候補にスコアリング
  │   ├── マイル効率 = 通常価格 ÷ 必要マイル
  │   ├── 宿泊コスパ = 最安値 ÷ 評価
  │   └── 総合スコア = 加重平均


レスポンス: ランキング形式のレコメンドリスト

デプロイ構成

Docker(セルフホスト)

yaml
# docker-compose.yml
services:
  app:
    image: miletrek:latest
    ports:
      - "3000:3000"
    volumes:
      - ./data:/app/data      # SQLite DB
      - ./uploads:/app/uploads # ユーザーアップロード
    environment:
      - NODE_ENV=production
      - JWT_SECRET=${JWT_SECRET}
    restart: unless-stopped

ポート構成

ポート用途
3000Express (API + SPA配信)

Express が Vite でビルドされた SPA の静的ファイルも配信する(単一ポート構成)。