コンテンツにスキップ

システムアーキテクチャ設計書

システム概要

リツビ BtoB ECサイトの技術スタック全体とアーキテクチャ設計をまとめた文書です。

ローカル開発環境アーキテクチャ

開発環境の構成

ローカル開発環境では、Vendureサーバーはホストマシンで直接実行され、依存サービス(PostgreSQL、Redis等)のみがDockerコンテナで実行されます。これはVendure開発における標準的な構成です。

アーキテクチャ図

┌─────────────────────────────────────────────────────────────┐
│  ホストマシン (開発環境)                                      │
│                                                             │
│  ┌──────────────────────────────────────────────────────┐  │
│  │ Vendure Server (Node.js) - ホストで直接実行          │  │
│  │ - TypeScript watch mode (自動コンパイル)             │  │
│  │ - nodemon (ホットリロード)                           │  │
│  │ - Port: 3021                                        │  │
│  │ - デバッガ直接アタッチ可能                           │  │
│  └──────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌──────────────────────────────────────────────────────┐  │
│  │ Dashboard (Vite) - ホストで直接実行                  │  │
│  │ - Vite dev server                                    │  │
│  │ - Port: 5173                                        │  │
│  └──────────────────────────────────────────────────────┘  │
│                                                             │
│  ┌──────────────────────────────────────────────────────┐  │
│  │ Docker Compose Services                              │  │
│  │                                                       │  │
│  │  - PostgreSQL (Port: 5433)                          │  │
│  │  - Redis (Port: 6379)                                │  │
│  │  - pgAdmin (Port: 8080)                              │  │
│  │  - MailCatcher (Port: 1080/1025)                    │  │
│  │  - Redis Commander (Port: 8081)                      │  │
│  └──────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────┘

この構成を採用する理由

  1. ホットリロードの高速化: TypeScriptのウォッチモードやnodemonによる再起動が、コンテナ内よりもホストマシンで直接実行する方が高速
  2. デバッグの容易さ: VS Codeなどのデバッガを直接アタッチでき、ブレークポイントやプロファイル調査が容易
  3. 開発効率: コンテナのビルドや再起動のオーバーヘッドがなく、開発サイクルが速い
  4. 依存サービスの分離: データベースやキャッシュなどの依存サービスだけをDocker化することで、本番環境に近い状態を維持しつつ、アプリケーション自体は軽量に開発できる

本番環境との違い

