# API設計書

## 概要

本ドキュメントは、Liam HQアプリケーションのAPI設計書です。本アプリケーションはNext.js 15のApp Routerを使用しており、APIはRoute HandlersとServer Actionsの2種類で構成されています。

## 共通仕様

### ベースURL

```
/api
```

### 認証方式

Supabase Authによるセッション認証を使用。

- **主要認証方法**: GitHub OAuth、メール/パスワード認証
- **セッション管理**: Supabaseクライアントによるサーバーサイドセッション検証
- **トークン管理**: GitHub OAuth トークンはHttpOnly Cookieに暗号化して保存

### 共通ヘッダー

| ヘッダー名 | 必須 | 説明 |
| --- | --- | --- |
| Content-Type | - | application/json（リクエストボディがある場合） |
| Accept | - | application/json または text/event-stream |
| Cookie | - | Supabase認証セッション |

### 共通エラーレスポンス

| ステータスコード | 説明 |
| --- | --- |
| 400 | Bad Request - リクエストパラメータ不正 |
| 401 | Unauthorized - 認証エラー |
| 404 | Not Found - リソース未検出 |
| 500 | Internal Server Error - サーバーエラー |

## API一覧

### Route Handlers (REST API)

| カテゴリ | エンドポイント | メソッド | 説明 |
| --- | --- | --- | --- |
| Chat | /api/chat/stream | POST | AIチャットストリーム |
| Chat | /api/chat/replay | POST | チャットリプレイストリーム |
| Projects | /api/projects | GET | プロジェクト一覧取得 |
| Projects | /api/projects/[projectId] | GET | プロジェクト詳細取得 |
| Projects | /api/projects/search | GET | プロジェクト検索 |
| Auth | /api/logout | POST | ログアウト |
| GitHub | /api/github/token/refresh | POST | GitHubトークンリフレッシュ |
| Auth Callback | /auth/callback/[provider] | GET | OAuth認証コールバック |
| Auth Confirm | /confirm | GET | メールOTP確認 |
| Docs Search | /docs/api/search | GET | ドキュメント検索（docsサイト） |

### Server Actions

| カテゴリ | アクション名 | 説明 |
| --- | --- | --- |
| Session | createGitHubSession | GitHubリポジトリからセッション作成 |
| Session | createUrlSession | URLからセッション作成 |
| Session | createPasteSession | ペーストからセッション作成 |
| Session | createScratchSession | スクラッチからセッション作成 |
| Session | createUploadSession | ファイルアップロードからセッション作成 |
| Session | getBranches | リポジトリのブランチ一覧取得 |
| Session | getSchemaFilePath | スキーマファイルパス取得 |
| Project | addProject | プロジェクト作成 |
| Project | getRepositories | GitHubリポジトリ一覧取得 |
| Project | saveSchemaFilePath | スキーマファイルパス保存 |
| Organization | createOrganization | 組織作成 |
| Organization | updateOrganizationName | 組織名更新 |
| Organization | deleteOrganization | 組織削除 |
| Organization Member | inviteMember | メンバー招待 |
| Organization Member | acceptInvitation | 招待承諾 |
| Organization Member | removeMember | メンバー削除 |
| Organization Member | removeInvitation | 招待削除 |
| Public Share | checkPublicShareStatus | 公開共有状態確認 |
| Public Share | enablePublicShare | 公開共有有効化 |
| Public Share | disablePublicShare | 公開共有無効化 |
| Auth | loginByEmail | メールログイン |
| Auth | loginByGithub | GitHubログイン |

## 各APIエンドポイント定義

### Chat

#### 1. AIチャットストリーム

AIエージェントとのチャット会話をServer-Sent Events (SSE)でストリーミングします。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| エンドポイント | `POST /api/chat/stream` |
| 認証 | 必要 |
| タイムアウト | 700秒 |
| Max Duration | 300秒 |

**リクエストボディ**

```json
{
  "userInput": "テーブルを追加してください",
  "designSessionId": "550e8400-e29b-41d4-a716-446655440000"
}
```

