diff --git a/CLAUDE.md b/CLAUDE.md index e4b036d..312a691 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -39,6 +39,8 @@ describe('PokemonCard', () => { 機能単位でモジュールを分離し、`index.ts`(バレルファイル)で公開APIを定義する。 モジュール内ファイルへの直接importはESLintで禁止され、必ずバレル経由でアクセスする。 +設計判断の詳細は [ADR(Architecture Decision Records)](docs/adr/) を参照。 + ### ディレクトリ構成 ``` diff --git a/README.md b/README.md index 24ccb94..32ae0cf 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ GitHub Issues #1〜#5 に定義された各ステップに沿って、AI と協 | 言語 | TypeScript (strict mode) | | ルーティング | Expo Router (file-based routing) | | 国際化 | i18next / react-i18next / expo-localization | -| 状態管理 | React Context + AsyncStorage | +| 状態管理 | zustand | | テスト | Jest / @testing-library/react-native | | パッケージ管理 | pnpm | | 外部 API | [PokeAPI](https://pokeapi.co/)(REST + GraphQL) | @@ -84,7 +84,7 @@ src/ ├── splash/ # スプラッシュアニメーション └── shared/ # モジュール横断の共有コード ├── components/ # PokemonCard, FavoriteButton - ├── contexts/ # FavoritesContext + ├── stores/ # useFavoritesStore (zustand) ├── domain/ # 型定義, タイプカラー ├── i18n/ # 国際化設定, 翻訳ファイル └── repository/ # PokeAPI クライアント @@ -92,7 +92,7 @@ src/ __tests__/ # テスト(src の構造をミラー) ``` -各モジュールは `index.ts`(バレルファイル)で公開 API を定義し、モジュール内部への直接アクセスは ESLint で禁止しています。詳細は [CLAUDE.md](./CLAUDE.md) を参照してください。 +各モジュールは `index.ts`(バレルファイル)で公開 API を定義し、モジュール内部への直接アクセスは ESLint で禁止しています。設計判断の詳細は [ADR](./docs/adr/) を、開発ルールは [CLAUDE.md](./CLAUDE.md) を参照してください。 --- diff --git a/docs/adr/0000-adr-template.md b/docs/adr/0000-adr-template.md new file mode 100644 index 0000000..af7b7f6 --- /dev/null +++ b/docs/adr/0000-adr-template.md @@ -0,0 +1,33 @@ +# [短いタイトル] + +- ステータス: [Proposed | Accepted | Deprecated | Superseded by ADR-NNNN] +- 決定日: YYYY-MM-DD +- 決定者: [チーム名 or 個人] + +## コンテキスト + +この決定が必要になった背景・課題を記述する。 + +## 検討した選択肢 + +1. **選択肢1** — 概要 +2. **選択肢2** — 概要 +3. **選択肢3** — 概要 + +## 決定 + +選択した内容とその理由を記述する。 + +## 結果 + +### ポジティブな影響 + +- 良い影響を記述 + +### ネガティブな影響 + +- トレードオフや制約を記述 + +## 参考 + +- 関連リンクや関連ADRを記載 diff --git a/docs/adr/0001-modular-monolith.md b/docs/adr/0001-modular-monolith.md new file mode 100644 index 0000000..30de9e9 --- /dev/null +++ b/docs/adr/0001-modular-monolith.md @@ -0,0 +1,58 @@ +# モジュラーモノリスアーキテクチャの採用 + +- ステータス: Accepted +- 決定日: 2026-04-15 +- 決定者: プロジェクトチーム + +## コンテキスト + +ポケモン図鑑アプリを段階的に構築する中で、機能が増えるにつれてコードの整理方法を決める必要があった。画面数やデータソースが増えても保守性を維持できるアーキテクチャが求められた。 + +## 検討した選択肢 + +1. **フラットなディレクトリ構成** — `components/`, `screens/`, `hooks/` を機能横断で配置する従来型の構成 +2. **モジュラーモノリス** — 機能単位で `src//` にコードを分離し、バレルファイルで公開APIを制御する +3. **monorepo** — 各機能を独立したパッケージとして分離する + +## 決定 + +**モジュラーモノリス**を採用する。 + +- 機能単位でモジュールを分離: `home`, `detail`, `favorites`, `settings`, `splash` +- 各モジュールは `index.ts`(バレルファイル)で公開APIのみを定義する +- モジュール内は `components/`, `screens/`, `hooks/`, `domain/`, `repository/` で役割分担する +- 2つ以上のモジュールが使う共通コードは `src/shared/` に配置する +- `app/` ディレクトリはExpo Routerのルーティング定義のみに限定する +- ESLint `no-restricted-imports` でモジュール境界を強制する + +```javascript +// eslint.config.js +patterns: [{ + group: [ + "@/src/home/*", "@/src/home/*/**", + "@/src/detail/*", "@/src/detail/*/**", + // ...各モジュール + ], + message: "モジュール内ファイルへの直接アクセスは禁止です。index.ts経由でimportしてください。", +}] +``` + +## 結果 + +### ポジティブな影響 + +- モジュール間の依存関係が明確になり、意図しない結合を防げる +- バレルファイルにより公開APIが一目で分かる +- 新機能追加時にモジュールを追加するだけでスケールできる +- ESLintによる自動チェックで規約違反を防止できる + +### ネガティブな影響 + +- モジュール追加時にESLint設定も更新する必要がある +- バレルファイルの管理コストが発生する +- 小規模な機能でもモジュールとして分離するオーバーヘッドがある + +## 参考 + +- [ADR-0009: コーディング規約](0009-coding-conventions.md) — ESLintによるモジュール境界の強制 +- `eslint.config.js` — 実際のESLint設定 diff --git a/docs/adr/0002-tech-stack.md b/docs/adr/0002-tech-stack.md new file mode 100644 index 0000000..f2b3529 --- /dev/null +++ b/docs/adr/0002-tech-stack.md @@ -0,0 +1,54 @@ +# 技術スタックの選定 + +- ステータス: Accepted +- 決定日: 2026-04-15 +- 決定者: プロジェクトチーム + +## コンテキスト + +React Native学習プロジェクトとして、モダンかつ安定した技術基盤を選定する必要があった。Expoのマネージドワークフローを活用しつつ、最新のReact Native機能(New Architecture)を取り入れたい。 + +## 検討した選択肢 + +1. **Expo(マネージドワークフロー)** — Expoが提供するビルド・設定の自動管理を活用 +2. **React Native CLI(ベアワークフロー)** — ネイティブコードを直接管理 +3. **他のクロスプラットフォームフレームワーク** — Flutter、Kotlin Multiplatformなど + +## 決定 + +**Expo マネージドワークフロー**を採用し、以下の技術スタックを選定した。 + +| カテゴリ | 選定技術 | バージョン | +|---------|---------|-----------| +| フレームワーク | Expo + React Native + React | 55 / 0.83 / 19.2 | +| 言語 | TypeScript (strict mode) | 5.9 | +| ルーティング | Expo Router | ファイルベース | +| パッケージ管理 | pnpm | 10.33.0 | +| ランタイム | Node.js | 24 | + +主な設定: +- `tsconfig.json`: `"strict": true` で型安全性を強制 +- `package.json`: `"packageManager": "pnpm@10.33.0"` でpnpmバージョンを固定 +- パスエイリアス `@/*` で絶対インポートを使用 +- `app.json`: `"newArchEnabled": true` でNew Architecture有効化、`"typedRoutes": true` で型安全ルーティング + +## 結果 + +### ポジティブな影響 + +- Expoによりネイティブビルド設定の複雑さを回避できる +- TypeScript strict modeにより型安全性が保証される +- pnpmによる高速なパッケージインストールとディスク効率 +- Expo Routerのファイルベースルーティングにより直感的な画面管理 + +### ネガティブな影響 + +- Expoがサポートしないネイティブモジュールは使用できない +- pnpmのhoisted設定(`.npmrc`)が必要でExpo互換性のための妥協がある +- New Architecture対応のライブラリに限定される + +## 参考 + +- `tsconfig.json` — TypeScript設定 +- `package.json` — 依存関係とスクリプト定義 +- `app.json` — Expo設定 diff --git a/docs/adr/0003-tdd-bdd.md b/docs/adr/0003-tdd-bdd.md new file mode 100644 index 0000000..074359f --- /dev/null +++ b/docs/adr/0003-tdd-bdd.md @@ -0,0 +1,65 @@ +# TDD/BDD開発手法の採用 + +- ステータス: Accepted +- 決定日: 2026-04-15 +- 決定者: プロジェクトチーム + +## コンテキスト + +AI-DLCプロジェクトとして、品質保証と学習効果を両立する開発手法が必要だった。AIとの協働開発においても一貫した品質を維持できる仕組みが求められた。 + +## 検討した選択肢 + +1. **TDD/BDD** — テストを先に書き、振る舞いを日本語で定義してから実装する +2. **実装後テスト** — 機能実装後にテストを追加する従来型の手法 +3. **E2Eテスト中心** — Detoxなどを用いたEnd-to-Endテスト主体の品質保証 + +## 決定 + +**TDD/BDD**を採用する。 + +- **Red-Green-Refactor**サイクルを徹底する + 1. Red — テストを先に書く(期待する振る舞いを定義) + 2. Green — テストが通る最小限の実装を書く + 3. Refactor — コードを整理する(テストが通ることを確認しながら) +- **BDDスタイル**: `describe` で機能名、`it` で日本語の振る舞いを記述 +- テストフレームワーク: Jest + jest-expo + @testing-library/react-native +- テスト配置: `__tests__/` ディレクトリに `src/` のミラー構造(`app/` にはテスト禁止) +- カバレッジ閾値: branches / functions / lines / statements 全て **80%以上** + +```javascript +// jest.config.js +coverageThreshold: { + global: { + branches: 80, + functions: 80, + lines: 80, + statements: 80, + }, +} +``` + +カバレッジ計測の除外対象: +- `src/**/*.d.ts` — 型定義ファイル +- `src/**/*Samples*` — サンプルコード +- `src/**/screens/**` — 画面コンポーネント(UI統合テストの境界) +- `src/**/index.ts` — バレルファイル(再エクスポートのみ) + +## 結果 + +### ポジティブな影響 + +- テストが仕様書として機能し、振る舞いが日本語で明確に記述される +- 80%のカバレッジ閾値によりリグレッションリスクが低減される +- AIとの協働でもテストファーストにより意図の齟齬を早期に検出できる + +### ネガティブな影響 + +- 実装前にテストを書くため、初期の開発速度はやや低下する +- 画面コンポーネント(screens)のテストが除外されており、UI統合テストの補完が必要 + +## 参考 + +- [ADR-0008: CI/CDパイプライン](0008-ci-cd-pipeline.md) — テスト自動実行との連携 +- `jest.config.js` — Jest設定 +- `jest.setup.js` — モック定義 diff --git a/docs/adr/0004-rest-graphql-api.md b/docs/adr/0004-rest-graphql-api.md new file mode 100644 index 0000000..fc6a1f9 --- /dev/null +++ b/docs/adr/0004-rest-graphql-api.md @@ -0,0 +1,47 @@ +# REST + GraphQL API併用戦略 + +- ステータス: Accepted +- 決定日: 2026-04-15 +- 決定者: プロジェクトチーム + +## コンテキスト + +PokeAPIはREST API(`pokeapi.co/api/v2/`)とGraphQL API(`beta.pokeapi.co/graphql/v1beta`)の両方を提供している。ポケモン名の多言語対応が必要な一覧画面と、詳細情報を取得する画面で、最適なAPIの選択が必要だった。 + +## 検討した選択肢 + +1. **REST APIのみ** — 全てのデータ取得をREST APIで行う +2. **GraphQL APIのみ** — 全てのデータ取得をGraphQL APIで行う +3. **REST + GraphQL併用** — 用途に応じて使い分ける + +## 決定 + +**REST + GraphQL併用**を採用する。 + +- **GraphQL**: `home` モジュールのポケモン一覧取得に使用。1回のクエリで多言語名(`pokemon_v2_pokemonspeciesnames`)を含む一覧データを取得できる +- **REST**: `detail`, `shared` モジュールの単体ポケモン詳細取得に使用。シンプルなエンドポイントで十分な場面ではRESTを選択 +- **GraphQLクライアントライブラリは不使用**: 素の `fetch` でPOSTリクエストを送信(Apollo等の依存を回避) +- **Repositoryパターン**: 各APIアクセスをrepositoryとしてカプセル化し、ドメイン層から直接APIを呼ばない + +GraphQLの使用は `home` モジュールに限定し、他モジュールではREST APIを使用する。 + +## 結果 + +### ポジティブな影響 + +- 多言語対応の一覧取得がGraphQLの1クエリで完結する(REST APIだとN+1問題が発生する) +- シンプルな詳細取得ではREST APIの手軽さを活かせる +- GraphQLクライアントライブラリ不使用により依存が最小限 +- Repositoryパターンにより、API実装の詳細がドメイン層から隠蔽される + +### ネガティブな影響 + +- 2種類のAPIアクセスパターンが混在するため、コードの一貫性がやや低下する +- GraphQL APIはbeta版であり、安定性のリスクがある +- GraphQLクライアントライブラリ不使用のため、キャッシュ管理は自前で行う必要がある + +## 参考 + +- [ADR-0005: 国際化(i18n)戦略](0005-i18n-strategy.md) — GraphQLによる多言語データ取得との連携 +- `src/home/repository/pokemonGraphqlApi.ts` — GraphQL実装 +- `src/shared/repository/pokemonApi.ts` — REST API実装 diff --git a/docs/adr/0005-i18n-strategy.md b/docs/adr/0005-i18n-strategy.md new file mode 100644 index 0000000..8d64a93 --- /dev/null +++ b/docs/adr/0005-i18n-strategy.md @@ -0,0 +1,46 @@ +# 国際化(i18n)戦略 + +- ステータス: Accepted +- 決定日: 2026-04-15 +- 決定者: プロジェクトチーム + +## コンテキスト + +ポケモン図鑑アプリとして、UIラベルとポケモン名の両方を日本語・英語で表示する必要があった。UIラベルの翻訳とAPIから取得するポケモン名の多言語対応を統一的に扱う仕組みが必要だった。 + +## 検討した選択肢 + +1. **i18next + react-i18next** — React向けの実績豊富な国際化ライブラリ +2. **expo-localization + 自前実装** — Expoの組み込み機能と自前のリソース管理 +3. **react-intl** — FormatJS系の国際化ライブラリ + +## 決定 + +**i18next + react-i18next**を採用する。 + +- 対応言語: `ja`(日本語)、`en`(英語) +- 翻訳リソース: `src/shared/i18n/locales/ja.json`, `en.json` に配置 +- 言語設定の永続化: `@react-native-async-storage/async-storage` でデバイスに保存 +- デフォルト言語: `ja` +- UIラベル翻訳: i18nextのリソースファイルで管理 +- ポケモン名の多言語対応: GraphQL APIの `pokemon_v2_pokemonspeciesnames` で取得(ADR-0004参照) +- 言語切り替え: `useLanguage` カスタムフックで管理(i18n変更 + AsyncStorage保存を同時に行う) + +## 結果 + +### ポジティブな影響 + +- i18nextの豊富なエコシステムと実績による安定性 +- `useTranslation` フックによるReactコンポーネントとの自然な統合 +- AsyncStorageによりアプリ再起動後も言語設定が保持される +- UIラベルとポケモン名の多言語対応が別々の仕組みで適切に分離されている + +### ネガティブな影響 + +- i18next + react-i18nextの2パッケージが追加依存となる +- ポケモン名の翻訳がi18nextのリソースではなくAPIから取得されるため、2系統の翻訳管理が必要 + +## 参考 + +- [ADR-0004: REST + GraphQL API併用戦略](0004-rest-graphql-api.md) — GraphQLによるポケモン名の多言語取得 +- `src/shared/i18n/` — i18n設定と翻訳リソース diff --git a/docs/adr/0006-state-management.md b/docs/adr/0006-state-management.md new file mode 100644 index 0000000..774a479 --- /dev/null +++ b/docs/adr/0006-state-management.md @@ -0,0 +1,45 @@ +# 状態管理戦略 + +- ステータス: Accepted +- 決定日: 2026-04-15 +- 決定者: プロジェクトチーム + +## コンテキスト + +お気に入り機能など、複数画面で共有する状態の管理方法を決める必要があった。ポケモンの手持ちを模した「最大6件」という制約付きのお気に入りリストを、一覧画面・詳細画面・お気に入り画面の3画面で同期する必要がある。 + +当初はReact Context APIで実装していたが、Provider不要化とボイラープレート削減のためzustandへ移行した。 + +## 検討した選択肢 + +1. **React Context API** — React組み込みのContext + Providerパターン +2. **zustand** — 軽量なグローバル状態管理ライブラリ +3. **Redux Toolkit** — Flux系の状態管理ライブラリ + +## 決定 + +**zustand**を採用する。 + +- `useFavoritesStore`(`create()` で生成)でお気に入り状態をグローバル管理 +- お気に入り上限: 6件(`MAX_FAVORITES = 6`、ポケモンの手持ち数に由来) +- `useFavorites` カスタムフックで `isFavorite` / `isFull` の派生状態を提供 +- Providerが不要なため、`app/_layout.tsx` のネストが削減された +- 現在の実装ではメモリ内のみ(AsyncStorageによる永続化は未実装) + +## 結果 + +### ポジティブな影響 + +- Providerが不要でコンポーネントツリーがシンプル +- zustandのセレクタにより、必要な状態のみを購読し再レンダリングを最小化できる +- ボイラープレートが少なく、`create()` 1つでストアを定義できる +- `useFavorites` フックにより消費側のAPIがシンプル + +### ネガティブな影響 + +- zustandへの外部依存が追加される +- 現在はメモリ内のみのため、アプリ再起動でお気に入りが消失する + +## 参考 + +- `src/shared/stores/useFavoritesStore.ts` — zustandによる状態管理実装 diff --git a/docs/adr/0007-ui-styling.md b/docs/adr/0007-ui-styling.md new file mode 100644 index 0000000..f984387 --- /dev/null +++ b/docs/adr/0007-ui-styling.md @@ -0,0 +1,42 @@ +# UIスタイリング方針 + +- ステータス: Accepted +- 決定日: 2026-04-15 +- 決定者: プロジェクトチーム + +## コンテキスト + +React Nativeアプリのスタイリング手法を選定する必要があった。学習プロジェクトとしてReact Nativeの基本を理解しつつ、パフォーマンスとアニメーション表現力を確保したい。 + +## 検討した選択肢 + +1. **React Native StyleSheet** — React Native標準の `StyleSheet.create` を使用 +2. **styled-components / Emotion** — CSS-in-JSライブラリ +3. **NativeWind (Tailwind CSS)** — Tailwind CSSをReact Nativeで使用 + +## 決定 + +**React Native標準の `StyleSheet.create` のみ**を使用する。 + +- CSS-in-JSライブラリやTailwind CSS系ライブラリは使用しない +- アニメーション: `lottie-react-native` でリッチなアニメーション(お気に入りボタン等)、`react-native-reanimated` でネイティブ駆動のアニメーション +- ジェスチャー: `react-native-gesture-handler` でタッチ操作を管理 +- ポケモンタイプ別の色定義は `src/shared/domain/typeColors.ts` にドメイン知識として管理 + +## 結果 + +### ポジティブな影響 + +- 外部依存なしでReact Nativeの標準スタイリングを学習できる +- ビルド時に最適化されるためパフォーマンスが良好 +- Lottie + Reanimatedによりリッチなアニメーション表現が可能 + +### ネガティブな影響 + +- StyleSheetは冗長になりやすく、コンポーネント間でのスタイル共有が手間 +- テーマ管理(ダークモード等)の仕組みを自前で構築する必要がある + +## 参考 + +- `src/shared/domain/typeColors.ts` — ポケモンタイプ色定義 +- `src/shared/components/` — 共有UIコンポーネント実装例 diff --git a/docs/adr/0008-ci-cd-pipeline.md b/docs/adr/0008-ci-cd-pipeline.md new file mode 100644 index 0000000..be960d6 --- /dev/null +++ b/docs/adr/0008-ci-cd-pipeline.md @@ -0,0 +1,53 @@ +# CI/CDパイプライン + +- ステータス: Accepted +- 決定日: 2026-04-15 +- 決定者: プロジェクトチーム + +## コンテキスト + +PRごとの品質確認を自動化し、カバレッジの可視化によりコード品質を継続的に監視する仕組みが必要だった。 + +## 検討した選択肢 + +1. **GitHub Actions** — GitHubネイティブのCI/CDサービス +2. **CircleCI** — クラウド型CI/CDサービス +3. **Bitrise** — モバイルアプリ向けCI/CDサービス + +## 決定 + +**GitHub Actions**を採用し、以下のワークフローを構築した。 + +### テストカバレッジワークフロー(`test-coverage.yml`) + +- **トリガー**: PR作成・更新時(全ブランチ対象) +- **ランタイム**: Ubuntu + Node.js 22 + pnpm +- **ステップ**: + 1. `pnpm install --frozen-lockfile` で依存をインストール + 2. `pnpm test:coverage` でテスト実行 + カバレッジ生成 + 3. カバレッジレポート(LCOV形式)をGitHub Pagesにデプロイ(`pr/<番号>/` パスで管理) + 4. PRコメントにカバレッジサマリーを自動投稿(`jest-coverage-comment` アクション) + 5. 既存コメントがあれば更新、なければ新規作成 + +### カバレッジレポートのクリーンアップ + +- マージ済みPRのレポートを定期的に削除するワークフローを用意 + +## 結果 + +### ポジティブな影響 + +- PRごとにカバレッジが自動的に可視化され、品質低下を早期に検出できる +- GitHub Pagesへのデプロイにより、詳細なカバレッジレポートをブラウザで閲覧可能 +- PRコメントによりレビュー時にカバレッジを即座に確認できる + +### ネガティブな影響 + +- GitHub Pagesにカバレッジレポートが蓄積されるためクリーンアップが必要 +- CI実行時間がテスト数に比例して増加する + +## 参考 + +- [ADR-0003: TDD/BDD開発手法の採用](0003-tdd-bdd.md) — テスト戦略との連携 +- `.github/workflows/test-coverage.yml` — ワークフロー定義 +- `.github/workflows/cleanup-coverage.yml` — クリーンアップワークフロー diff --git a/docs/adr/0009-coding-conventions.md b/docs/adr/0009-coding-conventions.md new file mode 100644 index 0000000..578263e --- /dev/null +++ b/docs/adr/0009-coding-conventions.md @@ -0,0 +1,71 @@ +# コーディング規約 + +- ステータス: Accepted +- 決定日: 2026-04-15 +- 決定者: プロジェクトチーム + +## コンテキスト + +AIとの協働開発において、一貫したコード品質とコミット履歴を維持するための規約が必要だった。プロジェクトに参加する開発者(人間・AI問わず)が同じルールに従えるよう、明確な規約を定義する必要があった。 + +## 検討した選択肢 + +1. **Conventional Commits + ESLint** — コミットメッセージ規約とリンターの組み合わせ +2. **独自規約** — プロジェクト固有のルールを定義 +3. **規約なし** — 各開発者の裁量に任せる + +## 決定 + +**Conventional Commits + ESLint**ベースの規約を採用する。 + +### コミットメッセージ + +Conventional Commits形式を使用: +- `feat:` — 新機能 +- `fix:` — バグ修正 +- `test:` — テスト追加・修正 +- `refactor:` — リファクタリング +- `chore:` — ビルド・依存関係更新 +- `docs:` — ドキュメント + +### ブランチ命名規則 + +`/` 形式: +- 例: `feat/pokemon-list-screen`, `fix/type-badge-color`, `chore/update-dependencies` + +### TypeScript + +- strict mode必須(`tsconfig.json` で `"strict": true`) +- 型の省略禁止 + +### ESLint + +- `eslint-config-expo` をベースに使用(FlatConfig形式) +- `no-restricted-imports` でモジュール境界を強制(ADR-0001参照) + +### 検証コマンド + +`pnpm validate` で lint + typecheck + test を一括実行: +```bash +pnpm validate # = pnpm lint && pnpm typecheck && pnpm test +``` + +## 結果 + +### ポジティブな影響 + +- コミット履歴が構造化され、変更の種類が一目で分かる +- ブランチ名から作業内容を推測できる +- `pnpm validate` で全チェックを一括実行でき、PRの品質を保証できる +- AIとの協働でも同じ規約に従うことで一貫性が保たれる + +### ネガティブな影響 + +- 規約を覚えるための初期学習コストがある +- コミットメッセージのprefixが制約となり、柔軟な記述がしにくい場合がある + +## 参考 + +- [ADR-0001: モジュラーモノリスアーキテクチャの採用](0001-modular-monolith.md) — ESLintによるモジュール境界の強制 +- `eslint.config.js` — ESLint設定 +- `CLAUDE.md` — 開発ルールの詳細