項目 ローカル開発環境 本番環境(Fly.io)
Vendureサーバー ホストマシンで直接実行 Dockerコンテナ内で実行
PostgreSQL Dockerコンテナ 独立したFly.ioアプリ(ritsubi-postgres-db
Redis Dockerコンテナ 未使用(in-memoryキャッシュ)
ホットリロード TypeScript watch + nodemon なし(ビルド済み)
デバッグ VS Code直接アタッチ可能 ログベース
メール送信 MailCatcher(開発用) 実際のSMTPサーバー
開発ツール MailCatcher、pgAdmin、Redis Commander 使用しない

詳細は apps/vendure-server/LOCAL_DEVELOPMENT.md を参照してください。

本番環境(Fly.io)コンテナ化アーキテクチャ

コンテナ化の単位

Fly.ioへのデプロイでは、Vendureサーバー(ritsubi-vendure-server)とその依存パッケージのみが1つのコンテナに含まれます

ビルドコンテキストと含まれるパッケージ

  • ビルドコンテキスト: プロジェクトルート(monorepo全体)
  • 含まれるパッケージ:
  • ritsubi-vendure-server(メインアプリケーション)
  • @ritsubi/plugins(カスタムプラグイン)
  • @ritsubi/domain(ドメインモデル)
  • @ritsubi/utils(ユーティリティ)
  • @ritsubi/shared-graphql(GraphQLスキーマ)
  • 除外されるパッケージ: ritsubi-storefront、その他の非依存パッケージ

マルチステージビルド

Dockerfile.flyは3段階のマルチステージビルドを使用:

  1. baseステージ: 全ワークスペースパッケージをビルド
  2. deployステージ: 本番依存関係のみをインストールし、pnpm deployで展開
  3. runnerステージ: 最小限のランタイムイメージにコピー

コンテナ内の構造

/app/apps/vendure-server/     # Vendureサーバー本体
├── dist/                      # ビルド済みTypeScript
├── node_modules/              # 依存関係(pnpm deployで展開)
└── src/                       # ソースコード(デバッグ用)

/app/packages/                 # 依存するワークスペースパッケージ
├── plugins/
├── domain/
├── utils/
└── shared-graphql/

デプロイフロー

  1. ビルド: ルートディレクトリをコンテキストとしてDockerイメージをビルド
  2. プッシュ: Fly.io Registryにイメージをプッシュ
  3. デプロイ: Blue-Greenデプロイメント戦略で展開
  4. マイグレーション: release_commandでデータベースマイグレーション実行
  5. 起動: アプリケーションを起動

詳細は apps/vendure-server/DEPLOYMENT.md を参照してください。

アーキテクチャ概要

システム構成

graph TB
    subgraph "Internet"
        U[ユーザー]
        CF[Cloudflare CDN]
    end

    subgraph "Cloudflare Pages (Global Edge)"
        subgraph "Next.js Storefront"
            NS1[Edge Function (App Router)]
            NS2[Edge Function (API Routes)]
        end
    end

    subgraph "Fly.io Tokyo Region (nrt)"
        subgraph "Vendure Backend"
            V1[Vendure Instance 1]
            V2[Vendure Instance 2]
            WK[Worker Instance]
        end

        subgraph "Data Layer"
            PG[(Fly Postgres)]
            UP[(Upstash Redis)]
            VOL[Fly Volumes]
        end
    end

    subgraph "External Services"
        SMTP[メール配信]
        PAY[決済ゲートウェイ]
        ERP[SMILE ERP]
        S3[Wasabi Object Storage]
    end

    U --> CF
    CF --> NS1
    CF --> NS2
    NS1 --> V1
    NS2 --> V2
    V1 --> PG
    V2 --> PG
    V1 --> UP
    V2 --> UP
    WK --> UP
    WK --> PG
    V1 --> VOL
    V2 --> VOL
    V1 --> S3
    V1 --> SMTP
    V2 --> PAY
    V1 --> ERP

技術スタック一覧

全体構成

コンポーネント 技術/サービス 目的
Frontend Next.js 15.5 (App Router) React SSR/SSG Storefront
Backend Vendure 3.4 (Node.js/TypeScript) Headless E-commerce Engine
Database PostgreSQL 17 + PGroonga (Fly.io Docker) メインデータストレージ
Cache/Queue Upstash Redis セッション管理、ジョブキュー
Storage Wasabi (S3 互換) + Fly Volumes アセット保管とローカルキャッシュ
CDN Cloudflare 静的アセット配信
Hosting (FE) Cloudflare Pages (Edge Functions) グローバルエッジでのSSR/静的配信
Hosting (BE) Fly.io (Tokyo Region) コンテナオーケストレーション

フロントエンド技術スタック

技術 バージョン 用途
Next.js 15.x React フレームワーク
React 19.x UI ライブラリ
TypeScript 5.2.2 型安全性
Tailwind CSS 4.1.13 スタイリング
shadcn/ui Latest UI コンポーネント
Apollo Client 3.8.0 GraphQL クライアント
Radix UI 1.2.12 UI プリミティブ
Lucide React 0.544.0 アイコンライブラリ
React Hook Form 7.47.0 フォーム管理
Zod 3.22.4 バリデーション
Embla Carousel 8.x スライダー・カルーセル

バックエンド技術スタック

技術 バージョン 用途
Vendure 3.4.3 E-commerce エンジン
Node.js 22.x ランタイム
TypeScript 5.2.2 型安全性
GraphQL 16.11.0 API
PostgreSQL 17.x + PGroonga 4.0.4 データベース
Redis 7.x キャッシュ・キュー
NestJS 10.3.10 フレームワーク
TypeORM 0.3.17 ORM

インフラ・運用技術スタック

技術 バージョン 用途
Cloudflare Pages Latest フロントエンドホスティング
Cloudflare CDN/DNS Latest CDN・DNS
Fly.io Latest Vendure コンテナホスティング
Upstash Latest Redis マネージドサービス
PostgreSQL 15.x データベース
Redis 7.x キャッシュ・キュー

開発・テスト技術スタック

技術 バージョン 用途
oxlint 1.31.0 コード品質チェック
Prettier 3.0.3 コードフォーマット
Turbo 1.13.4 ビルドシステム
Vitest 3.2.4 ユニットテスト・E2E (Vendure)
Playwright 1.49.0 E2Eテスト (Storefront)
Testing Library 16.3.0 React テストユーティリティ
Storybook 9.1.7 コンポーネント開発環境
GraphQL Codegen 5.0.0 型安全なGraphQLクライアント
MSW 2.4.9 API モック

デプロイメント構成

アプリケーション構成

# Fly.io アプリケーション構成
ritsubi-vendure:
  - Primary Region: nrt (Tokyo)
  - Instance Count: 2 (HA構成)
  - Resource: 2x shared-cpu-1x (1GB RAM)

ritsubi-worker:
  - Primary Region: nrt (Tokyo)
  - Instance Count: 1
  - Resource: 1x shared-cpu-1x (1GB RAM)

ネットワーク設計

内部通信(IPv6 Private Network)

Vendure API → PostgreSQL: 内部プライベート接続
Vendure API → Upstash Redis: 内部プライベート接続
Worker → Redis/PostgreSQL: 内部プライベート接続

外部通信(Public Internet)

Cloudflare Pages Edge → Vendure GraphQL: HTTPS (Port 443)
外部API → Vendure: HTTPS (Port 443, Admin GUI用)
Webhook → Vendure: HTTPS (Port 443, 決済通知用)

セキュリティ設計

ネットワークセキュリティ

  • プライベートネットワーク: Fly.io IPv6 プライベートネットワーク使用
  • 外部アクセス制限: Admin GUI のみ特定IPからアクセス許可
  • HTTPS強制: すべての外部通信でTLS 1.3使用
  • CORS設定: Next.js Storefront のみからのAPI アクセス許可

アプリケーションセキュリティ

// Vendure セキュリティ設定例
export const securityConfig = {
  auth: {
    sessionDuration: '7d',
    sessionCacheStrategy: new RedisSessionCacheStrategy({
      redisOptions: {
        host: process.env.UPSTASH_REDIS_URL,
        password: process.env.UPSTASH_REDIS_PASSWORD,
        tls: { rejectUnauthorized: false },
      },
    }),
  },
  cors: {
    origin: [
      'https://ritsubi-storefront.pages.dev',
      'https://order.ritsubi.co.jp',
    ],
    credentials: true,
  },
  adminApiPath: 'admin-api',
  shopApiPath: 'shop-api',
};

データベース設計

PostgreSQL 構成(Fly Postgres)

# Fly Postgres 設定
Database: ritsubi-vendure-db
Instance: shared-cpu-1x (1GB RAM, 10GB Storage)
Region: nrt (Tokyo)
Backup: 自動日次バックアップ (7日間保持)
High Availability: マスター/スタンバイ構成

接続管理

// Vendure データベース接続設定
export const dbConfig = {
  type: 'postgres',
  host: process.env.DATABASE_HOST,
  port: 5432,
  username: process.env.DATABASE_USER,
  password: process.env.DATABASE_PASSWORD,
  database: process.env.DATABASE_NAME,
  ssl: { rejectUnauthorized: false },
  synchronize: false, // 本番環境では false
  migrationsRun: true,
  logging: ['error', 'warn'],
  poolSize: 10,
  connectionTimeoutMillis: 5000,
  idleTimeoutMillis: 10000,
};

Redis 構成(Upstash)

# Upstash Redis 設定
Plan: 固定料金プラン (3GB Max Data Size)
Region: Tokyo (Fly.io 内部配置)
Eviction Policy: noeviction (BullMQ対応)
Max Connections: 100
TLS: 有効

用途別設定

// Redis 用途別接続設定
export const redisConfig = {
  // セッションキャッシュ用
  session: {
    host: process.env.UPSTASH_REDIS_HOST,
    port: 6379,
    password: process.env.UPSTASH_REDIS_PASSWORD,
    tls: { rejectUnauthorized: false },
    keyPrefix: 'session:',
    ttl: 7 * 24 * 60 * 60, // 7日間
  },

  // BullMQ ジョブキュー用
  queue: {
    host: process.env.UPSTASH_REDIS_HOST,
    port: 6379,
    password: process.env.UPSTASH_REDIS_PASSWORD,
    tls: { rejectUnauthorized: false },
    maxRetriesPerRequest: null, // BullMQ必須設定
    keyPrefix: 'bull:',
    lazyConnect: true,
  },

  // 一般キャッシュ用
  cache: {
    host: process.env.UPSTASH_REDIS_HOST,
    port: 6379,
    password: process.env.UPSTASH_REDIS_PASSWORD,
    tls: { rejectUnauthorized: false },
    keyPrefix: 'cache:',
    ttl: 60 * 60, // 1時間
  },
};

スケーリング戦略

水平スケーリング

Auto Scaling 設定

# fly.toml - Auto scaling設定
[http_service]
  internal_port = 3000
  force_https = true
  auto_stop_machines = true
  auto_start_machines = true
  min_machines_running = 1
  processes = ["app"]

[[http_service.concurrency]]
  type = "connections"
  hard_limit = 1000
  soft_limit = 800

[metrics]
  port = 9091
  path = "/metrics"

インスタンス拡張方針

# トラフィック増加時の拡張
# CPU使用率 > 70% で自動スケールアップ
# 接続数 > 800 で新インスタンス起動

# 負荷レベル別インスタンス数
Low Traffic (通常時):    2 instances
Medium Traffic (繁忙期): 4 instances
High Traffic (キャンペーン): 6 instances

垂直スケーリング

リソース拡張パス

# スケールアップパス
Tier 1 (開始): shared-cpu-1x (1GB RAM)
Tier 2 (成長): performance-1x (2GB RAM)
Tier 3 (拡大): performance-2x (4GB RAM)
Tier 4 (企業): performance-4x (8GB RAM)

パフォーマンス最適化

Next.js 最適化

// next.config.js - 最適化設定
const nextConfig = {
  experimental: {
    serverComponentsExternalPackages: ['@vendure/core'],
  },
  images: {
    domains: ['ritsubi-assets.fly.dev'],
    formats: ['image/webp', 'image/avif'],
  },
  compress: true,
  poweredByHeader: false,
  reactStrictMode: true,
  swcMinify: true,

  // ISR設定
  generateBuildId: () => process.env.BUILD_ID || 'development',

  // Cloudflare CDN設定
  assetPrefix: process.env.CDN_URL || '',

  // 本番最適化
  productionBrowserSourceMaps: false,
  optimizeFonts: true,

  // Bundle分析
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.resolve.fallback = {
        ...config.resolve.fallback,
        fs: false,
        net: false,
        tls: false,
      };
    }
    return config;
  },
};