| フィールド名 | 型 | 必須 | バリデーション | 説明 |
| --- | --- | --- | --- | --- |
| userInput | string | ○ | minLength: 1 | ユーザーの入力メッセージ |
| designSessionId | string | ○ | UUID形式 | デザインセッションID |

**レスポンス（成功時）**

ステータスコード: `200 OK`

Content-Type: `text/event-stream`

```
event: message
data: {"type": "text", "content": "..."}

event: end
data: null
```

**レスポンス（エラー時）**

ステータスコード: `400 Bad Request`

```json
{
  "error": "Validation error: Message is required"
}
```

ステータスコード: `401 Unauthorized`

```json
{
  "error": "Authentication required"
}
```

ステータスコード: `404 Not Found`

```json
{
  "error": "Design Session not found"
}
```

---

#### 2. チャットリプレイストリーム

既存のチャット履歴をリプレイしてストリーミングします。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| エンドポイント | `POST /api/chat/replay` |
| 認証 | 必要 |
| タイムアウト | 700秒 |
| Max Duration | 300秒 |

**リクエストボディ**

```json
{
  "designSessionId": "550e8400-e29b-41d4-a716-446655440000"
}
```

| フィールド名 | 型 | 必須 | バリデーション | 説明 |
| --- | --- | --- | --- | --- |
| designSessionId | string | ○ | UUID形式 | デザインセッションID |

**レスポンス（成功時）**

ステータスコード: `200 OK`

Content-Type: `text/event-stream`

```
event: message
data: {"type": "text", "content": "..."}

event: end
data: null
```

**レスポンス（エラー時）**

ステータスコード: `400 Bad Request`

```json
{
  "error": "Validation error: Invalid design session ID"
}
```

ステータスコード: `401 Unauthorized`

```json
{
  "error": "Authentication required"
}
```

ステータスコード: `404 Not Found`

```json
{
  "error": "Building schema not found for design session"
}
```

---

### Projects

#### 3. プロジェクト一覧取得

全プロジェクトの一覧を取得します。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| エンドポイント | `GET /api/projects` |
| 認証 | 不要（現在モック実装） |
| 権限 | - |

**レスポンス（成功時）**

ステータスコード: `200 OK`

```json
[
  {
    "id": "00000000-0000-0000-0000-000000000001",
    "name": "Liam HQ",
    "created_at": "2024-01-01T00:00:00.000Z",
    "updated_at": "2024-01-01T00:00:00.000Z",
    "organization_id": "00000000-0000-0000-0000-100000000001"
  }
]
```

**レスポンス（エラー時）**

ステータスコード: `500 Internal Server Error`

```json
{
  "error": "Failed to fetch projects"
}
```

---

#### 4. プロジェクト詳細取得

指定されたプロジェクトの詳細を取得します。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| エンドポイント | `GET /api/projects/[projectId]` |
| 認証 | 不要（現在モック実装） |
| 権限 | - |

**パスパラメータ**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| projectId | string | ○ | プロジェクトID |

**レスポンス（成功時）**

ステータスコード: `200 OK`

```json
{
  "id": "00000000-0000-0000-0000-000000000001",
  "name": "Liam HQ",
  "created_at": "2024-01-01T00:00:00.000Z",
  "updated_at": "2024-01-01T00:00:00.000Z",
  "organization_id": "00000000-0000-0000-0000-100000000001"
}
```

**レスポンス（エラー時）**

ステータスコード: `500 Internal Server Error`

```json
{
  "error": "Failed to fetch projects"
}
```

---

#### 5. プロジェクト検索

プロジェクトを検索します。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| エンドポイント | `GET /api/projects/search` |
| 認証 | 必要（暗黙的） |
| 権限 | - |

**クエリパラメータ**

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
| --- | --- | --- | --- | --- |
| query | string | - | "" | 検索文字列（プロジェクト名の部分一致） |
| organizationId | string | - | - | 組織IDでフィルタリング |

**レスポンス（成功時）**

ステータスコード: `200 OK`

