# 機能設計書 99-使用量制限

## 概要

本ドキュメントは、Giselleプラットフォームにおける使用量制限（Usage Limits）機能について記述する。

### 本機能の処理概要

**業務上の目的・背景**：チームのプランに応じたリソース使用制限を管理し、エージェント実行時間（Agent Time）の上限を設定・監視する。Freeプランには使用制限があり、Proプランは無制限となる。これにより、プラン別のサービス差別化と、システムリソースの適正配分を実現する。

**機能の利用シーン**：
- ワークフロー実行前の使用量チェック
- エージェント実行時間の記録
- 使用量上限到達時の警告表示
- チームの利用状況確認

**主要な処理内容**：
1. チームの使用量制限情報の取得（fetchUsageLimits）
2. プラン別の制限値計算（agentTimeLimit）
3. エージェント実行時間の集計（calculateAgentTimeUsageMs）
4. 使用量チェック（checkUsageLimits）
5. エージェント活動の記録（saveAgentActivity）
6. 制限到達判定（useUsageLimitsReached）
7. 警告UI表示（UsageLimitWarning）

**関連システム・外部連携**：
- データベース（teams, agents, agentActivities, agentTimeRestrictions）
- 言語モデルTier判定（language-model）

**権限による制御**：チーム単位での使用量管理。制限付きチームは制限値0。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 17 | ワークフローエディタ画面 | 主機能 | 使用量制限警告表示 |
| 30 | 利用状況画面 | 主機能 | 利用状況の確認 |

## 機能種別

リソース管理 / 課金制御

## 入力仕様

### 入力パラメータ（使用量取得）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| workspaceId | WorkspaceId | Yes | ワークスペースID | - |

### 入力パラメータ（活動記録）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| agentId | AgentId | Yes | エージェントID | - |
| startedAt | Date | Yes | 開始時刻 | - |
| endedAt | Date | Yes | 終了時刻 | - |
| totalDurationMs | number | Yes | 総実行時間（ミリ秒） | - |

### 入力データソース

- データベース（teams, agents, agentActivities）
- ワークスペース情報

## 出力仕様

### 出力データ（UsageLimits）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| featureTier | Tier | 言語モデルTier（free/pro） |
| resourceLimits.agentTime.limit | number | 制限時間（ミリ秒） |
| resourceLimits.agentTime.used | number | 使用済み時間（ミリ秒） |

### 出力先

- クライアント（React Context経由）
- Generation実行前チェック

## 処理フロー

### 処理シーケンス

```
1. 使用量取得
   └─ workspaceId → チーム情報取得 → プラン判定 → 制限値計算 → 使用量集計 → UsageLimits返却

2. 使用量チェック
   └─ Generation → fetchUsageLimits → Tier確認 → Agent Time確認 → 結果返却

3. 活動記録
   └─ Generation完了 → totalDurationMs計算 → saveAgentActivity → DB記録

4. 請求期間計算
   └─ チーム作成日 → 月次サイクル計算 → 期間内使用量集計
```

### フローチャート

```mermaid
flowchart TD
    A[ワークフロー実行] --> B[fetchUsageLimits]
    B --> C[チーム情報取得]
    C --> D[プラン判定]
    D --> E{プラン種別}
    E -->|Pro| F[制限=無限大]
    E -->|Free| G[制限=30分]
    E -->|Restricted| H[制限=0]

    F --> I[使用量集計]
    G --> I
    H --> I

    I --> J[UsageLimits返却]
    J --> K[checkUsageLimits]
    K --> L{制限超過?}
    L -->|Yes| M[UsageLimitError]
    L -->|No| N[実行続行]

    N --> O[Generation実行]
    O --> P[実行時間計算]
    P --> Q[saveAgentActivity]
    Q --> R[DB記録]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | Freeプラン制限 | 月間30分のAgent Time制限 | Freeプラン |
| BR-002 | Proプラン無制限 | Agent Time制限なし | Proプラン |
| BR-003 | 制限付きチーム | Agent Time使用不可（制限=0） | agentTimeRestrictionsに登録 |
| BR-004 | 請求期間計算 | チーム作成日を基準とした月次サイクル | 常時 |
| BR-005 | Tier判定 | プランに応じた言語モデルTierを返却 | 常時 |

### 計算ロジック

**Agent Time制限値計算**:
```typescript
function agentTimeLimit(team, restricted):
  if (team.id in restricted):
    return 0  // 制限付きチームは使用不可
  if (isProPlan(team)):
    return POSITIVE_INFINITY  // 無制限
  return FREE_LIMIT_MINUTES * 60 * 1000  // 30分をミリ秒に変換
