# アーキテクチャ設計書

## 概要

本ドキュメントは、Medusaオープンソースコマースプラットフォームのアーキテクチャ設計を記述する。MedusaはTypeScriptで実装されたモノレポ構造を持つモジュラーコマースプラットフォームであり、30以上のコマースモジュールを提供する。

## システム全体構成

### アーキテクチャ概要図

詳細なアーキテクチャ構成図は [アーキテクチャ構成図.md](./アーキテクチャ構成図.md) を参照。

### システム境界と外部連携

| 外部システム | 連携方式 | 用途 |
| --- | --- | --- |
| PostgreSQL | TCP/IP (pg ドライバー) | プライマリデータストア、全モジュールのデータ永続化 |
| Redis | TCP/IP (ioredis) | イベントバス（BullMQ）、キャッシュ、ロッキング、ワークフローエンジン |
| Amazon S3 | HTTPS (AWS SDK) | ファイルストレージ（プロダクト画像等） |
| Stripe | HTTPS (REST API) | 決済処理プロバイダー |
| SendGrid | HTTPS (REST API) | メール通知プロバイダー |
| PostHog | HTTPS (REST API) | アナリティクスプロバイダー |
| OAuth プロバイダー（Google, GitHub） | HTTPS (OAuth 2.0) | 認証プロバイダー |
| 外部ストアフロントアプリケーション | HTTPS (REST API) | Store API経由での顧客向け機能アクセス |
| 管理アプリケーション | HTTPS (REST API) | Admin API経由での管理機能アクセス |

## レイヤー構成

### アーキテクチャスタイル

**モジュラーモノリス + ワークフローオーケストレーション**

Medusaは以下のアーキテクチャパターンを採用している：

1. **モジュラーモノリス**: 独立した30以上のコマースモジュールがデプロイ単位として統合されつつ、論理的に分離されている
2. **サービスレイヤーパターン**: 各モジュールはサービス層を通じてビジネスロジックを公開
3. **ワークフローオーケストレーション**: 複数モジュールにまたがる操作はWorkflows SDKによる明示的なオーケストレーションで実現
4. **依存性注入（DI）**: Awilixコンテナによる依存性管理
5. **イベント駆動**: モジュール間の疎結合通信はイベントバス（ローカル/Redis）を通じて実現

### レイヤー定義

| レイヤー | 責務 | 主なコンポーネント |
| --- | --- | --- |
| Presentation (HTTP) | リクエストルーティング、認証、バリデーション、レスポンス整形 | `packages/core/framework/src/http/` - ApiLoader, Router, Middlewares |
| Application (Workflows) | ユースケース実行、トランザクション境界、補償処理 | `packages/core/core-flows/` - createWorkflow, createStep |
| Domain (Modules) | ビジネスロジック、ドメインモデル、モジュールサービス | `packages/modules/*/src/services/` - MedusaService拡張クラス |
| Infrastructure | データアクセス、外部サービス連携、イベント発行 | `packages/modules/*/src/repositories/`, Event Bus, Providers |

### レイヤー間の依存関係ルール

```
Presentation → Application → Domain → Infrastructure
     ↓              ↓           ↓
   HTTP層      Workflows      Modules
```

**依存の方向性**:
- 上位レイヤーは下位レイヤーに依存可能
- 下位レイヤーは上位レイヤーを知らない
- Domainレイヤー（Modules）は他のModulesを直接参照しない（Link Modulesを通じて関連付け）

**許可される参照**:
- API Routes → Workflows → Module Services
- Workflows → 複数の Module Services
- Module Services → Repositories, Providers

**禁止される参照**:
- Module A → Module B（直接参照、Link経由のみ許可）
- Repositories → Services
- Providers → Module Services

## モジュール構成

### ドメイン分割

| ドメイン | 責務 | 関連モジュール |
| --- | --- | --- |
| Product | 商品カタログ管理 | product, inventory, stock-location, pricing |
| Order | 注文処理、フルフィルメント | order, fulfillment, cart |
| Customer | 顧客管理、顧客グループ | customer, auth, user |
| Payment | 決済処理 | payment, promotion |
| Region & Tax | 地域・税金管理 | region, tax, currency |
| Notification | 通知管理 | notification |
| Platform | プラットフォーム基盤 | api-key, rbac, settings, translation |

### パッケージ構造

