Skip to content

feat(restock): Create the ReStock App #566

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
1 change: 1 addition & 0 deletions .cspell/framework-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ altool
appbar
appbundle
APPL
Bitcode
Checkmark
COCOAPODS
codecov
Expand Down
3 changes: 2 additions & 1 deletion .cspell/organization-words.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Organization Specific Words
3537BAHE48
Aimiee
altfire
altive
Expand All @@ -7,4 +8,4 @@ muramatsu
naipaka
riscait
ryunosuke
ssid
ssid
1 change: 1 addition & 0 deletions .cspell/project-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pascalcase
prefs
recase
remoteconfig
rollingstock
subloc
todos
wholename
146 changes: 146 additions & 0 deletions .cursor/rules/flutter.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
---
description: Flutterアプリアーキテクチャ
globs: *
alwaysApply: true
---
# Flutter

このドキュメントでは、現在のプロジェクト構造とアーキテクチャパターンについて説明します。
Flutterのベストプラクティスを適用しながら一貫性を維持するために、これらのガイドラインに従ってください。

Flutter SDK version: [version](mdc:.fvm/version)

## アーキテクチャ概要

- Feature first architectureと状態管理
- Hooksベースのウィジェット構成
- ローカル永続化のためのSharedPreferences
- バックエンドサービスとしてのFirebase
- altive_lintsによる静的解析 [analysis_options.yaml](mdc:analysis_options.yaml)

## ディレクトリ構造

```
lib/
environment/
features/ // 機能モジュール
feature_name/ // 個別機能ディレクトリ
providers/ // 機能固有のプロバイダー
widgets/ // 機能固有のウィジェット
{feature}_page.dart // メインページ
constants/ // アプリ全体の定数
extensions/ // 拡張メソッド
gen/ // 自動生成コード
i18n // 国際化
pacakge_adaptor/ // パッケージの仲介役
pages/ // ページ(画面)を基準としたUIを格納
router/ //
util/ // ドメイン(ビジネスロジック)に依存しない関数
widgets/ // 共通ウィジェット
test/ // テストファイル格納
```

## 状態管理ガイドライン

1. @riverpodアノテーションを使用したRiverpodを使用
2. riverpod_generatorに適切なNotifierクラスの決定を任せる
3. 適切なローカルストレージを使用する:
- 簡単な設定やフラグにはSharedPreferences
- 複雑なユーザーデータやコンテンツにはSembast
4. 適切な状態の不変性パターンに従う
5. 適切なプロバイダーのスコープを使用
6. コードが静的解析を通過することを確認:
- pedantic_monoのリントルールに従う
- すべての解析警告を修正
- 適切なNull安全パターンを使用
- 必要なドキュメントコメントを追加

## ウィジェットガイドライン

1. ステートフルウィジェットにはHookConsumerWidgetを使用
2. adaptive_dialogで適切なエラーハンドリングを実装
3. 適切なウィジェット構成を使用
4. Material 3デザイン原則に従う
5. 適切な読み込み状態を実装
6. go_routerを使用したルーティング

## プロバイダーガイドライン

1. プロバイダーをfeature/providersディレクトリに配置
2. 適切なプロバイダーの依存関係を使用
3. 適切なエラーハンドリングを実装
4. 適切なキャッシュ戦略に従う
5. 適切なプロバイダーのスコープを使用
6. 単一責任の原則に従う:
- 1つのプロバイダーは1つの特定の状態を管理すべき
- 状態の変更は単一の真実のソースによって処理されるべき
- ビジネスロジックは焦点を絞り、一貫性を持たせる

## 機能の構成

1. 機能ごとに最初に整理
2. 機能を独立させる
3. coreを通じて共通コードを共有
4. 一貫した命名パターンに従う
5. 適切なルーティングを実装
6. DRY原則に従う:
- 共通ウィジェットをcore/widgetsに抽出
- core/providersを通じて共通プロバイダーを共有
- 繰り返しコードパターンには拡張機能を使用
- 共通操作にはユーティリティ関数を作成

## テストガイドライン

1. オフラインユニットテストを作成:
- 依存関係のモック化にはmockitoを使用
- ネットワークとデータベースの依存関係を最小化
- ビジネスロジックを分離してテストに集中
2. 複雑なUIにはウィジェットテストを実装
3. 適切なモック戦略を使用
4. 適切なテスト命名規則に従う

## パフォーマンスガイドライン

1. 適切な画像キャッシュを実装
2. UGC(ユーザー生成コンテンツ)のリストビューを最適化:
- 遅延読み込みにはListView.builderを使用
- 大規模データセット用のページネーションを実装
- リストアイテムを適切にキャッシュ
- 読み込みとエラー状態を処理
- 適切なスクロールパフォーマンス最適化を使用
3. 適切な状態管理パターンに従う
4. 適切なメモリ管理を実装
5. 適切な広告読み込み戦略を使用

## 命名ガイドライン

1. 一貫したケーシングに従う:
- ディレクトリ名:snake_case
- ファイル名:snake_case
- クラス名:UpperCamelCase
- 変数名:camelCase
- 定数名:camelCase

2. 画面とコンポーネントの命名:
- ページ:NounPage(例:ArticlePage、ArticlesPage)
- コンポーネント:NounComponentType(例:ArticleTile、ArticleCard)
- 一般的なWidgetサフィックスを避ける(例:ArticleWidget)

