git clone https://github.com/majiayu000/claude-skill-registry
T=$(mktemp -d) && git clone --depth=1 https://github.com/majiayu000/claude-skill-registry "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/data/infer-intent" ~/.claude/skills/majiayu000-claude-skill-registry-infer-intent && rm -rf "$T"
skills/data/infer-intent/SKILL.mdcivicship-api 設計意図推論
Git履歴・コミットメッセージから設計の意図や歴史的文脈を推論します。なぜこのコードがこう書かれているのか、過去の変更理由を理解することで、安全な変更を支援します。
使用方法
# 特定ファイルの設計意図を推論 /infer-intent src/application/domain/account/wallet/service.ts # ドメイン全体の歴史を分析 /infer-intent wallet # 特定の実装パターンの理由を調査 /infer-intent "なぜWalletServiceはトランザクションを必須にしているのか"
引数:
: ファイルパス、ドメイン名、または質問$ARGUMENTS
意図推論プロセス
ステップ1: Git履歴の取得
対象ファイル・ドメインのコミット履歴を取得:
# ファイルの全履歴 git log --follow --oneline src/application/domain/account/wallet/service.ts # 詳細な変更履歴 git log -p --follow src/application/domain/account/wallet/service.ts # 特定期間のコミット git log --since="1 year ago" --oneline -- src/application/domain/account/wallet # コミット統計 git log --stat --oneline -- src/application/domain/account/wallet
履歴レポート:
## Git履歴の概要 ### 変更統計 | 項目 | 値 | |------|-----| | 総コミット数 | 45件 | | 最初のコミット | 2023-06-20 | | 最新のコミット | 2026-01-10 | | 期間 | 2年7ヶ月 | | 主要コントリビューター | 3名 | --- ### コミット頻度 | 期間 | コミット数 | |------|-----------| | 2023年 | 12件 | | 2024年 | 20件 | | 2025年 | 10件 | | 2026年 | 3件 | **トレンド:** 2024年にピーク(機能追加が活発) --- ### 主要なコミット #### 1. 初期実装(2023-06-20)
commit a1b2c3d feat: Add wallet domain with basic CRUD operations
**変更内容:** - WalletService, WalletRepository の初期実装 - 基本的なCRUD操作のみ --- #### 2. トランザクション対応(2023-08-15)
commit e4f5g6h fix: Add transaction support to wallet operations
**変更内容:** - すべてのメソッドに `tx` パラメータ追加 - トランザクション内での操作を保証 **理由(コミットメッセージから推論):** - ポイント送受信で不整合が発生したバグ修正 - トランザクションなしでは残高計算にレースコンディション --- #### 3. バリデーション強化(2024-02-10)
commit i7j8k9l feat: Add strict validation for negative balance
**変更内容:** - 残高がマイナスにならないチェック追加 **理由:** - 本番環境でマイナス残高が発生 - ビジネスルール違反を防ぐため --- #### 4. パフォーマンス最適化(2024-06-20)
commit m1n2o3p perf: Optimize wallet balance calculation with cache
**変更内容:** - 残高計算にキャッシュ導入 - クエリ回数を削減 **理由:** - ユーザー増加によりレスポンスタイム劣化 - 100ms → 30ms に改善 --- #### 5. セキュリティ修正(2025-03-15)
commit q4r5s6t security: Add RLS to all wallet queries
**変更内容:** - すべてのクエリに `ctx.issuer` を適用 **理由:** - 他ユーザーのウォレット情報が見えるバグ - セキュリティ監査で指摘
ステップ2: コミットメッセージの分析
コミットメッセージから設計判断を推論:
## コミットメッセージ分析 ### カテゴリ別の分類 | カテゴリ | 件数 | 割合 | |---------|------|------| | feat (機能追加) | 18件 | 40% | | fix (バグ修正) | 12件 | 27% | | perf (パフォーマンス) | 5件 | 11% | | security (セキュリティ) | 3件 | 7% | | refactor (リファクタリング) | 4件 | 9% | | test (テスト) | 3件 | 7% | **傾向:** 機能追加が多いが、バグ修正も頻繁 --- ### 頻出キーワード分析 | キーワード | 出現回数 | 文脈 | |-----------|---------|------| | transaction | 8回 | トランザクション対応 | | validation | 6回 | バリデーション強化 | | balance | 10回 | 残高計算ロジック | | security | 5回 | セキュリティ修正 | | performance | 4回 | パフォーマンス改善 | **解釈:** - トランザクションが重要な関心事 - 残高計算は複雑で頻繁に修正 - セキュリティ問題が過去に複数回発生 --- ### 重要な設計決定 #### 決定1: トランザクション必須化 **コミット:** e4f5g6h (2023-08-15) **メッセージ:**
fix: Add transaction support to wallet operations
ポイント送受信でレースコンディションが発生し、 残高の不整合が発生した。 今後すべてのウォレット操作はトランザクション内で 実行することを必須とする。
**推論される意図:** - データ整合性が最優先 - 並行アクセスでのレースコンディションを防ぐ - パフォーマンスよりも正確性を重視 --- #### 決定2: マイナス残高の禁止 **コミット:** i7j8k9l (2024-02-10) **メッセージ:**
feat: Add strict validation for negative balance
本番環境でマイナス残高が発生したため、 厳密なバリデーションを追加。 ポイント使用時に残高不足の場合はエラーを返す。
**推論される意図:** - ビジネスルール: ポイントは借金できない - 既存のバリデーションが不十分だった - 信頼性向上のための防御的プログラミング --- #### 決定3: キャッシュ導入 **コミット:** m1n2o3p (2024-06-20) **メッセージ:**
perf: Optimize wallet balance calculation with cache
ユーザー増加によりウォレットクエリが ボトルネックになっていた。 残高計算に10秒のキャッシュを導入し、 レスポンスタイムを100ms→30msに改善。
**推論される意図:** - スケーラビリティへの対応 - リアルタイム性よりパフォーマンスを優先(10秒は許容) - 将来的なユーザー増加を見越した設計 --- #### 決定4: RLS(Row-Level Security)の徹底 **コミット:** q4r5s6t (2025-03-15) **メッセージ:**
security: Add RLS to all wallet queries
セキュリティ監査で、一部のクエリでRLSが 適用されていないことが判明。 全てのクエリで ctx.issuer を使用するよう修正。
**推論される意図:** - セキュリティが最重要課題 - 一度でも情報漏洩があった(またはリスクがあった) - 再発防止のための徹底的な対策
ステップ3: コード変更パターンの分析
コード変更の傾向から設計思想を推論:
# ファイルパスを引数から取得 FILE_PATH="${ARGUMENTS}" # 追加された行数と削除された行数 git log --stat --oneline -- "${FILE_PATH}" | \ grep "$(basename "${FILE_PATH}")" | awk '{sum+=$4} END {print sum}' # 特定関数の変更履歴(例: createWallet関数) git log -L :createWallet:"${FILE_PATH}"
変更パターンレポート:
## コード変更パターン ### メソッド別の変更頻度 | メソッド | 変更回数 | 最終変更日 | |---------|---------|-----------| | createWallet | 8回 | 2025-01-10 | | findByUserId | 12回 | 2024-11-20 | | transferPoints | 15回 | 2025-12-05 | | calculateBalance | 10回 | 2024-06-20 | **解釈:** - `transferPoints` が最も変更が多い(複雑なロジック) - `findByUserId` も頻繁に変更(セキュリティ、パフォーマンス改善) --- ### createWallet メソッドの進化 #### Version 1(2023-06-20) ```typescript async createWallet(userId: string) { return this.repo.create({ userId, balance: 0 }); }
特徴: シンプル、トランザクションなし
Version 2(2023-08-15)
async createWallet(userId: string, tx: Prisma.TransactionClient) { return this.repo.create({ userId, balance: 0 }, tx); }
変更: トランザクション対応
Version 3(2024-02-10)
async createWallet(ctx: IContext, userId: string, tx: Prisma.TransactionClient) { // バリデーション追加 const existing = await this.repo.findByUserId(ctx, userId, tx); if (existing) { throw new Error("WALLET_ALREADY_EXISTS"); } return this.repo.create({ userId, balance: 0 }, tx); }
変更: 重複チェック追加
Version 4(現在)
async createWallet( ctx: IContext, input: GqlWalletCreateInput, communityId: string, tx: Prisma.TransactionClient ): Promise<PrismaWallet> { // バリデーション const existing = await this.repo.findByUserId(ctx, input.userId, tx); if (existing) { throw new Error("WALLET_ALREADY_EXISTS"); } // 入力変換 const data = this.converter.toCreateData(input, communityId); // 作成 return await this.repo.create(ctx, data, tx); }
変更: Clean Architecture パターンに準拠、Converter導入
推論:
- 段階的にアーキテクチャを改善
- 最初はシンプルだったが、バグを経験して厳格化
- 最終的にDDDパターンに完全準拠
--- ### ステップ4: 関連IssueとPRの調査 GitHubのIssue/PRから背景を調査: ```bash # 関連PRを検索 gh pr list --search "wallet" --state all --limit 20 # 特定PRの詳細(PR番号を引数から取得) PR_NUMBER="${ARGUMENTS}" gh pr view "$PR_NUMBER" # PRのコメントを確認 gh api repos/Hopin-inc/civicship-api/pulls/"$PR_NUMBER"/comments
Issue/PR分析:
## 関連Issue/PRの分析 ### 重要なPR #### PR #45: トランザクション対応 **タイトル:** Add transaction support to wallet operations **作成日:** 2023-08-15 **状態:** Merged **説明:**
問題
ポイント送受信で以下のバグが発生:
- ユーザーAが100ptをユーザーBに送信
- 同時にユーザーBが100ptをユーザーAに送信
- 両者のポイントが増加(残高の不整合)
原因
トランザクション管理がなく、レースコンディション
対策
すべてのウォレット操作をトランザクション内で実行
**レビューコメント:** - "トランザクションを必須にするのは良い判断" - "パフォーマンスへの影響は?" → "問題なし、10ms以下" **推論:** - 実際に本番でバグが発生していた - データ整合性を最優先する文化 - パフォーマンスよりも正確性 --- #### PR #78: セキュリティ修正 **タイトル:** Add RLS to all wallet queries **作成日:** 2025-03-15 **状態:** Merged **説明:**
問題
セキュリティ監査で指摘: ユーザーAが他ユーザーのウォレット情報を取得可能
原因
一部のクエリで ctx.issuer を使用していない
対策
全てのRepositoryメソッドでRLSを適用
**レビューコメント:** - "Critical なセキュリティバグ、即座にマージすべき" - "テストカバレッジを100%にして" **推論:** - セキュリティインシデントが発生した可能性 - 監査プロセスが機能している - セキュリティを非常に重視
ステップ5: コードレビューコメントの分析
過去のコードレビューから設計思想を推論:
# PRのレビューコメントを取得 gh api repos/Hopin-inc/civicship-api/pulls/45/reviews
レビューコメント分析:
## コードレビューから見える設計思想 ### 頻出するレビュー指摘 #### 1. トランザクション管理 **コメント例:**
このメソッドはトランザクション内で呼ばれる可能性があるので、 tx パラメータを追加してください。
**頻度:** 10回以上 **推論される原則:** - トランザクション管理は必須 - 全てのメソッドで tx を伝播すべき - データ整合性への強いこだわり --- #### 2. エラーハンドリング **コメント例:**
バリデーションエラーは Error ではなく、 ビジネス例外クラスを使ってください。
**頻度:** 5回以上 **推論される原則:** - エラーを適切に分類 - クライアントに意味のあるエラーメッセージ - デバッグしやすいコード --- #### 3. テストカバレッジ **コメント例:**
このメソッドのテストが不足しています。 エッジケースもカバーしてください。
**頻度:** 8回以上 **推論される原則:** - テストを重視 - カバレッジ目標: 90%以上 - エッジケースを見逃さない --- #### 4. パフォーマンス **コメント例:**
このクエリはN+1問題を引き起こします。 DataLoaderを使用してください。
**頻度:** 3回以上 **推論される原則:** - パフォーマンスを意識 - N+1問題は許容しない - スケーラビリティを考慮
ステップ6: チーム文化の推論
コミットメッセージ、PR、レビューから組織文化を推論:
## チーム文化の推論 ### 開発プロセス #### コードレビュー文化 - **全PRにレビュー必須** - 平均レビュー数: 2-3名 - レビュー期間: 1-2日 - マージ条件: 全レビュアーの承認 + CI通過 **推論:** - 品質を重視する文化 - チーム間のナレッジ共有 - 属人化を防ぐ仕組み --- #### テスト文化 - **テストなしのPRはマージされない** - カバレッジ目標: 90% - E2Eテストも重視 **推論:** - テスト駆動開発(TDD)に近い文化 - 品質保証を最優先 --- #### セキュリティ意識 - **セキュリティ監査を定期実施** - RLSを徹底 - センシティブデータの取り扱いに厳格 **推論:** - 金融系・個人情報を扱うプロダクト - セキュリティインシデントを経験している可能性 - コンプライアンスを重視 --- ### 技術的な価値観 #### 優先順位 1. **正確性 > パフォーマンス** - トランザクション必須化 - 厳格なバリデーション 2. **セキュリティ > 利便性** - 全クエリにRLS - 認証・認可の徹底 3. **保守性 > 開発速度** - Clean Architecture準拠 - リファクタリングを厭わない 4. **テスト > 機能追加** - 高いカバレッジ要求 - エッジケースの網羅 **推論:** - 長期的な運用を見据えた設計 - 技術的負債を許容しない文化
ステップ7: 設計パターンの推論
コードの進化から設計パターンを推論:
## 設計パターンの進化 ### パターン1: トランザクション管理 **進化:**
V1: トランザクションなし ↓ V2: 一部のメソッドにトランザクション ↓ V3: 全メソッドでトランザクション必須 ↓ V4: UseCaseでトランザクション管理、Serviceは伝播のみ
**推論される設計思想:** - レイヤー責任の明確化 - UseCaseがトランザクション境界 - Serviceはビジネスロジックのみ --- ### パターン2: エラーハンドリング **進化:**
V1: 例外をそのままthrow ↓ V2: カスタムエラークラス導入 ↓ V3: エラーコードの統一 ↓ V4: GraphQLエラーとの統合
**推論される設計思想:** - ユーザーフレンドリーなエラーメッセージ - デバッグしやすいエラー情報 - クライアント側での適切なハンドリング --- ### パターン3: データアクセス **進化:**
V1: Serviceが直接Prismaを呼ぶ ↓ V2: Repository層を導入 ↓ V3: Converter層を導入(入力変換) ↓ V4: Presenter層を導入(出力変換)
**推論される設計思想:** - Clean Architectureへの段階的移行 - 各レイヤーの責任を明確化 - テストしやすい構造
ステップ8: 技術的決定の背景推論
なぜこの技術選択をしたのかを推論:
## 技術的決定の背景 ### 決定1: Prisma ORM 採用 **推論される理由:** 1. **型安全性:** TypeScriptとの親和性 2. **マイグレーション:** スキーマ管理が容易 3. **開発効率:** 生SQLを書く必要がない 4. **コミュニティ:** 活発なエコシステム **裏付け:** - 初期コミットからPrisma使用 - マイグレーションファイルが整然と管理されている - Prisma独自の機能(RLS、トランザクション)を活用 --- ### 決定2: GraphQL 採用 **推論される理由:** 1. **柔軟性:** クライアントが必要なデータのみ取得 2. **型安全性:** スキーマ駆動開発 3. **フロントエンドとの親和性:** React/Apollo との統合 4. **N+1防止:** DataLoaderでパフォーマンス最適化 **裏付け:** - DataLoaderの積極的な活用 - GraphQL Code Generatorでの型生成 - スキーマファーストな開発プロセス --- ### 決定3: tsyringe(DI) 採用 **推論される理由:** 1. **テスタビリティ:** モック化が容易 2. **疎結合:** 依存関係の明確化 3. **保守性:** インターフェースベースの設計 4. **スケーラビリティ:** 依存関係の管理が容易 **裏付け:** - 全てのクラスで `@injectable()` を使用 - テストでのモック差し替えが一貫している - インターフェース(IXxxRepository)の徹底
ステップ9: 暗黙的な制約の発見
コードから暗黙的なビジネスルール・制約を推論:
## 暗黙的な制約 ### 制約1: 1ユーザー = 1ウォレット **コード:** ```typescript const wallet = await this.repo.findByUserId(ctx, userId, tx); // 配列ではなく単一オブジェクトを返す
推論:
- ビジネスルール: ユーザーは1つのウォレットのみ
- 将来的に複数ウォレット対応は想定外
- データモデル:
制約userId UNIQUE
制約2: ポイントは整数のみ
コード:
balance: Int // Prismaスキーマ
推論:
- ビジネスルール: 小数点以下のポイントは存在しない
- 1pt = 最小単位
- 将来的に小数対応は大きな変更
制約3: マイナス残高は許容しない
コード:
if (balance < requiredPoints) { throw new Error("INSUFFICIENT_BALANCE"); }
推論:
- ビジネスルール: 借金(マイナス残高)は不可
- 前払いシステム
- 与信機能は存在しない
制約4: ポイント送受信は同一コミュニティ内のみ
コード:
const fromWallet = await this.repo.findByCommunity(ctx, fromUserId, communityId, tx); const toWallet = await this.repo.findByCommunity(ctx, toUserId, communityId, tx);
推論:
- ビジネスルール: コミュニティをまたいだポイント移動は不可
- コミュニティごとに独立した経済圏
- 将来的にクロスコミュニティ機能は大きな変更
--- ### ステップ10: 意図推論レポートの生成 ```markdown # 設計意図推論レポート **対象:** WalletService **分析日:** 2026-01-15 --- ## エグゼクティブサマリー ### 設計の核心 **このコードは何のために存在するか:** - ポイント経済システムの中核 - データ整合性とセキュリティを最優先 - スケーラブルで保守しやすい設計 **主要な設計判断:** 1. トランザクション必須化(データ整合性) 2. RLS徹底(セキュリティ) 3. Clean Architecture準拠(保守性) 4. 厳格なバリデーション(信頼性) --- ## 歴史的文脈 ### タイムライン **2023年6月:** 初期実装 - シンプルなCRUD操作 - トランザクション未対応 **2023年8月:** レースコンディション発生 - 本番でバグ → トランザクション必須化 - データ整合性への意識向上 **2024年2月:** マイナス残高バグ - バリデーション不足 → 厳格化 - 防御的プログラミングへ **2024年6月:** スケーラビリティ問題 - ユーザー増加 → パフォーマンス最適化 - キャッシュ導入 **2025年3月:** セキュリティ監査 - RLS漏れ → 全面適用 - セキュリティ最優先へ --- ## 変更時の注意事項 ### してはいけないこと 1. **トランザクションを削除しない** - 理由: 過去にレースコンディションで不整合発生 - 正確性 > パフォーマンス 2. **RLSをスキップしない** - 理由: セキュリティ監査で指摘された過去あり - 全クエリで `ctx.issuer` 必須 3. **バリデーションを緩和しない** - 理由: マイナス残高バグの再発防止 - ビジネスルールの厳格な適用 4. **1ユーザー1ウォレットの前提を崩さない** - 理由: システム全体がこの前提で設計 - 変更は全体への影響大 --- ### 推奨される変更方法 **新機能追加時:** 1. 既存のトランザクションパターンに従う 2. テストカバレッジ 90%以上 3. セキュリティレビュー必須 **パフォーマンス改善時:** 1. 正確性を損なわない 2. キャッシュ導入は慎重に 3. ベンチマークで検証 **リファクタリング時:** 1. Clean Architecture パターンを維持 2. レイヤー責任を明確に 3. 段階的に実施 --- ## 将来の方向性 ### 予想される課題 1. **複数ウォレット対応** - 現状: 1ユーザー1ウォレット - 変更影響: システム全体 2. **クロスコミュニティ送金** - 現状: 同一コミュニティ内のみ - 変更影響: トランザクション境界の再設計 3. **小数点ポイント対応** - 現状: 整数のみ - 変更影響: 型定義、計算ロジック全体 --- ## 参考資料 - PR #45: トランザクション対応 - PR #78: セキュリティ修正 - Issue #23: マイナス残高バグ - Issue #67: パフォーマンス劣化
活用例
例1: なぜこのコードがこう書かれているか
/infer-intent "WalletServiceのtxパラメータが必須な理由"
出力:
- Git履歴からレースコンディションのバグを発見
- トランザクション必須化の背景を説明
例2: 変更してはいけない箇所の特定
/infer-intent src/application/domain/account/wallet/service.ts
出力:
- 過去のバグ修正履歴
- 変更時の注意事項
注意事項
推論の限界
- ❌ コミットメッセージが不明確な場合、推論不可
- ❌ 口頭での決定事項は把握できない
- ❌ ビジネス要件の詳細は不明
推奨される使い方
- ✅ 変更前に設計意図を理解
- ✅ 新メンバーのオンボーディング
- ✅ リファクタリング前の調査
参考資料
以下については
@CLAUDE.md を参照してください:
- アーキテクチャパターン
- トランザクション管理
- RLSの使い方