Vendure 最適化

// Vendure パフォーマンス設定
export const vendureConfig: VendureConfig = {
  // データベース最適化
  dbConnectionOptions: {
    type: 'postgres',
    poolSize: 10,
    cache: {
      type: 'redis',
      options: redisConfig.cache,
    },
  },

  // GraphQL 最適化
  apiOptions: {
    shopApiPlayground: false, // 本番では無効
    adminApiPlayground: false,
    introspection: false,
    cors: securityConfig.cors,
  },

  // ジョブキュー最適化
  jobQueueOptions: {
    jobQueueStrategy: new BullMQJobQueueStrategy({
      connection: redisConfig.queue,
    }),
  },

  // セッション最適化
  authOptions: {
    sessionCacheStrategy: new RedisSessionCacheStrategy({
      redisOptions: redisConfig.session,
    }),
  },

  // アセット最適化
  assetOptions: {
    assetStorageStrategy: new CloudflareR2AssetStorageStrategy({
      bucket: process.env.R2_BUCKET_NAME,
      region: 'auto',
      credentials: {
        accessKeyId: process.env.R2_ACCESS_KEY_ID,
        secretAccessKey: process.env.R2_SECRET_ACCESS_KEY,
      },
    }),
  },
};

スケジューラ設定(DefaultSchedulerPlugin)

  • apps/vendure-server/src/vendure-config.tsDefaultSchedulerPlugin を有効化済み。
  • 開発環境では manualTriggerCheckInterval: '5s'、本番系は '10s' を指定し、手動トリガー監視の反応速度を調整。
  • 既定で runTasksInWorkerOnlytrue のため、スケジュールタスクはワーカープロセス側で処理される想定。
  • 新規タスクは同ファイル内の schedulerOptions.tasks に追記し、想定SLAに合わせて timeout 等のオプションを設定する。
  • マルチインスタンス運用時でも単一実行を保証するため、BullMQ 導入済みの場合も当プラグインを併用する。

