data-modeler
イミュータブルデータモデルに基づくデータモデリング自動化Skill。ブラックボードパターンで段階的にエンティティ抽出からER図生成まで実行します。
When & Why to Use This Skill
This Claude skill is a sophisticated automated data modeling agent designed to transform business use cases into production-ready database architectures. Based on the 'Immutable Data Model' principle and utilizing the 'Blackboard' design pattern, it systematically guides the user through entity extraction, resource/event classification, and relationship analysis. It automates the generation of high-value technical artifacts, including Mermaid ER diagrams, PostgreSQL-compatible DDL scripts, and CQRS-compliant OpenAPI 3.1.0 specifications, ensuring a seamless transition from requirements to system design.
Use Cases
- Automated Schema Generation: Converting raw business requirements or use case descriptions into structured PostgreSQL DDL and ER diagrams.
- Immutable Architecture Design: Implementing modern data modeling standards by clearly separating stateful resources from immutable event logs for better auditability.
- API-First Development: Automatically generating CQRS-compliant OpenAPI specifications that align perfectly with the underlying database schema.
- System Refactoring: Visualizing and validating existing business logic to transition from legacy CRUD models to more robust, event-driven architectures.
- Rapid Prototyping: Reducing the time between initial brainstorming and the creation of a functional database and API contract for new projects.
| name | data-modeler |
|---|---|
| description | イミュータブルデータモデルに基づくデータモデリング自動化Skill。ブラックボードパターンで段階的にエンティティ抽出からER図生成まで実行します。 |
| version | 2.0.0 |
| author | Akira Abe |
Data Modeler Skill
このSkillは、ユースケース記述からRDBMSのテーブル設計を自動生成するエージェントです。 ブラックボードパターンを採用し、Claude自身が段階的にデータモデリングを実行します。
アーキテクチャ概要
ブラックボードパターン
このSkillはブラックボードパターンを採用しています。ブラックボードとは、複数の専門知識(Knowledge Sources)が協調して問題を解決するための共有データ空間です。
┌─────────────────────────────────────────┐
│ Blackboard (共有データ空間) │
│ artifacts/{project_name}/ │
├─────────────────────────────────────────┤
│ ├── state.yaml │ ← フェーズ管理・制御情報
│ ├── entities_raw.json │ ← 抽出された名詞・動詞
│ ├── entities_classified.json │ ← リソース/イベント分類結果
│ ├── model.json │ ← データモデル定義(関連含む)
│ ├── validation_result.json │ ← 検証結果
│ └── er_diagram.mmd │ ← 最終出力(Mermaid ER図)
└─────────────────────────────────────────┘
↑ ↑
│ 読み書き │
│ │
┌──────────┴──────────────┴──────────────┐
│ Claude (Control Component) │
│ 各フェーズを順次実行 │
├────────────────────────────────────────┤
│ Phase 1: エンティティ抽出 │
│ Phase 2: リソース/イベント分類 │
│ Phase 3: 関連分析 │
│ Phase 4: 検証 │
│ Phase 5: ER図生成 │
└────────────────────────────────────────┘
ブラックボードの役割:
- 中間結果の保存: 各フェーズの成果物を保存
- フェーズ間の連携: 前フェーズの出力が次フェーズの入力になる
- 状態管理: 現在のフェーズ、完了済みフェーズを記録
- 検証可能性: 各段階の成果物を後から確認できる
- プロジェクト分離: 複数のモデリングプロジェクトを並行管理可能
プロジェクト名によるディレクトリ分離:
各モデリングプロジェクトは独立したディレクトリで管理されます。
artifacts/
├── invoice-management/ ← 請求書管理システム
│ ├── state.yaml
│ ├── entities_classified.json
│ ├── model.json
│ └── ...
├── inventory-management/ ← 在庫管理システム
│ ├── state.yaml
│ └── ...
└── order-processing/ ← 受注処理システム
└── ...
これにより、異なる業務ドメインのモデリングを同時進行できます。
使用方法
基本的な使い方
# ユースケースからデータモデルを生成
/data-modeler
請求期日が到来した場合、顧客に請求書を送付する。
期日までに入金がない場合には、確認状を送付する。
ファイルからの入力
# タスク記述をファイルから読み込む
cat examples/invoice-management.txt
# その後、/data-modeler を実行してユースケースを入力
実行フロー
全体フロー
1. プロジェクト名の入力 & ブラックボード初期化
↓ (artifacts/{project_name}/ ディレクトリを作成)
2. Phase 0.5: ユースケース詳細化 ★NEW
↓ (usecase_detailed.md をブラックボードに書き込み)
3. Phase 1: エンティティ抽出
↓ (entities_raw.json をブラックボードに書き込み)
4. Phase 2: リソース/イベント分類
↓ (entities_classified.json をブラックボードに書き込み)
5. Phase 2.5: 属性レビュー
↓ (entities_classified.json を更新)
6. Phase 3: 関連分析
↓ (model.json をブラックボードに書き込み)
7. Phase 4: 検証
↓ (validation_result.json をブラックボードに書き込み)
8. Phase 5: ER図生成
↓ (er_diagram.mmd をブラックボードに書き込み)
9. Phase 6: DDL生成
↓ (schema.sql, sample_data.sql, query_examples.sql をブラックボードに書き込み)
10. Phase 7: OpenAPI生成 ★NEW
↓ (openapi.yaml をブラックボードに書き込み)
11. 最終結果を表示
重要: すべてのブラックボードファイル(state.yaml, entities_raw.json, model.json など)は、プロジェクトごとに独立した artifacts/{project_name}/ ディレクトリ内に保存されます。
Phase 0.5: ユースケース詳細化
目的
漠然とした要求メモから作成されたユースケースを、API設計に十分な詳細レベルに引き上げます。 AIが推定した基本的なユースケースを叩き台として、ユーザーの業務知識を反映させることでモデル精度を向上させます。
ブラックボードからの入力
usecase.md(Phase 0で生成された基本的なユースケース)state.yamlのproject_nameフィールド
処理内容
このフェーズは /usecase-detailer スキルを使用して実行します。
詳細化する要素:
CRUD操作の補完
- Create: どのエンティティをどのタイミングで作成?
- Read: どの検索条件・フィルター・ソートが必要?
- Update: どの属性を変更可能?誰が変更可能?
- Delete: 論理削除?物理削除?削除条件は?
エラーケースの定義
- バリデーションエラー(必須項目、型、範囲)
- ビジネスルール違反(重複、権限、状態遷移)
- 外部依存エラー(DB接続、外部API)
検証ルールの抽出
- 必須項目の明確化
- 値の範囲・形式制約
- 一意性制約
- 関連性制約(外部キー、状態遷移)
APIマッピング
- HTTPメソッド(GET/POST/PUT/DELETE)
- エンドポイント案
- リクエスト/レスポンス形式
対話的詳細化:
各ユースケースに対して、以下の質問を対話的に行います:
- 「このユースケースでは、どのエンティティを作成/更新しますか?」
- 「顧客を選択する際、どんな検索条件が必要ですか?」
- 「プロジェクト名に制約はありますか?」
- 「登録が失敗するのはどんな場合ですか?」
実行方法:
/usecase-detailer {project_name}
このコマンドにより、usecase.md を読み込み、対話的に詳細化を行い、usecase_detailed.md を生成します。
ブラックボードへの出力
usecase_detailed.md に以下の形式で書き込み:
# ユースケース詳細仕様
## UC-01: プロジェクト登録
### 基本フロー
1. **顧客選択**
- 検索条件: 顧客名(部分一致)、業界
- ソート: 顧客名昇順
- エラー: 顧客が存在しない場合 → 404 Customer Not Found
2. **プロジェクト情報入力**
- 必須項目: プロジェクト名、予定開始日、契約金額
- 任意項目: 説明、開発種別
- バリデーション:
- プロジェクト名: 1-200文字
- 契約金額: 0以上
- 予定開始日: 今日以降
3. **登録実行**
- Create: PROJECT レコード
- 重複チェック: 同一顧客×同一プロジェクト名 → 409 Conflict
- レスポンス: 201 Created + project_id
### API マッピング
- エンドポイント: POST /api/projects
- Request Body: { customer_id, project_name, planned_start_date, contract_amount, description?, developmentTypeID? }
- Success: 201 Created
- Errors: 400 (バリデーション), 404 (顧客不存在), 409 (重複)
次フェーズへの遷移
state.yaml を更新:
current_phase: entity_extraction
completed_phases:
- usecase_detailing
スキップ判断:
- 詳細化が必要: ユースケースが抽象的(検索条件・エラーケース未定義)→ Phase 0.5を実行
- スキップ可能: ユースケースが既に詳細(API設計に十分な情報)→ Phase 1へ直接進む
詳細な実装は /usecase-detailer スキルを参照してください。
Phase 1: エンティティ抽出
目的
ユースケース記述から、データモデリングに必要な**名詞(エンティティ候補)と動詞(イベント候補)**を抽出します。
ブラックボードからの入力
state.yamlのinput_usecaseフィールド(ユーザーが入力したユースケース記述)
処理内容
以下の基準でエンティティ候補を抽出してください:
名詞の抽出:
- 人、物、組織、概念を表す名詞
- データとして管理すべき対象
- 抽象的すぎる概念(「システム」「データ」「情報」など)は除外
動詞の抽出:
- 業務アクションを示す動詞
- 特定の時点で発生する行為
- 「〜する」「〜される」という形式
命名規則:
- 名詞: PascalCase、単数形(例:
Customer,Invoice) - 動詞: camelCase(例:
send,confirm) - 詳細は
templates/naming-rules.mdを参照
ブラックボードへの出力
entities_raw.json に以下の形式で書き込み:
{
"noun_candidates": [
{
"japanese": "顧客",
"english": "Customer",
"note": "請求書を受け取る対象"
},
{
"japanese": "請求書",
"english": "Invoice",
"note": "顧客に送付される文書"
}
],
"verb_candidates": [
{
"japanese": "送付する",
"english": "send",
"note": "請求書や確認状を送る行為"
}
]
}
次フェーズへの遷移
state.yaml を更新:
current_phase: classification
completed_phases:
- entity_extraction
Phase 2: リソース/イベント分類
目的
抽出されたエンティティ候補を、リソースとイベントに分類します。 これはイミュータブルデータモデルの基本原則です。
ブラックボードからの入力
entities_raw.json
処理内容
分類基準:
リソース(Resource):
- 継続的に存在するもの
- 時間経過で状態が変化しうるもの
- 「〜がある」「〜を管理する」という表現で説明できる
- 例: 顧客、商品、社員、部署
イベント(Event):
- 特定時点で発生した事実
- 一度発生したら変更されないもの(不変)
- 「〜した」「〜が発生した」という表現で説明できる
- 必ず1つの日時属性を持つ(最重要)
- 例: 注文、入金、出荷、請求書送付
イベント命名の推奨形式:
- 動詞 + 名詞:
InvoiceSend(請求書送付)、PaymentMake(入金) - 詳細は
templates/naming-rules.mdを参照
参考資料:
templates/immutable-model-rules.mdの「エンティティの分類」セクション
ブラックボードへの出力
entities_classified.json に以下の形式で書き込み:
{
"resources": [
{
"japanese": "顧客",
"english": "Customer",
"attributes": [
{
"japanese": "顧客ID",
"english": "customer_id",
"type": "INT",
"is_primary_key": true
},
{
"japanese": "顧客名",
"english": "Name",
"type": "VARCHAR(100)",
"is_primary_key": false
}
],
"note": "請求書を受け取る主体"
}
],
"events": [
{
"japanese": "請求書送付",
"english": "InvoiceSend",
"datetime_attribute": {
"japanese": "送付日時",
"english": "send_date_time",
"type": "TIMESTAMP"
},
"attributes": [
{
"japanese": "イベントID",
"english": "event_id",
"type": "INT",
"is_primary_key": true
},
{
"japanese": "送付日時",
"english": "send_date_time",
"type": "TIMESTAMP",
"is_primary_key": false
},
{
"japanese": "送付方法",
"english": "send_method",
"type": "VARCHAR(50)",
"is_primary_key": false
}
],
"note": "顧客に請求書を送付した事実"
}
]
}
次フェーズへの遷移
state.yaml を更新:
current_phase: relationship_analysis
completed_phases:
- entity_extraction
- classification
Phase 2.5: 属性レビュー&編集
目的
Phase 2で自動推定された属性をユーザーに提示し、対話的に確認・修正できるようにします。 AIが推定した属性を叩き台として、ユーザーの業務知識を反映させることでモデル精度を向上させます。
ブラックボードからの入力
entities_classified.json(Phase 2で生成された分類済みエンティティ)
処理内容
ステップ1: 属性一覧の表示
全エンティティの属性をMarkdown表形式で表示します。
表示形式:
# 属性レビュー
以下の属性が自動推定されました。内容を確認し、必要に応じて修正してください。
## リソース
### Customer(顧客)
| 属性名(日本語) | 属性名(英語) | 型 | 主キー | 備考 |
|---------------|--------------|-----|--------|------|
| 顧客ID | customer_id | INT | ✓ | |
| 顧客名 | name | VARCHAR(100) | | |
| 住所 | address | VARCHAR(255) | | |
| 電話番号 | phone | VARCHAR(20) | | |
| 作成日時 | created_at | TIMESTAMP | | |
**説明**: 請求書を受け取る主体。継続的に存在し管理される
---
### Invoice(請求書)
| 属性名(日本語) | 属性名(英語) | 型 | 主キー | 備考 |
|---------------|--------------|-----|--------|------|
| 請求書ID | invoice_id | INT | ✓ | |
| 顧客ID | customer_id | INT | | 外部キー |
| 請求番号 | invoice_number | VARCHAR(50) | | |
| 発行日 | issue_date | DATE | | |
| 請求金額 | amount | DECIMAL(10,2) | | |
| 支払期日 | due_date | DATE | | |
**説明**: 発行された請求文書。顧客に対する請求内容を保持
---
## イベント
### InvoiceSend(請求書送付)
**日時属性**: 送付日時(send_date_time)- TIMESTAMP
| 属性名(日本語) | 属性名(英語) | 型 | 主キー | 備考 |
|---------------|--------------|-----|--------|------|
| イベントID | event_id | INT | ✓ | |
| 請求書ID | invoice_id | INT | | 外部キー |
| 顧客ID | customer_id | INT | | 外部キー |
| 送付日時 | send_date_time | TIMESTAMP | | **日時属性** |
| 送付方法 | send_method | VARCHAR(50) | | |
**説明**: 請求書を顧客に送付した事実。特定時点で発生した不変のイベント
ステップ2: メインメニュー
ユーザーに以下のメニューを提示します:
このまま次のフェーズ(関連分析)に進みますか?
1. 既存エンティティの属性を修正する
2. 新しいエンティティを追加する
3. エンティティを削除する
4. このまま進む
番号を入力してください:
選択肢の説明:
- 選択肢1: 既存エンティティの属性を追加・削除・修正(従来の属性修正フロー)
- 選択肢2: 新しいリソースまたはイベントエンティティを追加
- 選択肢3: 既存エンティティを削除(外部キー参照チェックあり)
- 選択肢4: 現在のモデルを確定し、Phase 3(関連分析)に進む
ステップ3: 既存エンティティの属性修正フロー(選択肢1)
ユーザーが「1. 既存エンティティの属性を修正する」を選択した場合、以下の対話的な修正フローを実行します。
3-1. エンティティ選択
どのエンティティを修正しますか?
【リソース】
1. Customer(顧客)
2. Invoice(請求書)
【イベント】
3. InvoiceSend(請求書送付)
4. Payment(入金)
5. ConfirmationSend(確認状送付)
番号を入力してください(終了する場合は 0):
3-2. 修正操作選択
Customer(顧客)の属性をどう修正しますか?
1. 属性を追加する
2. 属性を削除する
3. 属性を修正する
4. 戻る
番号を入力してください:
3-3. 属性の追加
新しい属性を追加します。以下の情報を入力してください。
属性名(日本語):
属性名(英語):
型(例: INT, VARCHAR(100), DECIMAL(10,2), TIMESTAMP, DATE):
主キーにしますか?(y/n):
[入力後]
以下の属性を追加します:
- 属性名(日本語): メールアドレス
- 属性名(英語): Email
- 型: VARCHAR(100)
- 主キー: いいえ
追加してよろしいですか?(y/n):
検証ルール:
- 主キーは1エンティティに1つのみ(既存の主キーがある場合は警告)
- 英語名はPascalCase推奨、型は有効なSQL型
- イベントエンティティの場合、日時属性(TIMESTAMP型)の重複追加を警告
3-4. 属性の削除
削除する属性を選択してください:
1. 顧客ID (customer_id) - INT - 主キー
2. 顧客名 (name) - VARCHAR(100)
3. 住所 (address) - VARCHAR(255)
4. 電話番号 (phone) - VARCHAR(20)
5. 作成日時 (created_at) - TIMESTAMP
番号を入力してください:
検証ルール:
- 主キーは削除不可(エラーメッセージを表示)
- イベントの日時属性(datetime_attribute)は削除不可
- 外部キーの可能性がある属性は警告(
{エンティティ名}ID形式)
エラーメッセージ例:
[エラー] 主キーは削除できません。
理由: すべてのエンティティには必ず1つの主キーが必要です。
現在の主キー: customer_id
対処方法:
1. 別の属性を主キーに設定する
2. その後、現在の主キーを削除する
[エラー] イベントの日時属性は削除できません。
理由: イベントエンティティは必ず1つの日時属性を持つ必要があります。
これはイミュータブルデータモデルの基本原則です。
現在の日時属性: send_date_time (TIMESTAMP)
参考: templates/immutable-model-rules.md の「イベントの日時属性に関するルール」
3-5. 属性の修正
修正する属性を選択してください:
1. 顧客ID (customer_id) - INT - 主キー
2. 顧客名 (name) - VARCHAR(100)
3. 住所 (address) - VARCHAR(255)
4. 電話番号 (phone) - VARCHAR(20)
5. 作成日時 (created_at) - TIMESTAMP
番号を入力してください:
[選択後]
修正する項目を選択してください:
1. 属性名(日本語)
2. 属性名(英語)
3. 型
4. 主キーフラグ
番号を入力してください:
[選択後]
現在の値: VARCHAR(100)
新しい値: VARCHAR(255)
[入力後]
以下のように修正します:
- 顧客名 (name): VARCHAR(100) → VARCHAR(255)
修正してよろしいですか?(y/n):
検証ルール:
- 主キーを外す場合、他に主キーがあることを確認
- イベントの日時属性名を変更する場合、
datetime_attributeとattributesの両方を更新
3-6. 変更後の再表示
修正が完了しました。更新後の属性を確認してください。
### Customer(顧客)
| 属性名(日本語) | 属性名(英語) | 型 | 主キー | 備考 |
|---------------|--------------|-----|--------|------|
| 顧客ID | customer_id | INT | ✓ | |
| 顧客名 | name | VARCHAR(255) | | ← 修正 |
| 住所 | address | VARCHAR(255) | | |
| 電話番号 | phone | VARCHAR(20) | | |
| メールアドレス | Email | VARCHAR(100) | | ← 追加 |
| 作成日時 | created_at | TIMESTAMP | | |
引き続き他のエンティティを修正しますか?(y/n):
ステップ3.1: エンティティ追加フロー(選択肢2)
ユーザーが「2. 新しいエンティティを追加する」を選択した場合、以下のフローを実行します。
3.1-1. エンティティ種別の選択
どの種類のエンティティを追加しますか?
1. リソース(Resource)- 継続的に存在するもの
例: 顧客、商品、従業員、部署、業界、開発種別
2. イベント(Event)- 特定時点で発生した事実
例: 注文、入金、出荷、評価、リスク評価、プロジェクト開始
番号を入力してください:
エンティティ種別の説明:
- リソース: システムで管理する対象物。継続的に存在し、状態が変化する可能性がある
- イベント: 特定の時点で発生した事実。一度発生したら不変(イミュータブル)
3.1-2. リソースエンティティの追加
ユーザーが「1. リソース」を選択した場合:
=== リソースエンティティの追加 ===
エンティティ名(日本語):
> 開発種別
エンティティ名(英語):
> DevelopmentType
説明(note):
> 開発種別のマスターデータ(新規開発、保守開発など)
[確認画面]
以下のリソースエンティティを追加します:
- 日本語名: 開発種別
- 英語名: DevelopmentType
- 説明: 開発種別のマスターデータ(新規開発、保守開発など)
自動生成される属性(★自動生成):
1. development_type_id (INT, 主キー) ★
2. development_type_name (VARCHAR(100)) ★
3. created_at (TIMESTAMP) ★
追加の属性を定義しますか?(y/n):
自動生成ルール:
- 主キー:
{EntityName}ID(INT, 主キー) - name属性:
{entity_name}_name(VARCHAR(100)) - 作成日時:
created_at(TIMESTAMP)
追加属性の定義(yを選択した場合):
[属性追加ループ - 既存の3-3. 属性の追加フローを再利用]
属性名(日本語):
> 説明
属性名(英語):
> description
型(例: INT, VARCHAR(100), TEXT, TIMESTAMP):
> TEXT
主キーにしますか?(y/n):
> n
もう1つ属性を追加しますか?(y/n):
> n
最終確認:
以下の内容でリソースエンティティを追加します:
### DevelopmentType(開発種別)
| 属性名(日本語) | 属性名(英語) | 型 | 主キー | 自動生成 |
|---------------|--------------|-----|--------|---------|
| 開発種別ID | development_type_id | INT | ✓ | ★ |
| 開発種別名 | development_type_name | VARCHAR(100) | | ★ |
| 説明 | description | TEXT | | |
| 作成日時 | created_at | TIMESTAMP | | ★ |
**説明**: 開発種別のマスターデータ(新規開発、保守開発など)
この内容で追加してよろしいですか?(y/n):
> y
✅ DevelopmentType エンティティを追加しました。
3.1-3. イベントエンティティの追加
ユーザーが「2. イベント」を選択した場合:
=== イベントエンティティの追加 ===
イベント名(日本語):
> プロジェクト開始
イベント名(英語):
> ProjectStart
説明(note):
> プロジェクトが正式に発足した事実
[日時属性の定義 - イベント特有]
イベントには必ず1つの日時属性が必要です。
日時属性名(日本語):
> 開始日時
日時属性名(英語):
> start_date_time
[確認画面]
以下のイベントエンティティを追加します:
- 日本語名: プロジェクト開始
- 英語名: ProjectStart
- 説明: プロジェクトが正式に発足した事実
- 日時属性: start_date_time (TIMESTAMP)
自動生成される属性(★自動生成):
1. event_id (INT, 主キー) ★
2. start_date_time (TIMESTAMP) ← 日時属性
追加の属性を定義しますか?(y/n):
自動生成ルール(イベント):
- 主キー:
event_id(INT, 主キー) - イベントは汎用的なevent_idを使用 - 日時属性: ユーザー指定の名前 (TIMESTAMP)
追加属性の定義(yを選択した場合):
[属性追加ループ]
属性名(日本語):
> プロジェクトID
属性名(英語):
> project_id
型:
> INT
主キーにしますか?(y/n):
> n
もう1つ属性を追加しますか?(y/n):
> y
属性名(日本語):
> 登録者
属性名(英語):
> registered_by
型:
> INT
主キーにしますか?(y/n):
> n
もう1つ属性を追加しますか?(y/n):
> n
最終確認:
以下の内容でイベントエンティティを追加します:
### ProjectStart(プロジェクト開始)
**日時属性**: start_date_time (TIMESTAMP)
| 属性名(日本語) | 属性名(英語) | 型 | 主キー | 自動生成 |
|---------------|--------------|-----|--------|---------|
| イベントID | event_id | INT | ✓ | ★ |
| プロジェクトID | project_id | INT | | |
| 開始日時 | start_date_time | TIMESTAMP | | (日時属性) |
| 登録者 | registered_by | INT | | |
**説明**: プロジェクトが正式に発足した事実
この内容で追加してよろしいですか?(y/n):
> y
✅ ProjectStart イベントエンティティを追加しました。
3.1-4. 検証ルール(エンティティ追加時)
1. 命名規則チェック:
- 英語名: PascalCase、単数形、特殊文字なし
- 日本語名: 空でない、わかりやすい名称
- 重複チェック: 既存のエンティティ名と被っていないか
エラーメッセージ例:
[エラー] エンティティ名が既に存在します: "Customer"
既存のエンティティ:
- Customer(顧客) - リソース
別の名前を入力してください:
2. イベント特有チェック:
- 日時属性必須(TIMESTAMP型)
datetime_attributeとattributes両方に含める
3. リソース特有チェック:
- 主キー必須({EntityName}ID)
- Name属性は推奨(自動生成で含まれる)
3.1-5. entities_classified.json への追加
追加したエンティティを entities_classified.json に書き込みます。
リソースの場合:
{
"resources": [
{
"japanese": "開発種別",
"english": "DevelopmentType",
"attributes": [
{
"japanese": "開発種別ID",
"english": "development_type_id",
"type": "INT",
"is_primary_key": true
},
{
"japanese": "開発種別名",
"english": "development_type_name",
"type": "VARCHAR(100)",
"is_primary_key": false
},
{
"japanese": "説明",
"english": "description",
"type": "TEXT",
"is_primary_key": false
},
{
"japanese": "作成日時",
"english": "created_at",
"type": "TIMESTAMP",
"is_primary_key": false
}
],
"note": "開発種別のマスターデータ(新規開発、保守開発など)"
}
]
}
イベントの場合:
{
"events": [
{
"japanese": "プロジェクト開始",
"english": "ProjectStart",
"datetime_attribute": {
"japanese": "開始日時",
"english": "start_date_time",
"type": "TIMESTAMP"
},
"attributes": [
{
"japanese": "イベントID",
"english": "event_id",
"type": "INT",
"is_primary_key": true
},
{
"japanese": "プロジェクトID",
"english": "project_id",
"type": "INT",
"is_primary_key": false
},
{
"japanese": "開始日時",
"english": "start_date_time",
"type": "TIMESTAMP",
"is_primary_key": false
},
{
"japanese": "登録者",
"english": "registered_by",
"type": "INT",
"is_primary_key": false
}
],
"note": "プロジェクトが正式に発足した事実"
}
]
}
ステップ3.2: エンティティ削除フロー(選択肢3)
ユーザーが「3. エンティティを削除する」を選択した場合、以下のフローを実行します。
3.2-1. エンティティ選択
=== エンティティの削除 ===
削除するエンティティを選択してください:
【リソース】
1. Project(プロジェクト)
2. Customer(顧客)
3. DevelopmentType(開発種別)
4. Industry(業界)
【イベント】
5. ProjectStart(プロジェクト開始)
6. RiskEvaluate(リスク評価)
7. InvoiceSend(請求書送付)
番号を入力してください(キャンセルは 0):
3.2-2. 外部キー参照チェック
選択されたエンティティが他のエンティティから参照されているかをチェックします。
検出ロジック:
全エンティティをスキャンして {EntityName}ID 属性を検索します。
例: DevelopmentType を削除しようとした場合:
[外部キー参照チェック実行中...]
以下のエンティティに "development_type_id" 属性が見つかりました:
- Project(プロジェクト)
- PROJECT_DEVELOPMENT_TYPE(ジャンクションテーブル)
3.2-3. 削除確認
以下のエンティティを削除しようとしています:
- 日本語名: 開発種別
- 英語名: DevelopmentType
- 種類: リソース
【警告】この操作は取り消せません。
このエンティティは他のエンティティから参照されている可能性があります:
- Project エンティティに development_type_id 属性があります
- PROJECT_DEVELOPMENT_TYPE エンティティに development_type_id 属性があります
削除すると、Phase 3(関連分析)でこの関係が失われます。
また、Phase 6(DDL生成)で外部キー制約エラーが発生する可能性があります。
本当に削除してよろしいですか?(yes と完全に入力してください):
検証ルール:
- 単純な
yやyes以外の完全入力を要求 - 大文字小文字を区別(
yesのみ受け付ける)
削除実行:
> yes
✅ DevelopmentType エンティティを削除しました。
entities_classified.json から削除されました。
引き続き他のエンティティを削除しますか?(y/n):
> n
メインメニューに戻ります。
キャンセル:
> no
削除をキャンセルしました。
メインメニューに戻ります。
3.2-4. entities_classified.json からの削除
削除したエンティティを entities_classified.json から除外します。
削除前:
{
"resources": [
{"english": "Project", ...},
{"english": "Customer", ...},
{"english": "DevelopmentType", ...} ← 削除対象
]
}
削除後:
{
"resources": [
{"english": "Project", ...},
{"english": "Customer", ...}
]
}
ステップ4: イベントエンティティの特殊処理
イベントエンティティの修正時は、以下の特殊なルールを適用します。
datetime_attributeの整合性維持:
// entities_classified.jsonの構造
{
"events": [
{
"datetime_attribute": {
"japanese": "送付日時",
"english": "send_date_time",
"type": "TIMESTAMP"
},
"attributes": [
{
"japanese": "送付日時", // ← datetime_attributeと重複
"english": "send_date_time",
"type": "TIMESTAMP"
}
]
}
]
}
処理ルール:
datetime_attributeの修正時、attributes内の対応する属性も同時に更新attributes内の日時属性を修正する場合、datetime_attributeも更新- 日時属性は削除不可(警告メッセージを表示)
- イベントに日時属性は1つのみ(追加時に検証)
警告メッセージ例:
[警告] イベントには既に日時属性「send_date_time」があります。
イベントには1つの日時属性のみを持たせる必要があります。
複数の日時が必要な場合は、イベントを分割してください。
参考: templates/immutable-model-rules.md の「イベントの日時属性に関するルール」
ステップ5: 最終確認と保存
すべての修正が完了しました。
【変更サマリー】
- Customer(顧客): 1件の属性を修正、1件の属性を追加
- Invoice(請求書): 変更なし
- InvoiceSend(請求書送付): 変更なし
この内容で確定してよろしいですか?(y/n):
[yを選択した場合]
entities_classified.json を更新しました。
次のフェーズ(関連分析)に進みます。
ブラックボードへの出力
修正後の内容で entities_classified.json を上書き保存します。
変更検出:
- 変更がない場合: そのまま次フェーズへ
- 変更がある場合: ファイルを上書き後、次フェーズへ
次フェーズへの遷移
state.yaml を更新:
current_phase: relationship_analysis
completed_phases:
- entity_extraction
- classification
- attribute_review # ← 新規追加
エラーハンドリング
型の妥当性チェック
サポートする型:
【整数型】
INT, INTEGER, BIGINT, SMALLINT, TINYINT
【文字列型】
VARCHAR(n) - 可変長文字列(例: VARCHAR(100))
CHAR(n) - 固定長文字列(例: CHAR(10))
TEXT - 長文テキスト
【数値型】
DECIMAL(m,n) - 固定小数点(例: DECIMAL(10,2))
NUMERIC(m,n) - 数値型
FLOAT, DOUBLE - 浮動小数点
【日時型】
TIMESTAMP - 日時(推奨)
DATE - 日付
TIME - 時刻
DATETIME - 日時
【真偽値型】
BOOLEAN, BOOL
エラーメッセージ:
[エラー] 無効な型が指定されました: "VACHAR(100)"
有効な型の例を上記に示します。
もう一度入力してください:
命名規則の検証
警告レベル(推奨に従っていない場合):
[警告] 英語名が命名規則に従っていません: "customer_id"
推奨される命名規則:
- エンティティ名: PascalCase(例: Customer, InvoiceSend)
- 属性名: PascalCase(例: customer_id, send_date_time)
推奨される名前: "customer_id"
このまま続けますか?(y/n):
外部キーの可能性の警告
検出ロジック: {エンティティ名}ID 形式をチェック
[警告] この属性は外部キーの可能性があります: "customer_id"
推測される参照先エンティティ: Customer
この属性を削除すると、Phase 3(関連分析)で以下の影響があります:
- Customer との関連が自動検出されなくなります
- 手動で外部キー制約を定義する必要が生じます
本当に削除してよろしいですか?(y/n):
Phase 3: 関連分析
目的
エンティティ間の関連(リレーションシップ)を分析し、カーディナリティと外部キーを決定します。 また、必要に応じて交差エンティティを導入します。
ブラックボードからの入力
entities_classified.json
処理内容
カーディナリティの決定:
- 1:1(一対一): 例: 国 ←→ 首都
- 1:N(一対多): 例: 顧客 → 注文
- M:N(多対多): 必ず交差エンティティで解消
交差エンティティの導入基準:
以下のいずれかに該当する場合、交差エンティティを導入します:
- 多対多の関係である
- 関連に日時情報が必要
- 関連に数量・金額などの属性が必要
- 関連自体が業務上の意味を持つ
例: 学生と講義(多対多)
学生 ← 履修(交差エンティティ) → 講義
履修 {
学生ID (FK)
講義ID (FK)
履修日時
成績
}
外部キーの決定:
- 参照先のテーブルの主キー名をそのまま使用
- 例:
Customer.customer_id→InvoiceSend.customer_id
参考資料:
templates/immutable-model-rules.mdの「交差エンティティの導入」セクションtemplates/naming-rules.mdの「外部キー」セクション
不足エンティティの自動検出とPhase 2.5への反復ループ
Phase 3の関連分析中に、不足している可能性のあるエンティティを自動検出します。 検出された場合、ユーザーに提案してPhase 2.5(属性レビュー&編集)に戻り、エンティティを追加します。
検出ロジック
以下のパターンで不足エンティティを検出します:
1. 外部キー候補属性の参照先が存在しない
全エンティティの属性をスキャンし、{EntityName}ID パターンの属性を検出:
- 型が
INTまたはBIGINT - 主キーではない
- 対応する
{EntityName}エンティティが存在しない
検出例:
Invoice エンティティに customer_id 属性がありますが、Customer エンティティが存在しません。
Project エンティティに industry_id 属性がありますが、Industry エンティティが存在しません。
Customer エンティティに industry_id 属性がありますが、Industry エンティティが存在しません。
2. 推測されるエンティティ種別
属性名から推測される適切なエンティティ種別を判定します:
| 属性名パターン | 推測される種別 | 理由 |
|---|---|---|
| customer_id | リソース | 顧客は継続的に存在する主体 |
| industry_id | リソース | 業界は分類マスターデータ |
| development_type_id | リソース | 開発種別は分類マスターデータ |
| payment_id | イベント | 入金は特定時点の事実 |
| order_id | イベントまたはリソース | ユースケース次第で判断 |
判定ルール:
- 名詞が「種別」「タイプ」「分類」「業界」「カテゴリ」の場合 → リソース(マスターデータ)
- 名詞が動詞由来(入金、発注、承認など)の場合 → イベント
- 不明な場合 → リソースとして推奨(安全側)
検出時のユーザー提示
不足エンティティを検出した場合、以下のようにユーザーに提示します:
【Phase 3: 不足エンティティを検出しました】
関連分析の結果、以下のエンティティが不足している可能性があります:
1. Customer(顧客)
- 理由: Invoice に customer_id 属性がありますが、Customer エンティティが存在しません
- 推奨種別: リソース
- 推奨属性:
- customer_id (INT, 主キー)
- CustomerName (VARCHAR(100))
- created_at (TIMESTAMP)
2. Industry(業界)
- 理由: Customer に industry_id 属性がありますが、Industry エンティティが存在しません
- 推奨種別: リソース
- 推奨属性:
- industry_id (INT, 主キー)
- IndustryName (VARCHAR(100))
- created_at (TIMESTAMP)
3. Payment(入金)
- 理由: Invoice に payment_id 属性がありますが、Payment エンティティが存在しません
- 推奨種別: イベント(入金は特定時点の事実)
- 推奨属性:
- event_id (INT, 主キー)
- payment_date_time (TIMESTAMP, 日時属性)
- invoice_id (INT)
- amount (DECIMAL(10,2))
次のアクションを選択してください:
1. Phase 2.5に戻ってエンティティを追加する(推奨)
2. このまま進む(警告: 外部キー制約が作成されません)
番号を入力してください:
選択肢の説明:
- 選択肢1(推奨): Phase 2.5のメインメニューに戻り、「2. 新しいエンティティを追加する」で提案されたエンティティを追加できます
- 選択肢2: 不足エンティティを無視して進みます(非推奨)。この場合、以下の警告を表示:
[警告] 不足エンティティを無視して進みます。
以下の影響があります:
- customer_id、industry_id、payment_id の外部キー制約が作成されません
- Phase 6(DDL生成)でこれらの属性は通常のINT型として扱われます
- 参照整合性チェックが行われません
後からPhase 2.5に戻ることはできません。
本当にこのまま進みますか?(yes と完全に入力してください):
Phase 2.5への反復ループ
ユーザーが「1. Phase 2.5に戻ってエンティティを追加する」を選択した場合:
1. state.yamlの更新:
current_phase: attribute_review # Phase 2.5に戻す
completed_phases:
- entity_extraction
- classification
phase_iterations:
attribute_review_to_relationship: 1 # 反復カウンター初期化または増分
missing_entities_suggestions: # 検出された不足エンティティを記録
- name: Customer
type: resource
reason: "Invoice に customer_id 属性がありますが、Customer エンティティが存在しません"
- name: Industry
type: resource
reason: "Customer に industry_id 属性がありますが、Industry エンティティが存在しません"
2. Phase 2.5の再開:
Phase 2.5のメインメニューが表示され、ユーザーは:
- 提案されたエンティティを「2. 新しいエンティティを追加する」で追加
- 必要に応じて既存エンティティの属性も修正
- 完了後、「4. このまま進む」でPhase 3に戻る
3. Phase 3の再実行:
Phase 2.5完了後、再度Phase 3を実行:
- 新しく追加されたエンティティを含めて関連分析を実施
- 再度不足エンティティをチェック
- 不足がなければ次フェーズへ進む
- まだ不足があれば再度Phase 2.5へ(無制限反復)
4. 反復カウンターの管理:
phase_iterations:
attribute_review_to_relationship: 3 # 3回目の反復
反復制限:
- 制限なし: ユーザーがOKするまで無制限に反復可能
- 各反復で
state.yamlのphase_iterations.attribute_review_to_relationshipをインクリメント - 10回を超えた場合は警告メッセージを表示(無限ループの可能性)
[警告] Phase 2.5 ↔ Phase 3 の反復が10回を超えました。
反復回数: 11回
モデリングが複雑化している可能性があります。
以下を確認してください:
- エンティティの粒度が適切か
- 循環参照が発生していないか
- マスターデータとトランザクションデータが混在していないか
それでも続けますか?(y/n):
反復ループの終了条件
以下のいずれかで反復ループを終了します:
- 不足エンティティが0件: 自動的に次フェーズへ進む
- ユーザーが「このまま進む」を選択: Phase 3完了として次フェーズへ
- ユーザーが反復を中断: state.yamlをクリーンアップし、Phase 2.5で停止
検出結果の記録
state.yaml に検出結果を記録:
phase_3_analysis:
missing_entities_detected: 3
missing_entities:
- Customer
- Industry
- Payment
user_action: returned_to_phase_2_5 # または ignored
iteration_count: 2
ブラックボードへの出力
model.json に以下の形式で書き込み:
{
"entities": [
{
"name": "Customer",
"type": "resource",
"attributes": [...]
},
{
"name": "InvoiceSend",
"type": "event",
"attributes": [...]
}
],
"relationships": [
{
"from": "Customer",
"to": "InvoiceSend",
"cardinality": "1:N",
"from_attribute": "customer_id",
"to_attribute": "customer_id",
"relationship_type": "sends"
}
]
}
次フェーズへの遷移
state.yaml を更新:
current_phase: validation
completed_phases:
- entity_extraction
- classification
- relationship_analysis
Phase 4: 検証
目的
作成したデータモデルがイミュータブルデータモデルの原則に準拠しているかを検証します。
ブラックボードからの入力
model.json
処理内容
以下のチェックリストで検証してください:
イベントの検証:
- すべてのイベントに1つだけ日時属性がある
- イベントに複数の日時属性がないか(ある場合はイベントを分割)
- イベント名が動詞+名詞の形式になっているか
リソースの検証:
- リソースに不要な日時属性がないか(更新日時など)
- 隠れたイベントが抽出されているか
関連の検証:
- 多対多の関係が交差エンティティで解消されているか
- 外部キー制約が適切に定義されているか
命名規則の検証:
- エンティティ名が単数形・PascalCaseか
- 主キーが
{エンティティ名}ID形式か - 外部キーが参照先の主キー名と一致しているか
参考資料:
templates/immutable-model-rules.md全体templates/naming-rules.md全体
ブラックボードへの出力
validation_result.json に以下の形式で書き込み:
{
"is_valid": true,
"errors": [],
"warnings": [
{
"entity": "Customer",
"message": "リソースに 'updated_at' 属性があります。隠れたイベントがないか確認してください。"
}
],
"suggestions": [
{
"message": "InvoiceSend イベントと ConfirmationSend イベントを統合して SendDocument イベントにすることも検討できます。"
}
]
}
次フェーズへの遷移
検証結果が is_valid: true の場合のみ次へ進む。
エラーがある場合は、該当フェーズに戻って修正。
state.yaml を更新:
current_phase: diagram_generation
completed_phases:
- entity_extraction
- classification
- relationship_analysis
- validation
Phase 5: ER図生成
目的
最終的なデータモデルをMermaid形式のER図として出力します。
ブラックボードからの入力
model.jsonvalidation_result.json
処理内容
Mermaid ER図の形式で出力してください。
カーディナリティ表記:
||--o{: 1対多(1 to many)||--||: 1対1(1 to 1)}o--o{: 多対多(交差エンティティ経由)
属性表記:
PK: Primary KeyFK: Foreign Key- 型も記載(
int,varchar,timestampなど)
ブラックボードへの出力
er_diagram.mmd に以下の形式で書き込み:
erDiagram
CUSTOMER ||--o{ INVOICE_SEND : "sends"
CUSTOMER {
int customer_id PK
varchar name
varchar address
varchar phone
timestamp created_at
}
INVOICE_SEND {
int event_id PK
int customer_id FK
timestamp send_date_time
varchar send_method
}
次フェーズへの遷移
state.yaml を更新:
current_phase: ddl_generation
completed_phases:
- entity_extraction
- classification
- relationship_analysis
- validation
- diagram_generation
Phase 6: DDL生成
目的
データモデルからPostgreSQL用のCREATE TABLE文を生成します。 イミュータブルデータモデルのテーブル構造を実際のRDBMSで実現可能にします。
ブラックボードからの入力
model.json
処理内容
PostgreSQL DDLの生成ルール:
型マッピング:
INT→INTEGERVARCHAR(n)→VARCHAR(n)DECIMAL(m,n)→NUMERIC(m,n)TIMESTAMP→TIMESTAMP WITH TIME ZONEDATE→DATE
主キー制約:
- すべてのエンティティに
PRIMARY KEY制約を設定 - シーケンスを使った自動採番を推奨:
SERIALまたはGENERATED ALWAYS AS IDENTITY
外部キー制約:
relationshipsの情報からFOREIGN KEY制約を生成- 参照整合性を保証
ON DELETE/ON UPDATEポリシー:- リソース → イベント:
ON DELETE RESTRICT(リソース削除時はイベントが残っているため削除不可) - イベント → リソース:
ON DELETE RESTRICT(リソース削除時は関連イベントも確認が必要)
- リソース → イベント:
NOT NULL制約:
- 主キーは自動的に
NOT NULL - 外部キーは基本的に
NOT NULL(業務上必須の場合) - イベントの日時属性は
NOT NULL
テーブル名:
- エンティティ名を大文字スネークケースに変換(例:
InvoiceSend→INVOICE_SEND)
コメント:
COMMENT ON TABLEでテーブルの説明を追加COMMENT ON COLUMNで各カラムの日本語名を追加
ブラックボードへの出力
schema.sql に以下の形式で書き込み:
-- ================================================
-- イミュータブルデータモデル DDL
-- 生成日時: YYYY-MM-DD HH:MM:SS
-- ================================================
-- リソーステーブル
CREATE TABLE CUSTOMER (
customer_id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
name VARCHAR(100) NOT NULL,
address VARCHAR(255),
phone VARCHAR(20),
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
);
COMMENT ON TABLE CUSTOMER IS '顧客';
COMMENT ON COLUMN CUSTOMER.customer_id IS '顧客ID';
COMMENT ON COLUMN CUSTOMER.name IS '顧客名';
COMMENT ON COLUMN CUSTOMER.address IS '住所';
COMMENT ON COLUMN CUSTOMER.phone IS '電話番号';
COMMENT ON COLUMN CUSTOMER.created_at IS '作成日時';
-- イベントテーブル
CREATE TABLE INVOICE_SEND (
event_id INTEGER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
invoice_id INTEGER NOT NULL,
customer_id INTEGER NOT NULL,
send_date_time TIMESTAMP WITH TIME ZONE NOT NULL,
send_method VARCHAR(50),
CONSTRAINT fk_invoice_send_invoice FOREIGN KEY (invoice_id)
REFERENCES INVOICE(invoice_id) ON DELETE RESTRICT,
CONSTRAINT fk_invoice_send_customer FOREIGN KEY (customer_id)
REFERENCES CUSTOMER(customer_id) ON DELETE RESTRICT
);
COMMENT ON TABLE INVOICE_SEND IS '請求書送付';
COMMENT ON COLUMN INVOICE_SEND.event_id IS 'イベントID';
COMMENT ON COLUMN INVOICE_SEND.invoice_id IS '請求書ID';
COMMENT ON COLUMN INVOICE_SEND.customer_id IS '顧客ID';
COMMENT ON COLUMN INVOICE_SEND.send_date_time IS '送付日時';
COMMENT ON COLUMN INVOICE_SEND.send_method IS '送付方法';
-- インデックス(パフォーマンス最適化)
CREATE INDEX idx_invoice_send_customer ON INVOICE_SEND(customer_id);
CREATE INDEX idx_invoice_send_invoice ON INVOICE_SEND(invoice_id);
CREATE INDEX idx_invoice_send_datetime ON INVOICE_SEND(send_date_time);
重要なポイント:
- テーブル作成順序: 外部キー参照の依存関係を考慮し、親テーブル → 子テーブルの順に作成
- インデックス: 外部キーと日時カラムには自動的にインデックスを作成
- コメント: 日本語での説明を必ず追加(保守性向上)
最終出力
ユーザーに以下を表示:
- 生成されたDDLファイルのパス (
artifacts/{project_name}/schema.sql) - テーブル数とリレーションシップ数のサマリー
- 次のステップ(Docker環境でのテスト方法など)
次フェーズへの遷移
state.yaml を更新:
current_phase: openapi_generation
completed_phases:
- entity_extraction
- classification
- relationship_analysis
- validation
- diagram_generation
- ddl_generation
Phase 7: OpenAPI生成
目的
イミュータブルデータモデルからCQRS準拠のOpenAPI 3.1.0仕様書を完全自動生成します。 ユースケース指向のAPI設計を実現し、単純なCRUD APIではなく実際のビジネスアクションに基づくエンドポイントを生成します。
ブラックボードからの入力
entities_classified.json(Phase 2で生成された分類済みエンティティ)model.json(Phase 3で生成された関連情報)usecase_detailed.md(Phase 0.5で生成、オプション)
処理内容
このフェーズは /openapi-generator スキルを使用して実行します。
OpenAPI生成の方針:
1. イベント → POST/PUT マッピング
- イベントエンティティを意味のあるアクションAPIに変換
- 命名パターンから適切なHTTPメソッドとエンドポイントを推論
- Idempotency-Key ヘッダー必須(重複イベント防止)
マッピング例:
| イベント種別 | HTTPメソッド | エンドポイント例 |
|---|---|---|
| ProjectStart | POST | /api/projects/{id}/start |
| PersonAssign | POST | /api/projects/{id}/members |
| PersonReplace | PUT | /api/projects/{id}/members/{memberId}/replace |
| RiskEvaluate | POST | /api/projects/{id}/risks |
2. リソース → GET マッピング
- リソースエンティティを取得APIに変換
- 検索、フィルタ、ページネーション対応
- 自動的にクエリパラメータを生成
CRUD エンドポイント:
GET /api/{resources}- 一覧取得(検索・フィルタ・ページング)GET /api/{resources}/{id}- 詳細取得POST /api/{resources}- 新規作成(Createイベントと連携)PATCH /api/{resources}/{id}- 部分更新DELETE /api/{resources}/{id}- 削除
3. 状態集約 → GET マッピング
- イベントから現在状態を推論するクエリAPI
- 4つのパターンを自動生成
状態集約パターン:
| パターン | エンドポイント例 | 説明 |
|---|---|---|
| Latest State | /api/projects/{id}/start/latest |
最新のイベント取得 |
| History | /api/projects/{id}/start/history |
イベント履歴(時系列) |
| Current Assignments | /api/projects/{id}/members/current |
現在の割当(置換済み除外) |
| Summary | /api/projects/{id}/risks/summary |
集約統計情報 |
4. RFC 7807 準拠エラーレスポンス
- Problem Details 形式
- 標準的なHTTPステータスコード(400, 401, 403, 404, 409, 422, 500)
- 詳細なバリデーションエラー情報
エラーレスポンス例:
{
"type": "https://api.example.com/errors/validation-error",
"title": "Validation Error",
"status": 400,
"detail": "プロジェクト名は1-200文字で入力してください",
"instance": "/api/projects",
"errors": [
{
"field": "project_name",
"message": "1-200文字で入力してください",
"value": ""
}
]
}
5. 検索・フィルタ・ページネーション
- エンティティ属性から自動的にクエリパラメータを生成
自動生成されるパラメータ:
- String属性 → 部分一致検索(
?project_name=keyword) - 外部キー属性 → 完全一致フィルタ(
?customer_id=123) - Date属性 → 範囲検索(
?planned_start_dateFrom=2024-01-01&planned_start_dateTo=2024-12-31) - ページング →
?limit=50&offset=0 - ソート →
?sort=project_nameまたは?sort=-project_name(降順)
実行方法:
/openapi-generator {project_name}
このコマンドにより、entities_classified.json と model.json を読み込み、完全なOpenAPI 3.1.0仕様書を生成します。
生成プロセス:
- エンティティ分析: リソース、イベント、ジャンクションに分類
- リソースエンドポイント生成: CRUD操作を自動生成
- イベントエンドポイント生成: アクションAPIを自動生成
- 状態集約エンドポイント生成: 4パターンのクエリAPIを自動生成
- スキーマ定義生成: 全エンティティのJSONスキーマを生成
- 共通コンポーネント追加: エラーレスポンス、パラメータ、ヘッダーを追加
- OpenAPI仕様書出力: YAML形式で出力
ブラックボードへの出力
openapi.yaml に以下の形式で書き込み:
openapi: 3.1.0
info:
title: "project-record-system API"
version: "1.0.0"
description: |
イミュータブルデータモデルに基づくRESTful API仕様書
## 設計原則
- **CQRS パターン**: Command(POST/PUT)とQuery(GET)を明確に分離
- **イベントソーシング**: 不変のイベントとして業務アクションを記録
- **Idempotency**: POST/PUTは必ずIdempotency-Keyヘッダーを使用
- **RFC 7807**: 標準化されたエラーレスポンス形式
servers:
- url: https://api.example.com
description: Production
- url: https://api-staging.example.com
description: Staging
paths:
# イベントエンドポイント(Actions)
/api/projects/{projectId}/start:
post:
summary: プロジェクトを開始する
operationId: startProject
tags:
- Projects
parameters:
- name: projectId
in: path
required: true
schema:
type: integer
- $ref: '#/components/parameters/IdempotencyKey'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectStartCommand'
responses:
'201':
description: プロジェクト開始成功
content:
application/json:
schema:
$ref: '#/components/schemas/ProjectStartResponse'
'400':
$ref: '#/components/responses/BadRequest'
'404':
$ref: '#/components/responses/NotFound'
'409':
$ref: '#/components/responses/Conflict'
security:
- BearerAuth: []
# リソースエンドポイント(CRUD)
/api/projects:
get:
summary: プロジェクト一覧を取得
operationId: listProjects
tags:
- Projects
parameters:
- name: project_name
in: query
schema:
type: string
description: プロジェクト名(部分一致)
- name: customer_id
in: query
schema:
type: integer
description: 顧客IDでフィルタ
- name: limit
in: query
schema:
type: integer
default: 50
maximum: 500
- name: offset
in: query
schema:
type: integer
default: 0
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
total:
type: integer
limit:
type: integer
offset:
type: integer
projects:
type: array
items:
$ref: '#/components/schemas/Project'
# 状態集約エンドポイント
/api/projects/{projectId}/members/current:
get:
summary: プロジェクトの現在のアサイン状況を取得
description: |
プロジェクトの現在のメンバーアサイン状況を取得します。
置換済みのアサインを除外した現在のメンバー一覧を返します。
SQL例:
```sql
SELECT pa.*, p.*
FROM PERSON_ASSIGN pa
JOIN PERSON p ON pa.person_id = p.person_id
WHERE pa.project_id = ?
AND NOT EXISTS (
SELECT 1 FROM PERSON_REPLACE pr
WHERE pr.project_id = pa.project_id
AND pr.old_person_id = pa.person_id
);
```
operationId: getProjectCurrentMembers
tags:
- Projects
- Members
parameters:
- name: projectId
in: path
required: true
schema:
type: integer
responses:
'200':
description: 成功
content:
application/json:
schema:
type: object
properties:
project_id:
type: integer
current_members:
type: array
items:
$ref: '#/components/schemas/PersonAssign'
components:
schemas:
Project:
type: object
required:
- project_id
- project_name
properties:
project_id:
type: integer
description: プロジェクトID
project_name:
type: string
maxLength: 200
description: プロジェクト名
customer_id:
type: integer
description: 顧客ID
planned_start_date:
type: string
format: date
description: 予定開始日
contract_amount:
type: number
description: 契約金額
description: プロジェクト
ProjectStartCommand:
type: object
required:
- start_date_time
- registered_by
properties:
start_date_time:
type: string
format: date-time
description: 開始日時
registered_by:
type: integer
description: 登録者のperson_id
ProblemDetails:
type: object
required:
- type
- title
- status
properties:
type:
type: string
format: uri
description: エラー種別を示すURI
title:
type: string
description: エラーの概要
status:
type: integer
description: HTTPステータスコード
detail:
type: string
description: エラーの詳細説明
instance:
type: string
format: uri
description: エラーが発生したエンドポイント
errors:
type: array
description: 詳細なバリデーションエラー
items:
type: object
properties:
field:
type: string
message:
type: string
value:
type: string
parameters:
IdempotencyKey:
name: Idempotency-Key
in: header
required: true
schema:
type: string
format: uuid
description: |
冪等性キー(重複防止用UUID)
同じIdempotency-Keyでの再送信は、元のレスポンスを返します。
これにより、ネットワーク障害時の重複イベント記録を防止します。
responses:
BadRequest:
description: バリデーションエラー
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
NotFound:
description: リソースが見つからない
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
Conflict:
description: リソースの競合
content:
application/problem+json:
schema:
$ref: '#/components/schemas/ProblemDetails'
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- BearerAuth: []
検証
生成されたOpenAPI仕様書は以下の方法で検証できます:
1. OpenAPI Validator
npm install -g @apidevtools/swagger-cli
swagger-cli validate artifacts/{project_name}/openapi.yaml
2. Swagger UI
# Swagger UIで可視化
docker run -p 8080:8080 -e SWAGGER_JSON=/openapi.yaml \
-v $(pwd)/artifacts/{project_name}/openapi.yaml:/openapi.yaml \
swaggerapi/swagger-ui
ブラウザで http://localhost:8080 にアクセスして仕様書を確認できます。
最終出力
ユーザーに以下を表示:
- 生成されたOpenAPI仕様書のパス (
artifacts/{project_name}/openapi.yaml) - エンドポイント数のサマリー(リソース、イベント、状態集約別)
- 検証方法(OpenAPI Validator、Swagger UI)
- 次のステップ(モックサーバー構築、クライアントSDK生成など)
次フェーズへの遷移
state.yaml を更新:
current_phase: completed
completed_phases:
- entity_extraction
- classification
- relationship_analysis
- validation
- diagram_generation
- ddl_generation
- openapi_generation
詳細な実装は /openapi-generator スキルを参照してください。
イミュータブルデータモデルの原則
このSkillは以下の原則に基づいてモデリングを行います:
エンティティの分類
- リソース: 時間経過で変化しうるもの(顧客、商品など)
- イベント: 特定時点で発生した事実(注文、入金など)
イベントの日時属性
- イベントエンティティには1つの日時属性のみ
- 日時はUTC形式で管理
隠れたイベントの抽出
- リソースに更新日時がある場合、イベントが隠されている可能性
- 例: 社員情報の更新日時 → 社員異動イベント
交差エンティティの導入
- 多対多の関係には交差エンティティを挿入
- 関連自体が属性を持つ場合も導入
詳細は templates/immutable-model-rules.md を参照してください。
制御ロジック(Claudeの実行手順)
ステップ1: プロジェクト名の入力
まず、ユーザーにプロジェクト名を確認します。
プロジェクト名の命名規則:
- ケバブケース(kebab-case)推奨(例:
invoice-management,inventory-system) - 英数字とハイフンのみ使用
- スペースや特殊文字は使用不可
対話例:
Claude: モデリングするプロジェクトの名前を入力してください(例: invoice-management):
User: invoice-management
既存プロジェクトの確認:
artifacts/{project_name}/が既に存在する場合は警告を表示- ユーザーに選択肢を提示:
- 既存プロジェクトを上書き(既存ファイルは削除される)
- 別の名前で新規作成
- 中断
ステップ2: ブラックボードの初期化
プロジェクト名を受け取ったら、以下を実行:
# プロジェクト名をシェル変数に設定(例)
PROJECT_NAME="invoice-management"
# ブラックボード領域を作成
mkdir -p artifacts/${PROJECT_NAME}
# 状態ファイルを初期化
cat > artifacts/${PROJECT_NAME}/state.yaml << EOF
project_name: ${PROJECT_NAME}
current_phase: entity_extraction
input_usecase: ""
completed_phases: []
EOF
ステップ3: ユースケース記述の入力
ユーザーからのユースケース記述を state.yaml の input_usecase に保存。
対話例:
Claude: ユースケースを入力してください:
User: 請求期日が到来した場合、顧客に請求書を送付する。期日までに入金がない場合には、確認状を送付する。
# ユースケースをstate.yamlに追加
# (実際には Read → Edit で更新)
ステップ4: フェーズループ
current_phase を確認し、以下のフェーズを順次実行:
entity_extraction→ Phase 1を実行classification→ Phase 2を実行relationship_analysis→ Phase 3を実行validation→ Phase 4を実行diagram_generation→ Phase 5を実行
各フェーズ完了後、state.yaml を更新して次フェーズへ。
注意: 各フェーズでは artifacts/${PROJECT_NAME}/ 内のファイルを読み書きします。
ステップ5: 最終結果の表示
artifacts/${PROJECT_NAME}/er_diagram.mmd を読み取り、ユーザーに表示。
トラブルシューティング
エンティティ抽出が不十分な場合
- ユースケースに具体的な名詞・動詞を含めてください
- 業務の流れを時系列で記述してください
イベントとリソースの分類が不適切な場合
- イベントには「〜した」「〜が発生した」という表現を使用
- リソースには「〜がある」「〜を管理する」という表現を使用
交差エンティティが不足する場合
- 多対多の関係を明示的に記述してください
- 例: 「学生は複数の講義を受講し、講義には複数の学生が参加する」
カスタマイズ方法
命名規則の変更
templates/naming-rules.md を編集して、プロジェクト固有の命名規則を適用できます。
モデリングルールの追加
templates/immutable-model-rules.md を編集して、追加のルールを定義できます。
参考資料
- イミュータブルデータモデル - Scrapbox
- LangChainとLangGraphによるRAG・AIエージェント実践入門 第12章
制約事項
- 現バージョンは日本語ユースケースのみ対応
- ER図はMermaid形式のみ出力
- DDL生成は今後のバージョンで対応予定