```

**使用量超過判定**:
```typescript
isLimitReached = agentTime.used >= agentTime.limit
```

## データベース操作仕様

### 操作別データベース影響一覧

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 使用量取得 | teams, agents | SELECT | チーム・エージェント情報取得 |
| 使用量集計 | agentActivities, agents | SELECT | 期間内使用量の集計 |
| 制限チーム取得 | agentTimeRestrictions, teams | SELECT | 制限対象チーム一覧取得 |
| 活動記録 | agentActivities | INSERT | エージェント活動の記録 |

### テーブル別操作詳細

#### agentActivities

| 操作 | 項目（カラム名） | 更新値・取得条件 | 備考 |
|-----|-----------------|-----------------|------|
| INSERT | agentDbId, startedAt, endedAt, totalDurationMs | 実行情報 | saveAgentActivity |
| SELECT | SUM(totalDurationMs) | 期間内 + チーム条件 | calculateAgentTimeUsageMs |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| UsageLimitError | 使用量超過 | Agent Time制限超過 | プランアップグレードを案内 |
| TEAM_NOT_FOUND | データ不在 | チームが存在しない | ワークスペース設定確認 |
| AGENT_NOT_FOUND | データ不在 | エージェントが存在しない | エージェント設定確認 |
| ACCESS_DENIED | Tier不足 | 言語モデルTier不足 | プランアップグレードを案内 |

### リトライ仕様

特になし（使用量チェックは即時判定）

## トランザクション仕様

- saveAgentActivityは単一INSERT
- calculateAgentTimeUsageMsは読み取り専用

## パフォーマンス要件

- 使用量取得: 500ms以内
- 使用量チェック: 100ms以内

## セキュリティ考慮事項

- workspaceIdによるチーム分離
- 制限付きチーム機能による不正利用防止

## 備考

- AGENT_TIME_CHARGE_LIMIT_MINUTES.FREE = 30分
- 請求期間はチーム作成日を基準とした月次サイクル
- 制限到達時はUIで警告表示

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: 型定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | usage-limits.ts | `packages/giselle/src/types/usage-limits.ts` | UsageLimits型、コールバック型定義 |

**主要な型定義（usage-limits.ts）**:
1. **4-12行目**: UsageLimits interface - featureTier, resourceLimits.agentTime
2. **14-19行目**: ConsumeAgentTimeCallback - 使用量記録コールバック型
3. **21-23行目**: FetchUsageLimitsFn - 使用量取得関数型

#### Step 2: 定数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | constants.ts | `apps/studio.giselles.ai/services/agents/activities/constants.ts` | プラン別制限値 |

**定数定義（constants.ts）**:
1. **1-4行目**: AGENT_TIME_CHARGE_LIMIT_MINUTES - FREE:30, PRO:60

#### Step 3: 使用量取得ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fetch-usage-limits.ts | `apps/studio.giselles.ai/packages/lib/fetch-usage-limits.ts` | ワークスペースからチーム取得 |
| 3-2 | usage-limits.ts | `apps/studio.giselles.ai/packages/lib/usage-limits.ts` | 使用量制限計算ロジック |

**主要処理フロー（fetch-usage-limits.ts）**:
1. **6-19行目**: workspaceId → teams JOIN agents → チーム情報取得
2. **26行目**: getUsageLimitsForTeam呼び出し

**主要処理フロー（usage-limits.ts）**:
1. **11-28行目**: getUsageLimitsForTeam - Tier取得、使用量計算、制限値計算
2. **30-40行目**: agentTimeLimit - プラン別制限値返却
3. **42-51行目**: fetchAgentTimeRestrictedTeamIds - 制限チーム取得

#### Step 4: 使用量集計を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | agent-time-usage.ts | `apps/studio.giselles.ai/services/agents/activities/agent-time-usage.ts` | 使用量集計ロジック |

**主要処理フロー（agent-time-usage.ts）**:
1. **8-11行目**: calculateAgentTimeUsageMs - 請求期間取得、使用量集計
2. **17-31行目**: getCurrentBillingPeriod - チーム作成日から月次サイクル計算
3. **34-59行目**: agentTimeUsageMs - SUM(totalDurationMs)で集計

#### Step 5: 使用量チェックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | utils.ts | `packages/giselle/src/generations/utils.ts` | checkUsageLimits関数 |

**主要処理フロー（utils.ts）**:
1. **833-877行目**: checkUsageLimits - Tier確認、Agent Time確認
2. **860-866行目**: hasTierAccess判定
3. **868-875行目**: agentTime超過判定

#### Step 6: UI層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | usage-limits.ts | `internal-packages/workflow-designer-ui/src/hooks/usage-limits.ts` | React Hook |
| 6-2 | usage-limit-warning.tsx | `internal-packages/workflow-designer-ui/src/ui/usage-limit-warning.tsx` | 警告UI |

**主要処理フロー（hooks/usage-limits.ts）**:
1. **4-13行目**: useUsageLimitsReached - used >= limit判定

### プログラム呼び出し階層図

```
ワークフロー実行
    │
    ├─ [使用量取得]
    │      │
    │      ├─ fetchUsageLimits(workspaceId)
    │      │      │
    │      │      ├─ db.select().from(teams).innerJoin(agents)
    │      │      │
    │      │      └─ getUsageLimitsForTeam(team)
    │      │             │
    │      │             ├─ getLanguageModelTier(team.plan)
    │      │             │
    │      │             ├─ calculateAgentTimeUsageMs(team.dbId)
    │      │             │      └─ getCurrentBillingPeriod
    │      │             │      └─ agentTimeUsageMs (SUM)
    │      │             │
    │      │             ├─ fetchAgentTimeRestrictedTeamIds()
    │      │             │
    │      │             └─ agentTimeLimit(team, restricted)
    │      │
    │      └─ UsageLimits返却
    │
    ├─ [使用量チェック]
    │      │
    │      └─ checkUsageLimits
    │             ├─ hasTierAccess(languageModel, featureTier)
    │             └─ agentTime.used >= agentTime.limit
    │
    ├─ [Generation実行]
    │
    └─ [活動記録]
           │
           └─ saveAgentActivity(agentId, startedAt, endedAt, totalDurationMs)
                  └─ db.insert(agentActivities)