3. データクラスの命名:
- 基本:Noun(例:Article)
- 修飾:AdjectiveNounまたはNounNoun(例:LatestArticle、PrivateArticle)

4. データソース層の命名:
- APIクライアント:NounClient(例:GitHubClient)
- リポジトリ:NounRepository(例:ArticleRepository)
- データソース:NounDataSource(例:ArticleDataSource)

5. 一般原則:
- エンティティには名詞または形容詞を使用
- アクションには動詞を使用
- 命名には複数形を考慮
- 名前は明確で説明的に保つ

## その他

- `Color.withOpacity` is deprecated and shouldn't be used. Use .withValues()
211 changes: 211 additions & 0 deletions .cursor/rules/riverpod.mdc
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
---
description: Riverpod実装ガイドライン
globs: *.dart, *.yaml
alwaysApply: true
---
# Riverpod実装ガイドライン

## 1. プロバイダーの種類とその使用方法

### 1.1 永続的プロバイダー(`@Riverpod(keepAlive: true)`)

以下の場合に使用する:

- アプリケーション全体で共有されるグローバル状態
- リポジトリクラス
- 認証状態
- システム設定
- キャッシュされたデータ

```dart
@Riverpod(keepAlive: true)
class AuthRepository extends _$AuthRepository {
@override
Future<User?> build() async {
// 実装
}
}
```

### 1.2 一時的プロバイダー(`@riverpod`)

以下の場合に使用する:

- 画面固有の状態管理
- 一時的なデータ保持
- UI状態制御
- フォーム入力管理

```dart
@riverpod
class ThemeModeController extends _$ThemeModeController {
@override
ThemeMode build() {
// 実装
}
}
```

## 2. 命名規則

### 2.1 プロバイダークラス

- Controller:状態変更を伴うプロバイダー
- Repository:データアクセスを担当するプロバイダー
- State:単純な状態を保持するプロバイダー

### 2.2 メソッド名

- build():初期状態の構築
- setState():状態の更新
- update():データの更新
- create():新規作成
- delete():削除

## 3. 状態管理パターン

### 3.1 非同期データ管理

```dart
@riverpod
class DataController extends _$DataController {
@override
Future<Data?> build() async {
// 非同期データを取得
}

Future<void> update() async {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => // 更新処理);
}
}
```

### 3.2 ローカルストレージ統合

```dart
@riverpod
class StorageController extends _$StorageController {
@override
Data build() {
final value = ref.watch(sharedPreferencesProvider).getString(key);
return // 変換処理
}

void save(Data data) {
state = data;
ref.read(sharedPreferencesProvider).setString(key, // 保存処理);
}
}
```

## 4. エラー処理

### 4.1 基本パターン

```dart
try {
state = const AsyncValue.loading();
state = await AsyncValue.guard(() => // 処理);
} on Exception catch (e) {
state = AsyncValue.error(e, StackTrace.current);
}
```

### 4.2 カスタム例外

```dart
if (condition) {
throw AppException('エラーメッセージ');
}
```

## 5. キャッシュ制御

### 5.1 キャッシュの無効化

```dart
// 関連するプロバイダーを無効化
ref.invalidate(relatedProvider);

// 複数のプロバイダーの一括無効化
ref
..invalidate(providerA)
..invalidate(providerB);
```

### 5.2 キャッシュの更新

```dart
// 既存のキャッシュを更新
state = state.whenData((data) => data.copyWith(// 更新内容));
```

## 6. ベストプラクティス

### 6.1 依存性注入

- プロバイダー間の依存関係を明示的に定義する
- 循環参照を避ける
- 適切なスコープを設定する

### 6.2 テスト可能性

- モック可能な設計
- 副作用の分離
- 明確な依存関係

### 6.3 パフォーマンス最適化

- 不要な再構築を避ける
- 適切なキャッシング戦略
- メモリリークの防止

### 6.4 ref.watchとref.readの使い分け

- プロバイダーとウィジェットのbuildメソッドでは、依存関係を適切に追跡するために常に`ref.watch`を使用する
- `ref.watch`は、監視されているプロバイダーの状態が変化したときにウィジェット/プロバイダーが再構築されることを保証する
- `ref.read`は、再構築をトリガーすべきではないイベントハンドラーやメソッドでのみ使用する
- buildメソッドで`ref.read`を誤って使用すると、古いデータや更新の見逃しにつながる可能性がある

```dart
// 良い例:buildでref.watchを使用
@override
Widget build(BuildContext context, WidgetRef ref) {
final user = ref.watch(userProvider);
return Text(user.name);
}

// 良い例:プロバイダーのbuildでref.watchを使用
@override
String build() {
final settings = ref.watch(settingsProvider);
return settings.theme;
}

// 良い例:イベントハンドラーでref.readを使用
void onButtonPressed() {
ref.read(counterProvider.notifier).increment();
}
```

## 7. コード生成

### 7.1 セットアップ

```yaml
dependencies:
riverpod_annotation: latest

dev_dependencies:
riverpod_generator: latest
build_runner: latest
```

### 7.2 生成コマンド

```bash
flutter pub run build_runner build
# または
flutter pub run build_runner watch
```
Loading