災害復旧・可用性

バックアップ戦略

Database Backup:
  - 自動日次バックアップ(Fly Postgres標準)
  - Point-in-time recovery(PITR)対応
  - Cross-region backup(将来的に大阪リージョン)

Redis Backup:
  - Upstash 自動バックアップ(24時間ごと)
  - データ永続化(AOF + RDB)

Application Backup:
  - Git リポジトリ(GitHub)
  - Docker イメージ(Fly Registry)
  - 設定ファイル(環境変数はSecrets管理)

障害対応

graph TD
    A[障害検知] --> B{障害レベル判定}
    B -->|Level 1| C[自動復旧]
    B -->|Level 2| D[手動介入]
    B -->|Level 3| E[緊急対応]

    C --> F[ヘルスチェック]
    D --> G[ログ調査]
    E --> H[バックアップから復旧]

    F --> I[正常化確認]
    G --> J[原因特定]
    H --> K[サービス復旧]

    I --> L[監視強化]
    J --> M[修正デプロイ]
    K --> N[事後検証]

RTO/RPO 目標

Recovery Time Objective (RTO):
  - Level 1 障害: 5分以内
  - Level 2 障害: 30分以内
  - Level 3 障害: 2時間以内

Recovery Point Objective (RPO):
  - データベース: 1時間以内
  - Redis キャッシュ: 即座に再構築可能
  - ファイルアセット: 24時間以内(Cloudflare R2)