```

### データフロー図

```
[入力]                          [処理]                           [出力]

workspaceId ────────────────────┐
                                │
                                ├──▶ fetchUsageLimits
                                │         │
                                │         ├──▶ teams JOIN agents
                                │         │
                                │         └──▶ getUsageLimitsForTeam
                                │                    │
team.plan ──────────────────────┤                    ├──▶ featureTier
                                │                    │
team.dbId ──────────────────────┤                    ├──▶ calculateAgentTimeUsageMs
                                │                    │         │
                                │                    │         └──▶ resourceLimits.agentTime.used
                                │                    │
                                │                    └──▶ agentTimeLimit
                                │                              │
                                │                              └──▶ resourceLimits.agentTime.limit
                                │
                                └──▶ UsageLimits
                                           │
                                           ├──▶ checkUsageLimits
                                           │         └──▶ ok / error
                                           │
                                           └──▶ useUsageLimitsReached (UI)
                                                     └──▶ boolean
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| usage-limits.ts | `packages/giselle/src/types/usage-limits.ts` | ソース | 型定義 |
| constants.ts | `apps/studio.giselles.ai/services/agents/activities/constants.ts` | ソース | 制限値定数 |
| fetch-usage-limits.ts | `apps/studio.giselles.ai/packages/lib/fetch-usage-limits.ts` | ソース | 使用量取得エントリーポイント |
| usage-limits.ts | `apps/studio.giselles.ai/packages/lib/usage-limits.ts` | ソース | 使用量計算ロジック |
| agent-time-usage.ts | `apps/studio.giselles.ai/services/agents/activities/agent-time-usage.ts` | ソース | 使用量集計 |
| save-agent-activity.ts | `apps/studio.giselles.ai/services/agents/activities/save-agent-activity.ts` | ソース | 活動記録 |
| utils.ts | `packages/giselle/src/generations/utils.ts` | ソース | checkUsageLimits |
| error.ts | `packages/giselle/src/error.ts` | ソース | UsageLimitError定義 |
| usage-limits.ts | `internal-packages/workflow-designer-ui/src/hooks/usage-limits.ts` | ソース | React Hook |
| usage-limit-warning.tsx | `internal-packages/workflow-designer-ui/src/ui/usage-limit-warning.tsx` | ソース | 警告UI |