```json
[
  {
    "id": "00000000-0000-0000-0000-000000000001",
    "name": "Liam HQ",
    "created_at": "2024-01-01T00:00:00.000Z",
    "updated_at": "2024-01-01T00:00:00.000Z",
    "organization_id": "00000000-0000-0000-0000-100000000001"
  }
]
```

**レスポンス（エラー時）**

ステータスコード: `500 Internal Server Error`

```json
{
  "error": "Failed to search projects"
}
```

---

### Auth

#### 6. ログアウト

ユーザーをログアウトさせます。組織ID Cookie、GitHubトークン、Supabaseセッションをクリアします。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| エンドポイント | `POST /api/logout` |
| 認証 | 必要 |
| 権限 | - |

**リクエストボディ**

なし

**レスポンス（成功時）**

ステータスコード: `200 OK`

```json
{
  "ok": true
}
```

**レスポンス（エラー時）**

ステータスコード: `500 Internal Server Error`

```json
{
  "ok": false,
  "error": "logout_failed"
}
```

---

### GitHub

#### 7. GitHubトークンリフレッシュ

GitHubのアクセストークンをリフレッシュします。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| エンドポイント | `POST /api/github/token/refresh` |
| 認証 | Cookieからリフレッシュトークン読み取り |
| 権限 | - |

**リクエストボディ**

なし

**レスポンス（成功時）**

ステータスコード: `200 OK`

```json
{
  "ok": true
}
```

**レスポンス（エラー時）**

ステータスコード: `500 Internal Server Error`

```json
{
  "ok": false,
  "error": "server_misconfigured"
}
```

ステータスコード: `401 Unauthorized`

```json
{
  "ok": false,
  "error": "refresh_failed"
}
```

---

### Auth Callback

#### 8. OAuth認証コールバック

GitHub OAuth認証のコールバック処理を行います。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| エンドポイント | `GET /auth/callback/[provider]` |
| 認証 | 不要（認証プロセスの一部） |
| 権限 | - |

**パスパラメータ**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| provider | string | ○ | 認証プロバイダー（例: github） |

**クエリパラメータ**

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
| --- | --- | --- | --- | --- |
| code | string | ○ | - | 認証コード |
| next | string | - | "/" | 認証後のリダイレクト先 |

**レスポンス（成功時）**

ステータスコード: `302 Found` - 指定されたリダイレクト先へ遷移

**レスポンス（エラー時）**

ステータスコード: `302 Found` - `/error` へリダイレクト

---

#### 9. メールOTP確認

メールOTP認証を確認します。

**基本情報**

| 項目 | 内容 |
| --- | --- |
| エンドポイント | `GET /confirm` |
| 認証 | 不要（認証プロセスの一部） |
| 権限 | - |

**クエリパラメータ**

| パラメータ名 | 型 | 必須 | デフォルト | 説明 |
| --- | --- | --- | --- | --- |
| token_hash | string | ○ | - | トークンハッシュ |
| type | string | ○ | - | OTPタイプ |
| next | string | - | "/" | 確認後のリダイレクト先 |

**レスポンス（成功時）**

ステータスコード: `302 Found` - 指定されたリダイレクト先へ遷移

**レスポンス（エラー時）**

ステータスコード: `302 Found` - `/error` へリダイレクト

---

## Server Actions定義

### Session Actions

#### createGitHubSession

GitHubリポジトリからスキーマを取得してデザインセッションを作成します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| projectId | string | - | プロジェクトID |
| parentDesignSessionId | string | - | 親セッションID |
| gitSha | string | - | Git SHA（コミットハッシュ） |
| initialMessage | string | - | 初期メッセージ |
| isDeepModelingEnabled | boolean | - | Deep Modeling有効化フラグ |

**レスポンス**

```typescript
type CreateSessionState =
  | { success: true; designSessionId: string }
  | { success: false; error: string }
```

---

#### createUrlSession

URLからスキーマを取得してデザインセッションを作成します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| parentDesignSessionId | string | - | 親セッションID |
| initialMessage | string | - | 初期メッセージ |
| isDeepModelingEnabled | boolean | - | Deep Modeling有効化フラグ |
| schemaUrl | string | ○ | スキーマファイルのURL |
| schemaFormat | string | ○ | スキーマフォーマット |

