diff --git a/CLAUDE.md b/CLAUDE.md index 3518627..36f6766 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,7 +9,19 @@ ## 必須ルール(コード実装時) - +### コーディング規約(GUIDE_05 準拠) + +- Effective Dart に準拠.プロジェクト固有ルールは GUIDE_05 を参照 +- `dart format` + `dart analyze` を必ず実行してからコミットする +- 1 ファイル 1 クラス.命名は Provider / Service / Screen の接尾辞ルールに従う +- エラー処理: Service → Provider → Screen の順で伝播し,画面でユーザーに通知 + +### コミット前チェック(GUIDE_07 準拠) + +1. `dart analyze` — 警告・エラー 0 件 +2. `dart format .` — 差分なし +3. `flutter test` — 全テスト通過 +4. ドキュメント更新(仕様変更がある場合) ### Git 運用(GUIDE_04 準拠) @@ -36,7 +48,9 @@ - ドキュメント作成規約: docs/01_GUIDE/GUIDE_02_ドキュメント作成ガイド.md - ファイル命名規則: docs/01_GUIDE/GUIDE_03_ファイル命名規則.md - Git 運用ルール: docs/01_GUIDE/GUIDE_04_Git運用ルール.md -- ※ コーディング規約,テスト方針等はプロジェクト立ち上げ時に作成する(GUIDE_01 参照) +- コーディング規約: docs/01_GUIDE/GUIDE_05_コーディング規約.md +- テスト方針: docs/01_GUIDE/GUIDE_06_テスト方針.md +- 実装完了フロー: docs/01_GUIDE/GUIDE_07_実装完了フロー.md ### 02_ENV(環境) diff --git "a/docs/01_GUIDE/GUIDE_05_\343\202\263\343\203\274\343\203\207\343\202\243\343\203\263\343\202\260\350\246\217\347\264\204.md" "b/docs/01_GUIDE/GUIDE_05_\343\202\263\343\203\274\343\203\207\343\202\243\343\203\263\343\202\260\350\246\217\347\264\204.md" new file mode 100644 index 0000000..47a2c96 --- /dev/null +++ "b/docs/01_GUIDE/GUIDE_05_\343\202\263\343\203\274\343\203\207\343\202\243\343\203\263\343\202\260\350\246\217\347\264\204.md" @@ -0,0 +1,125 @@ +# コーディング規約 (Coding Standards) + +本ドキュメントでは,MiniTIAS プロジェクトの Dart / Flutter コーディング規約を定義する. +基本方針として [Effective Dart](https://dart.dev/effective-dart) に準拠し,プロジェクト固有のルールのみ本書で定める. + +## フォーマット (Formatting) + +- `dart format` のデフォルト設定に従う(行幅 80 文字) +- VS Code の「保存時フォーマット」を有効にする(`.vscode/settings.json` で設定済み) +- 手動でのフォーマット調整は行わない + +## 命名規則 (Naming Conventions) + +Effective Dart の命名規則に従う.プロジェクト固有の補足は以下の通り. + +| 対象 | 規則 | 例 | +| --- | --- | --- | +| ファイル名 | snake_case | `camera_provider.dart` | +| クラス名 | UpperCamelCase | `CameraProvider` | +| 変数・関数 | lowerCamelCase | `takePhoto()` | +| 定数 | lowerCamelCase | `defaultImageQuality` | +| プライベート | 先頭に `_` | `_controller` | +| Provider | `〇〇Provider` | `CameraProvider` | +| Service | `〇〇Service` | `FileService` | +| Screen(画面) | `〇〇Screen` | `CaptureScreen` | +| Widget(部品) | 機能を表す名前 | `ShutterButton` | + +## import 順序 (Import Order) + +以下の順序で記述し,各グループ間は空行で区切る. + +```dart +// 1. Dart SDK +import 'dart:async'; +import 'dart:io'; + +// 2. Flutter SDK +import 'package:flutter/material.dart'; + +// 3. 外部パッケージ(pub.dev) +import 'package:camera/camera.dart'; +import 'package:provider/provider.dart'; + +// 4. プロジェクト内 +import 'package:mini_tias/providers/camera_provider.dart'; +import 'package:mini_tias/services/file_service.dart'; +``` + +※ `dart fix --apply` および `dart format` で自動整列されるため,手動調整は不要. + +## ディレクトリ構造 (Directory Structure) + +[SPEC_01_画面機能仕様書](../04_SPEC/SPEC_01_画面機能仕様書.md) のアーキテクチャセクションで定義したディレクトリ構成に従う. + +```text +lib/ +├── main.dart # エントリポイント,Provider 登録 +├── app.dart # MaterialApp,テーマ +├── providers/ # 状態管理(ChangeNotifier) +├── screens/ # 画面(Scaffold 単位) +├── widgets/ # 再利用可能な UI 部品 +└── services/ # 外部リソースとの橋渡し +``` + +### 配置ルール + +- **1 ファイル 1 クラス** を原則とする.ファイル名はクラス名の snake_case 版 +- **screens/**: 各画面に対応する 1 ファイル.画面固有のロジックは対応する Provider に置く +- **widgets/**: 複数画面で再利用する UI 部品,または画面ファイルが大きくなった場合に切り出す部品 +- **providers/**: 画面または機能ごとに 1 ファイル.ChangeNotifier を継承する +- **services/**: プラットフォーム API やファイルシステムへのアクセスを担う + +## 型の使い方 (Type Usage) + +- ローカル変数は型推論(`var` / `final`)を活用する +- 関数の引数・戻り値には明示的に型を記述する +- `dynamic` は避け,`Object?` を使用する +- `final` をデフォルトとし,再代入が必要な場合のみ `var` を使用する + +## エラーハンドリング (Error Handling) + +### 基本方針 + +- **Service 層**: 例外をキャッチし,呼び出し元に結果を返す.想定外の例外はそのまま上位に伝播させる +- **Provider 層**: Service の結果を受け取り,状態(エラーメッセージ等)として保持する +- **Screen 層**: Provider の状態を参照し,ユーザーにフィードバックを表示する(スナックバー等) + +### 想定するエラー + +| エラー | 発生箇所 | 対処 | +| --- | --- | --- | +| カメラ初期化失敗 | CameraProvider | エラーメッセージを画面に表示 | +| パーミッション拒否 | PermissionService | 設定画面への誘導を表示 | +| ストレージ書き込み失敗 | FileService | スナックバーでエラー通知 | +| ファイル削除失敗 | FileService | スナックバーでエラー通知 | + +### ログ出力 + +- 開発中は `debugPrint()` を使用する(リリースビルドでは自動的に無効化される) +- `print()` は使用しない + +## ドキュメント (Documentation) + +### コード内コメント + +- **DartDoc コメント(`///`)**: 公開 API(public なクラス・メソッド)に記述する +- **実装コメント(`//`)**: ロジックが自明でない箇所にのみ記述する +- 「何をしているか」ではなく「なぜそうしているか」を書く + +### DartDoc の書き方 + +```dart +/// 撮影画像を PNG 形式で共有ストレージに保存する. +/// +/// [imageBytes] は JPEG エンコード済みの画像データ. +/// 保存先は `Pictures/MiniTIAS/` ディレクトリ. +/// 同秒の重複ファイルが存在する場合は連番サフィックスを付与する. +Future saveImage(Uint8List imageBytes) async { + // ... +} +``` + +- 1 行目は動詞で始める簡潔な要約(句点で終わる) +- 詳細が必要な場合は空行を挟んで続ける +- パラメータの説明は `[paramName]` 記法を使用する diff --git "a/docs/01_GUIDE/GUIDE_06_\343\203\206\343\202\271\343\203\210\346\226\271\351\207\235.md" "b/docs/01_GUIDE/GUIDE_06_\343\203\206\343\202\271\343\203\210\346\226\271\351\207\235.md" new file mode 100644 index 0000000..ba62567 --- /dev/null +++ "b/docs/01_GUIDE/GUIDE_06_\343\203\206\343\202\271\343\203\210\346\226\271\351\207\235.md" @@ -0,0 +1,92 @@ +# テスト方針 (Testing Strategy) + +本ドキュメントでは,MiniTIAS プロジェクトのテスト方針を定義する. + +## 基本方針 (Principles) + +- 初期フェーズではカメラ・ストレージ等のハードウェア依存が大きいため,**実機での手動確認を主体** とする +- ハードウェアに依存しないロジック(ファイル命名,重複回避等)には **Unit テスト** を書く +- テストは `flutter test` で実行できる状態を維持する + +## テストの種類と対象 (Test Types) + +| 種類 | 対象 | 実施方法 | +| --- | --- | --- | +| Unit テスト | Service 層のロジック(ファイル命名,重複回避等) | `flutter test` | +| Widget テスト | 画面の基本的な UI 構成(ボタンの存在等) | `flutter test` | +| 手動確認 | カメラプレビュー,撮影,保存,削除の E2E 動作 | 実機(AQUOS sense3) | + +※ Integration テスト(`flutter drive`)は初期フェーズでは導入しない. + +## Unit テスト + +### 対象 + +- `FileService` — ファイル名生成ロジック,重複回避ロジック +- `PermissionService` — パーミッション状態の判定ロジック(モック使用) + +### ファイル配置 + +```text +test/ +├── services/ +│ ├── file_service_test.dart +│ └── permission_service_test.dart +└── providers/ + └── gallery_provider_test.dart +``` + +### 命名規則 + +- テストファイル名: `{対象ファイル名}_test.dart` +- テストグループ: `group('クラス名',)` でクラス単位にまとめる +- テスト名: 日本語で「〜の場合,〜する」形式 + +```dart +group('FileService', () { + test('同秒のファイルが存在しない場合,サフィックスなしのファイル名を返す', () { + // ... + }); + + test('同秒のファイルが存在する場合,連番サフィックスを付与する', () { + // ... + }); +}); +``` + +## Widget テスト + +### 対象 + +- 画面に必要な UI 要素が存在すること(シャッターボタン,ナビゲーションバー等) +- ボタンタップ時に Provider のメソッドが呼ばれること(モック使用) + +### 方針 + +- カメラプレビューはモック化する(`camera` パッケージのウィジェットは Widget テストで動作しない) +- Provider は `ChangeNotifierProvider.value` でモックを注入する + +## 手動確認 (Manual Testing) + +### 確認項目 + +実装完了時に以下を実機で確認する. + +- [ ] カメラプレビューが正しく表示される(180° 回転) +- [ ] シャッターボタンで撮影できる +- [ ] 撮影画像が `Pictures/MiniTIAS/` に PNG で保存される +- [ ] ファイル名が命名規則に従っている +- [ ] 連続撮影が正常に動作する +- [ ] 一覧画面にサムネイルが表示される +- [ ] サムネイルタップで拡大表示される +- [ ] 画像の削除ができる +- [ ] パーミッション拒否時に適切なメッセージが表示される +- [ ] アプリをバックグラウンド→復帰してもカメラが正常に動作する + +## テスト実行タイミング (When to Test) + +| タイミング | 実施内容 | +| --- | --- | +| 機能実装完了時 | 対応する Unit / Widget テストを作成・実行 | +| コミット前 | `flutter test` を実行し全テストが通ることを確認 | +| PR 作成前 | 手動確認項目のうち関連するものを実機で確認 | diff --git "a/docs/01_GUIDE/GUIDE_07_\345\256\237\350\243\205\345\256\214\344\272\206\343\203\225\343\203\255\343\203\274.md" "b/docs/01_GUIDE/GUIDE_07_\345\256\237\350\243\205\345\256\214\344\272\206\343\203\225\343\203\255\343\203\274.md" new file mode 100644 index 0000000..3642189 --- /dev/null +++ "b/docs/01_GUIDE/GUIDE_07_\345\256\237\350\243\205\345\256\214\344\272\206\343\203\225\343\203\255\343\203\274.md" @@ -0,0 +1,79 @@ +# 実装完了フロー (Implementation Completion Flow) + +本ドキュメントでは,機能実装の完了からコミット・PR 作成までの手順を定義する. +リファクタリングの判断基準もここで定める. + +## コミット前チェックリスト (Pre-commit Checklist) + +機能実装が完了したら,以下を順番に実施する. + +### 1. 静的解析 + +```bash +dart analyze +``` + +- 警告・エラーが 0 件であることを確認する +- `// ignore:` で抑制する場合は理由をコメントに記述する + +### 2. フォーマット + +```bash +dart format . +``` + +- 差分がないことを確認する(VS Code の保存時フォーマットが有効なら通常は差分なし) + +### 3. テスト実行 + +```bash +flutter test +``` + +- 全テストが通ることを確認する +- 新しいロジックを追加した場合はテストも追加する([GUIDE_06](GUIDE_06_テスト方針.md) 参照) + +### 4. ドキュメント確認 + +- 仕様変更がある場合は `docs/` のドキュメントを先に更新する +- 新しいファイルを追加した場合は CLAUDE.md の参照パスを更新する + +### 5. コミット・PR + +- [GUIDE_04](GUIDE_04_Git運用ルール.md) に従ってコミット・push・PR 作成を行う + +## 実装完了の基準 (Definition of Done) + +以下をすべて満たした場合に「実装完了」とする. + +- [ ] 要求された機能が動作する +- [ ] `dart analyze` で警告・エラーが 0 件 +- [ ] `dart format` で差分がない +- [ ] `flutter test` で全テストが通る +- [ ] 新しいロジックに対するテストが追加されている +- [ ] 関連ドキュメントが更新されている + +## リファクタリング方針 (Refactoring Policy) + +### 実施タイミング + +- **機能実装中**: 実装対象のコードに限り,必要に応じてリファクタリングする +- **機能実装後**: 動作確認が完了してからリファクタリングを行う(動くコードを壊さない) +- **独立した作業として**: 機能追加と同じコミットに混ぜない.`[clean]` タグで別コミットにする + +### 判断基準 + +以下のいずれかに該当する場合にリファクタリングを検討する. + +| 基準 | 例 | +| --- | --- | +| 同じコードが 3 箇所以上に重複している | 共通ロジックのメソッド抽出 | +| 1 ファイルが 300 行を超えている | クラスやウィジェットの分割 | +| 1 メソッドが 50 行を超えている | メソッドの分割 | +| クラスの責務が 2 つ以上混在している | クラスの分割 | + +### やらないこと + +- 動作に問題のないコードの「予防的」リファクタリング +- 将来の要件を見越した過度な抽象化 +- 機能追加と同一コミットでのリファクタリング