```
packages/
├── medusa/                    # メインパッケージ（APIルート、コマンド）
│   └── src/
│       ├── api/               # HTTPエンドポイント（admin/, store/, auth/）
│       ├── commands/          # CLIコマンド
│       ├── subscribers/       # イベントサブスクライバー
│       └── modules/           # モジュールエントリポイント
├── core/                      # コアフレームワーク
│   ├── framework/             # ランタイム基盤（HTTP, DI, 設定）
│   ├── types/                 # TypeScript型定義
│   ├── utils/                 # 共有ユーティリティ
│   ├── workflows-sdk/         # ワークフロー構築SDK
│   ├── core-flows/            # 事前定義ワークフロー
│   ├── modules-sdk/           # モジュール開発SDK
│   ├── orchestration/         # ワークフローオーケストレーション
│   └── js-sdk/                # フロントエンドSDK
├── modules/                   # コマースモジュール
│   ├── product/               # 商品モジュール
│   ├── order/                 # 注文モジュール
│   ├── cart/                  # カートモジュール
│   ├── customer/              # 顧客モジュール
│   ├── payment/               # 決済モジュール
│   ├── fulfillment/           # フルフィルメントモジュール
│   ├── promotion/             # プロモーションモジュール
│   ├── pricing/               # 価格設定モジュール
│   ├── inventory/             # 在庫モジュール
│   ├── auth/                  # 認証モジュール
│   ├── notification/          # 通知モジュール
│   ├── link-modules/          # モジュール間リンク
│   ├── event-bus-local/       # ローカルイベントバス
│   ├── event-bus-redis/       # Redisイベントバス
│   ├── cache-inmemory/        # インメモリキャッシュ
│   ├── cache-redis/           # Redisキャッシュ
│   ├── workflow-engine-inmemory/  # インメモリワークフローエンジン
│   ├── workflow-engine-redis/     # Redisワークフローエンジン
│   └── providers/             # 外部サービスプロバイダー
│       ├── auth-emailpass/
│       ├── auth-google/
│       ├── auth-github/
│       ├── payment-stripe/
│       ├── notification-sendgrid/
│       ├── file-local/
│       └── file-s3/
├── admin/                     # 管理ダッシュボード
│   ├── dashboard/             # React管理UI
│   ├── admin-vite-plugin/     # Viteプラグイン
│   └── admin-sdk/             # 管理SDK
└── cli/                       # CLIツール
    ├── medusa-cli/            # メインCLI
    └── create-medusa-app/     # プロジェクト初期化CLI
```

### モジュール内部構造（例: order モジュール）

```
packages/modules/order/src/
├── index.ts                   # モジュールエントリポイント
├── joiner-config.ts           # モジュール間リンク設定
├── models/                    # MikroORMエンティティモデル
│   ├── order.ts
│   ├── order-item.ts
│   └── ...
├── services/                  # サービス層
│   ├── order-module-service.ts    # メインモジュールサービス
│   └── order-service.ts           # 内部サービス
├── repositories/              # データアクセス層
├── migrations/                # データベースマイグレーション
├── types/                     # 型定義
└── utils/                     # モジュール固有ユーティリティ
```

### コンポーネント依存関係

**サービス依存パターン**:
- Module Service → Repository（データアクセス）
- Module Service → Event Emitter（イベント発行）
- Module Service → Logger（ロギング）

**ワークフロー依存パターン**:
- Workflow → 複数のModule Services（依存性注入経由）
- Step → 単一のModule Service操作
- Compensation → 補償用Step

## ミドルウェア構成

### データベース

| 種類 | ミドルウェア | バージョン | 用途 |
| --- | --- | --- | --- |
| RDB | PostgreSQL | 最新安定版 | 全モジュールのプライマリデータストア（MikroORM経由） |

### キャッシュ

| ミドルウェア | バージョン | 用途 | TTL |
| --- | --- | --- | --- |
| インメモリ（デフォルト） | - | 開発環境向けキャッシュ | 設定可能 |
| Redis | 最新安定版 | 本番環境向け分散キャッシュ | 設定可能 |

### メッセージキュー

| ミドルウェア | バージョン | 用途 |
| --- | --- | --- |
| ローカルイベントバス（デフォルト） | - | 開発環境向け同期イベント処理 |
| Redis + BullMQ | BullMQ 5.13.0, ioredis 5.4.1 | 本番環境向け非同期イベント処理、ジョブキュー |

### ワークフローエンジン

| ミドルウェア | バージョン | 用途 |
| --- | --- | --- |
| インメモリ（デフォルト） | - | 開発環境向けワークフロー実行 |
| Redis | ioredis 5.4.1 | 本番環境向け分散ワークフロー実行、状態永続化 |

### その他ミドルウェア