**レスポンス**

```typescript
type CreateSessionState =
  | { success: true; designSessionId: string }
  | { success: false; error: string }
```

---

#### createPasteSession

ペーストされたスキーマ内容からデザインセッションを作成します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| parentDesignSessionId | string | - | 親セッションID |
| initialMessage | string | - | 初期メッセージ |
| isDeepModelingEnabled | boolean | - | Deep Modeling有効化フラグ |
| schemaContent | string | ○ | スキーマ内容 |
| schemaFormat | string | ○ | スキーマフォーマット |

**レスポンス**

```typescript
type CreateSessionState =
  | { success: true; designSessionId: string }
  | { success: false; error: string }
```

---

#### createScratchSession

空のスキーマでデザインセッションを作成します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| parentDesignSessionId | string | - | 親セッションID |
| initialMessage | string | - | 初期メッセージ |
| isDeepModelingEnabled | boolean | - | Deep Modeling有効化フラグ |

**レスポンス**

```typescript
type CreateSessionState =
  | { success: true; designSessionId: string }
  | { success: false; error: string }
```

---

#### createUploadSession

アップロードされたファイルからデザインセッションを作成します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| parentDesignSessionId | string | - | 親セッションID |
| initialMessage | string | - | 初期メッセージ |
| isDeepModelingEnabled | boolean | - | Deep Modeling有効化フラグ |
| schemaFile | File | ○ | スキーマファイル |
| schemaFormat | string | ○ | スキーマフォーマット |

**レスポンス**

```typescript
type CreateSessionState =
  | { success: true; designSessionId: string }
  | { success: false; error: string }
```

---

#### getBranches

プロジェクトに紐づくGitHubリポジトリのブランチ一覧を取得します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| projectId | string | ○ | プロジェクトID |

**レスポンス**

```typescript
type GetBranchesState = {
  branches: GitHubBranch[]
  loading: boolean
  error?: string
}
```

---

#### getSchemaFilePath

プロジェクトのスキーマファイルパスを取得します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| projectId | string | ○ | プロジェクトID |

**レスポンス**

```typescript
type SchemaFilePathState = {
  path: string | null
  error?: string
}
```

---

### Project Actions

#### addProject

新規プロジェクトを作成します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| projectName | string | ○ | プロジェクト名 |
| repositoryName | string | ○ | リポジトリ名 |
| repositoryOwner | string | ○ | リポジトリオーナー |
| installationId | string | ○ | インストールID |
| repositoryIdentifier | string | ○ | リポジトリ識別子 |
| schemaFilePath | string | ○ | スキーマファイルパス |
| schemaFormat | string | ○ | スキーマフォーマット |

**レスポンス**

成功時: プロジェクト詳細ページへリダイレクト

エラー時:
```typescript
{
  success: false
  error: string
}
```

---

#### getRepositories

GitHubインストールに紐づくリポジトリ一覧を取得します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| installationId | string | ○ | インストールID |

**レスポンス**

```typescript
type GetRepositoriesState = {
  repositories: Repository[]
  loading: boolean
  error?: string
}
```

---

#### saveSchemaFilePath

プロジェクトのスキーマファイルパスを保存または更新します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | バリデーション | 説明 |
| --- | --- | --- | --- | --- |
| projectId | string | ○ | - | プロジェクトID |
| path | string | ○ | minLength: 1 | スキーマファイルパス |
| format | string | ○ | schemarb, postgres, prisma, tbls | スキーマフォーマット |

**レスポンス**

```typescript
{
  success: boolean
  error: string | null
  message: string | null
}
```

---

### Organization Actions

#### createOrganization

新規組織を作成します。

**入力**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| name | string | ○ | 組織名 |

**レスポンス**

```typescript
type CreateOrganizationResult =
  | { success: true; organizationId: string }
  | { success: false; error: string }
```

---

#### updateOrganizationName

組織名を更新します。

**入力**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| organizationId | string | ○ | 組織ID |
| name | string | ○ | 新しい組織名 |

