アーキテクチャガードスキル
プロジェクト構造規約
Next.js App Router構成(推奨)
code
src/
├── app/ # ルーティング(App Router)
│ ├── (auth)/ # 認証が必要なルートグループ
│ │ ├── dashboard/
│ │ └── settings/
│ ├── (public)/ # 公開ルートグループ
│ │ ├── login/
│ │ └── register/
│ ├── api/ # API Routes
│ │ └── users/
│ │ └── route.ts
│ ├── layout.tsx # ルートレイアウト
│ └── page.tsx # トップページ
├── components/
│ ├── ui/ # 汎用UI(Button, Input等)
│ ├── features/ # 機能別コンポーネント
│ │ └── auth/
│ │ ├── LoginForm.tsx
│ │ └── index.ts
│ └── layouts/ # レイアウトコンポーネント
├── lib/ # ユーティリティ、設定、クライアント
│ ├── utils.ts
│ ├── prisma.ts
│ └── auth.ts
├── hooks/ # カスタムフック
│ └── useAuth.ts
├── services/ # APIクライアント、外部サービス連携
│ └── userService.ts
├── types/ # 型定義
│ └── user.ts
├── constants/ # 定数
│ └── routes.ts
└── styles/ # グローバルスタイル
└── globals.css
依存関係ルール(レイヤードアーキテクチャ)
依存の方向(上から下のみ許可)
code
app/ ↓ components/ ↓ hooks/ ↓ services/ ↓ lib/ ↓ types/ & constants/
禁止される依存パターン
bash
# 1. components/ → app/ への逆依存 grep -rn "from ['\"]@/app" src/components/ --include="*.ts" --include="*.tsx" # 2. services/ → components/ への逆依存 grep -rn "from ['\"]@/components" src/services/ --include="*.ts" # 3. lib/ → services/ への逆依存 grep -rn "from ['\"]@/services" src/lib/ --include="*.ts" # 4. hooks/ → components/ への逆依存 grep -rn "from ['\"]@/components" src/hooks/ --include="*.ts"
コンポーネント設計規約
Container/Presentationalパターン
code
features/
└── user-profile/
├── UserProfileContainer.tsx # データ取得、状態管理
├── UserProfileView.tsx # 純粋なUI(props only)
├── useUserProfile.ts # カスタムフック
├── types.ts # 型定義
└── index.ts # 公開API(re-export)
index.ts の書き方
typescript
// features/user-profile/index.ts
export { UserProfileContainer as UserProfile } from './UserProfileContainer';
export type { UserProfileProps } from './types';
禁止パターン
1. UIコンポーネント内でのAPI呼び出し
typescript
// ❌ Bad: UIコンポーネント内でfetch
export function UserCard({ userId }: Props) {
const [user, setUser] = useState(null);
useEffect(() => {
fetch(`/api/users/${userId}`).then(/* ... */);
}, [userId]);
return <div>{user?.name}</div>;
}
// ✅ Good: カスタムフックに分離
export function UserCard({ userId }: Props) {
const { user, isLoading } = useUser(userId);
return <div>{user?.name}</div>;
}
2. 巨大ファイル(300行超)
bash
# 検出コマンド
find src -name "*.tsx" -o -name "*.ts" | xargs wc -l | awk '$1 > 300 {print}'
3. 循環依存
bash
# 検出コマンド npx madge --circular src/
4. 未使用エクスポート
bash
# 検出コマンド npx ts-prune
5. 深いインポートパス
typescript
// ❌ Bad: 深い相対パス
import { Button } from '../../../components/ui/Button';
// ✅ Good: エイリアス使用
import { Button } from '@/components/ui/Button';
新機能追加時のガイドライン
Q: 新しいページを追加する場合
A: src/app/ 配下に配置
- •認証が必要:
src/app/(auth)/[page-name]/page.tsx - •公開ページ:
src/app/(public)/[page-name]/page.tsx
Q: 新しいコンポーネントを追加する場合
A: 用途に応じて配置
- •汎用UI:
src/components/ui/[ComponentName].tsx - •機能固有:
src/components/features/[feature-name]/ - •レイアウト:
src/components/layouts/[LayoutName].tsx
Q: 新しいAPIを追加する場合
A: src/app/api/ 配下に配置
- •REST規約に従う:
src/app/api/[resource]/route.ts - •動的パラメータ:
src/app/api/[resource]/[id]/route.ts
Q: 新しいフックを追加する場合
A: src/hooks/ に配置
- •命名:
use[PascalCase].ts - •例:
useAuth.ts,useLocalStorage.ts
Q: 新しい型定義を追加する場合
A: src/types/ に配置
- •ドメインごとにファイル分割:
user.ts,product.ts - •共通型:
common.ts
違反検出コマンド集
bash
# 全チェック実行
echo "=== 依存関係チェック ==="
grep -rn "from ['\"]@/app" src/components/ --include="*.ts" --include="*.tsx" || echo "OK: components → app 違反なし"
grep -rn "from ['\"]@/components" src/services/ --include="*.ts" || echo "OK: services → components 違反なし"
echo "=== ファイルサイズチェック ==="
find src -name "*.tsx" -o -name "*.ts" | xargs wc -l | awk '$1 > 300 {print "WARNING:", $2, "is", $1, "lines"}'
echo "=== 循環依存チェック ==="
npx madge --circular src/ 2>/dev/null || echo "madgeが未インストール"
echo "=== 未使用エクスポートチェック ==="
npx ts-prune 2>/dev/null | head -20 || echo "ts-pruneが未インストール"
出力フォーマット
markdown
## アーキテクチャ監査結果 ### ✅ 準拠項目 - ディレクトリ構造: OK - レイヤー依存関係: OK - ファイルサイズ: OK ### ❌ 違反項目 | ファイル | 違反タイプ | 詳細 | 修正案 | |---------|-----------|------|--------| | UserProfile.tsx | サイズ超過 | 450行 | Container/View分割 | | api.ts → Button | 逆依存 | services→components | インターフェース抽出 | | A → B → A | 循環依存 | 相互参照 | 共通モジュール抽出 | ### 📝 推奨アクション 1. UserProfile.tsx を分割(優先度: 高) 2. 循環依存を解消(優先度: 高) 3. 未使用エクスポートを削除(優先度: 中)
リファクタリングパターン
巨大ファイルの分割
typescript
// Before: 1ファイル400行 // UserProfile.tsx (400行) // After: 3ファイルに分割 // UserProfileContainer.tsx (80行) - データ取得 // UserProfileView.tsx (150行) - UI // useUserProfile.ts (50行) - ロジック // types.ts (20行) - 型定義
循環依存の解消
typescript
// Before: A → B → A の循環 // moduleA.ts imports from moduleB.ts // moduleB.ts imports from moduleA.ts // After: 共通モジュール抽出 // common.ts (共通の型・関数) // moduleA.ts imports from common.ts // moduleB.ts imports from common.ts