| ミドルウェア | バージョン | 用途 |
| --- | --- | --- |
| Express | 4.21.0 | HTTPサーバーフレームワーク |
| MikroORM | 最新（framework依存） | ORMフレームワーク、データベースマイグレーション |
| Awilix | 8.0.1 | 依存性注入コンテナ |
| jsonwebtoken | 9.0.2 | JWT認証トークン処理 |
| Zod | 3.25.76 | スキーマバリデーション |

## データフロー

### リクエスト処理の流れ

同期APIリクエスト（例: 注文一覧取得）：

1. **HTTPリクエスト受信**: Express サーバーがリクエストを受け取る
2. **ミドルウェアチェーン**:
   - CORS処理
   - Body Parser
   - 認証ミドルウェア（Session/Bearer/API Key）
   - コンテキスト設定
3. **ルートハンドラ実行**:
   - `req.scope` からサービス解決
   - ワークフロー実行
4. **ワークフロー実行**:
   - `createWorkflow` で定義されたステップを順次実行
   - 各ステップがModule Serviceを呼び出し
5. **レスポンス返却**: 結果をJSON形式で返却

```typescript
// APIルート例
export const GET = async (
  req: AuthenticatedMedusaRequest,
  res: MedusaResponse
) => {
  const workflow = getOrdersListWorkflow(req.scope)
  const { result } = await workflow.run({
    input: { fields: req.queryConfig.fields, variables }
  })
  res.json({ orders: result.rows })
}
```

### 非同期処理の流れ

イベント駆動の非同期処理（例: 注文作成後の通知）：

1. **イベント発行**: Module ServiceがEmitEventsデコレータ経由でイベント発行
2. **イベントバス処理**:
   - ローカル: 同期的にサブスクライバーを呼び出し
   - Redis: BullMQキューにジョブ追加
3. **サブスクライバー実行**: 登録されたサブスクライバーがイベントを処理
4. **後続処理**: 通知送信、在庫更新等の処理を実行

```typescript
// イベント発行例（デコレータ使用）
@InjectManager()
@EmitEvents()
async createOrders(data, @MedusaContext() context = {}) {
  // 処理完了後、自動的にイベントが発行される
}
```

### データ永続化の流れ

1. **サービス呼び出し**: Module ServiceのCRUDメソッドが呼び出される
2. **トランザクション開始**: `@InjectTransactionManager`デコレータでトランザクション管理
3. **MikroORM操作**: エンティティの作成/更新/削除
4. **コミット/ロールバック**: 成功時にコミット、エラー時に自動ロールバック
5. **イベント発行**: `@EmitEvents`で変更イベントを発行

## 横断的関心事

### 認証・認可

| 方式 | 実装箇所 | 対象 |
| --- | --- | --- |
| Session認証 | `packages/core/framework/src/http/middlewares/authenticate-middleware.ts` | Admin/Store API |
| Bearer JWT認証 | 同上 | Admin/Store API |
| API Key認証 | 同上 | Admin API（シークレットキー） |
| Publishable API Key | `ensure-publishable-api-key.ts` | Store API |
| RBAC（権限管理） | `packages/modules/rbac/` | Admin API操作権限 |

**認証フロー**:
```typescript
authenticate(
  actorType: string | string[],  // "user" | "customer"
  authType: AuthType | AuthType[], // "session" | "bearer" | "api-key"
  options: { allowUnauthenticated?: boolean }
)
```

### ロギング・監査

| 種類 | 実装方式 | 保存先 |
| --- | --- | --- |
| アプリケーションログ | ContainerRegistrationKeys.LOGGER（Winston互換） | 標準出力/設定可能 |
| エラーログ | Error Handlerミドルウェア | 標準出力/設定可能 |
| リクエストログ | Morgan ミドルウェア | 標準出力 |

### エラーハンドリング

| エラー種別 | ハンドリング方式 | HTTPステータス |
| --- | --- | --- |
| NOT_FOUND | MedusaError | 404 |
| INVALID_DATA | MedusaError | 400 |
| NOT_ALLOWED | MedusaError | 400 |
| UNAUTHORIZED | MedusaError | 401 |
| FORBIDDEN | MedusaError | 403 |
| CONFLICT | MedusaError | 409 |
| DUPLICATE_ERROR | MedusaError | 422 |
| DB_ERROR | MedusaError | 500 |
| Zod Validation Error | フォーマット後エラー | 400 |
| Unknown Error | 汎用ハンドラ | 500 |