**レスポンス**

```typescript
{
  success: boolean
  error?: string
}
```

---

#### deleteOrganization

組織を削除します。

**入力**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| organizationId | string | ○ | 組織ID |

**レスポンス**

```typescript
{
  success: boolean
  error?: string
}
```

---

### Organization Member Actions

#### inviteMember

組織にメンバーを招待します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | バリデーション | 説明 |
| --- | --- | --- | --- | --- |
| email | string | ○ | email形式 | 招待先メールアドレス |
| organizationId | string | ○ | - | 組織ID |

**レスポンス**

成功時:
```typescript
{
  success: true
  error: null
  invitation_token: string
}
```

エラー時:
```typescript
{
  success: false
  error: string
}
```

---

#### acceptInvitation

組織への招待を承諾します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| token | string | ○ | 招待トークン |

**レスポンス**

成功時: プロジェクト一覧ページへリダイレクト

エラー時:
```typescript
{
  success: false
  error: string
}
```

---

#### removeMember

組織からメンバーを削除します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| memberId | string | ○ | メンバーID |
| organizationId | string | ○ | 組織ID |

**レスポンス**

```typescript
{
  success: boolean
  error?: string
}
```

---

#### removeInvitation

招待を取り消します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| invitationId | string | ○ | 招待ID |
| organizationId | string | ○ | 組織ID |

**レスポンス**

```typescript
{
  success: boolean
  error?: string
}
```

---

### Public Share Actions

#### checkPublicShareStatus

デザインセッションの公開共有状態を確認します。

**入力**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| designSessionId | string | ○ | デザインセッションID |

**レスポンス**

```typescript
{
  isPublic: boolean
}
```

---

#### enablePublicShare

デザインセッションの公開共有を有効化します。

**入力**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| designSessionId | string | ○ | デザインセッションID |

**レスポンス**

```typescript
{
  success: boolean
  error?: string
  isPublic?: boolean
}
```

---

#### disablePublicShare

デザインセッションの公開共有を無効化します。

**入力**

| パラメータ名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| designSessionId | string | ○ | デザインセッションID |

**レスポンス**

```typescript
{
  success: boolean
  error?: string
  isPublic?: boolean
}
```

---

### Auth Actions

#### loginByEmail

メールアドレスとパスワードでログインします。

**入力（FormData）**

| フィールド名 | 型 | 必須 | バリデーション | 説明 |
| --- | --- | --- | --- | --- |
| email | string | ○ | email形式 | メールアドレス |
| password | string | ○ | - | パスワード |
| returnTo | string | - | - | ログイン後のリダイレクト先 |

**レスポンス**

成功時: 指定されたリダイレクト先または `/design_sessions/new` へリダイレクト

エラー時: `/error` へリダイレクト

---

#### loginByGithub

GitHub OAuthでログインを開始します。

**入力（FormData）**

| フィールド名 | 型 | 必須 | 説明 |
| --- | --- | --- | --- |
| returnTo | string | - | ログイン後のリダイレクト先 |

**レスポンス**

GitHubのOAuth認証ページへリダイレクト

---

## 備考

### スキーマフォーマット

本アプリケーションでサポートされるスキーマフォーマット:

- `schemarb` - Ruby on Rails schema.rb
- `postgres` - PostgreSQL DDL
- `prisma` - Prisma Schema
- `tbls` - tbls JSON形式

### SSEイベント

チャットストリームAPI (`/api/chat/stream`, `/api/chat/replay`) で使用されるSSEイベント:

| イベント名 | 説明 |
| --- | --- |
| message | メッセージデータ |
| error | エラー発生 |
| end | ストリーム終了 |

### 環境変数

APIが依存する主要な環境変数:

| 変数名 | 説明 |
| --- | --- |
| GITHUB_CLIENT_ID | GitHub OAuthクライアントID |
| GITHUB_CLIENT_SECRET | GitHub OAuthクライアントシークレット |
| SITE_URL | サイトURL（本番環境） |
| VERCEL_BRANCH_URL | Vercelプレビュー環境URL |