運用考慮事項

デプロイメント戦略

Deployment Strategy: Blue-Green Deployment
- 新バージョンを並行環境にデプロイ
- ヘルスチェック通過後にトラフィック切り替え
- 問題発生時は即座にロールバック

Release Schedule:
- メジャーリリース: 月1回(計画停止あり)
- マイナーリリース: 週1回(無停止デプロイ)
- ホットフィックス: 随時(緊急対応)

監視・アラート

Key Metrics:
  - Response Time: < 200ms (P95)
  - Error Rate: < 0.1%
  - Availability: > 99.5%
  - Database Connections: < 80%
  - Redis Memory Usage: < 70%

Alert Thresholds:
  - Critical: サービス停止、データ損失リスク
  - Warning: パフォーマンス劣化、リソース逼迫
  - Info: 通常の運用イベント

メンテナンス

Scheduled Maintenance:
  - Database Maintenance: 月1回(日曜深夜)
  - Security Updates: 月2回
  - Performance Tuning: 四半期ごと

Maintenance Window:
  - 時間: 日曜 2:00-4:00 JST
  - 通知: 1週間前にユーザーへ告知
  - ロールバック: 30分以内で実行可能

文書バージョン: 1.0 作成日: 2025年9月17日 次回レビュー: 2025年12月17日(サービス開始3ヶ月後)