**エラーハンドリング実装**:
```typescript
// サービス層でのエラー発行
throw new MedusaError(
  MedusaError.Types.NOT_FOUND,
  `Order with id: ${id} was not found`
)

// ワークフローでの補償処理
export const deletePromotionsStep = createStep(
  "delete-promotions",
  async (ids, { container }) => {
    await promotionModule.softDeletePromotions(ids)
    return new StepResponse(void 0, ids)
  },
  async (idsToRestore, { container }) => {
    // 補償：削除したものを復元
    await promotionModule.restorePromotions(idsToRestore)
  }
)
```

### トランザクション管理

| 範囲 | 管理方式 | 分離レベル |
| --- | --- | --- |
| Module Service操作 | `@InjectTransactionManager`デコレータ | デフォルト（Read Committed） |
| Workflow Step | 各Stepが独立トランザクション | デフォルト |
| 複数Module操作 | Workflow補償による一貫性保証 | 最終的一貫性 |

**トランザクション管理パターン**:
```typescript
// 公開メソッド: EntityManager注入
@InjectManager()
@EmitEvents()
async deleteOrders(ids, @MedusaContext() context = {}) {
  return await this.deleteOrders_(ids, context)
}

// 内部メソッド: TransactionManager注入
@InjectTransactionManager()
protected async deleteOrders_(ids, @MedusaContext() context = {}) {
  await this.orderService_.softDelete(ids, context)
}
```

## 設計原則・コーディング規約

### 適用している設計原則

| 原則 | 適用箇所 | 実装例 |
| --- | --- | --- |
| 単一責任の原則（SRP） | 各Module | 1モジュール = 1ドメイン境界 |
| 開放閉鎖の原則（OCP） | Providers | プロバイダーインターフェースによる拡張 |
| 依存性逆転の原則（DIP） | サービス層 | インターフェース（IModuleService）への依存 |
| 補償トランザクション | Workflows | createStepの第3引数（補償関数） |
| イベント駆動 | モジュール間通信 | EmitEventsデコレータ、EventBus |
| ソフトデリート | 全エンティティ | softDelete/restore メソッド |

### コーディング規約

**ファイル命名**:
- ファイル名: kebab-case (`order-module-service.ts`)
- クラス名: PascalCase (`OrderModuleService`)
- 関数/変数名: camelCase (`createOrder`)
- 定数: SCREAMING_SNAKE_CASE (`MODULE_NAME`)
- DBフィールド: snake_case (`order_id`)

**TypeScript設定**:
- Target: ES2021
- Module: Node16
- Strict null checks: 有効
- Decorators: 実験的機能有効

**Prettier設定**:
- セミコロン: なし
- クォート: ダブルクォート
- インデント: 2スペース
- トレイリングカンマ: ES5

**APIルート規約**:
- HTTPメソッドを名前付きエクスポート (`export const GET`, `export const POST`)
- リクエスト型: `AuthenticatedMedusaRequest<T>` or `MedusaRequest<T>`
- レスポンス型: `MedusaResponse<T>`
- ワークフロー経由でビジネスロジック実行

**モジュールサービス規約**:
- `MedusaService<T>`を継承
- 公開メソッドに`@InjectManager()`、`@EmitEvents()`
- 内部メソッドに`@InjectTransactionManager()`
- `@MedusaContext()`でコンテキスト注入

**ワークフロー規約**:
- `createWorkflow`でワークフロー定義
- `createStep`でステップ定義（補償関数付き）
- `WorkflowData<T>`で入力型指定
- `WorkflowResponse<T>`で出力型指定

## 備考

### バージョン情報
- Medusa バージョン: 2.13.1
- Node.js: 20以上
- パッケージマネージャ: Yarn 3.2.1

### 開発・本番環境の違い

| 機能 | 開発環境 | 本番環境 |
| --- | --- | --- |
| イベントバス | event-bus-local（同期） | event-bus-redis（非同期） |
| キャッシュ | cache-inmemory | cache-redis |
| ワークフローエンジン | workflow-engine-inmemory | workflow-engine-redis |
| ファイルストレージ | file-local | file-s3 |
| 通知 | notification-local（コンソール出力） | notification-sendgrid |

### 拡張ポイント

1. **カスタムモジュール**: `modules-sdk`を使用して新規モジュール作成
2. **カスタムワークフロー**: `workflows-sdk`を使用してビジネスロジック拡張
3. **カスタムプロバイダー**: 認証/決済/通知等のプロバイダー追加
4. **APIエンドポイント追加**: `packages/medusa/src/api/`に新規ルート追加
5. **Admin UIカスタマイズ**: admin-vite-pluginによる拡張

### 参照ドキュメント
- 公式ドキュメント: https://docs.medusajs.com
- API リファレンス: https://docs.medusajs.com/api
