mcpField
F
flutter-project-init

flutter-project-init

github.com/vp-k開発1443 回インストール11 週間前に更新
リポジトリ

flutter-project-init について

Clean Architecture の構成で Flutter アプリを初期化するワークフロースキルです。プロジェクトとドメインの要件を確認し、状態管理や機能プリセットを選んでコードを生成し、Flutter のツールで検証します。

主な機能

  1. 01プロジェクト名と組織情報の設定
  2. 026種類の CRUD ドメインパターン
  3. 03Riverpod または BLoC の選択
  4. 04Minimal、Essential、Full のプリセット
  5. 05コード生成と Flutter の解析

活用シーン

  1. 01要件に基づく Flutter アプリの開始
  2. 02データモデルと状態管理方式の選択
  3. 03アプリの初期構成の生成と確認

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/vp-k/flutter-craft --skill flutter-project-init

インストール後、Claude Code で/flutter-project-initを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
categorized-pattern.md
relational-pattern.md
simple-pattern.md
stateful-pattern.md
tracked-pattern.md

詳細

Flutter プロジェクトの初期化

使用する場面:「新規プロジェクト」「プロジェクトを作成」「プロジェクトを開始」「Flutter を初期化」

ワークフローの概要

Step 1: Project Info     → name, org, description
Step 2: Domain Pattern   → Simple/Stateful/Categorized/Tracked/Relational/Custom
Step 3: Tech Stack       → State Management, Features
Step 4: Generate & Verify → create, build, analyze

ステップ 1:プロジェクト情報の収集

ユーザーに次の情報を尋ねます。

項目例必須
プロジェクト名my_app (snake_case)はい
組織com.exampleはい
説明"タスク管理アプリ"はい
エンティティ名Task、Note、Expenseはい

ステップ 2:ドメインパターンの選択(CRUD ベース)

ユーザーに次の中から選んでもらいます。

パターン例生成される構成
シンプルNote、Memo、Bookmark単一エンティティの CRUD
ステートフルTodo、Task、Orderステータスフィールド(完了/進行中など)を含む
カテゴリ分類Expense、Product、Recipeカテゴリとの関連を含む
トラッキングHabit、Workout、Study時刻/日付ベースのトラッキング
リレーショナルBlog (User-Post-Comment)複数エンティティ間の関連
カスタム-ユーザー定義のフィールド
パターンごとに生成されるコード
シンプルパターン
// Entity
@freezed
sealed class Note with _$Note {
  const factory Note({
    required String id,
    required String title,
    required String content,
    required DateTime createdAt,
    DateTime? updatedAt,
  }) = _Note;
}
ステートフルパターン
// Entity with status
@freezed
sealed class Task with _$Task {
  const factory Task({
    required String id,
    required String title,
    required String description,
    @Default(TaskStatus.pending) TaskStatus status,
    required DateTime createdAt,
    DateTime? completedAt,
  }) = _Task;
}

enum TaskStatus { pending, inProgress, completed, cancelled }
カテゴリ分類パターン
// Entity with category relation
@freezed
sealed class Expense with _$Expense {
  const factory Expense({
    required String id,
    required String title,
    required double amount,
    required String categoryId,
    required DateTime date,
    String? note,
  }) = _Expense;
}

@freezed
sealed class Category with _$Category {
  const factory Category({
    required String id,
    required String name,
    required String icon,
    required String color,
  }) = _Category;
}
トラッキングパターン
// Entity with time tracking
@freezed
sealed class Habit with _$Habit {
  const factory Habit({
    required String id,
    required String name,
    required String description,
    required HabitFrequency frequency,
    required List<DateTime> completedDates,
    required int currentStreak,
    required int bestStreak,
    required DateTime createdAt,
  }) = _Habit;
}

enum HabitFrequency { daily, weekly, monthly }
リレーショナルパターン
// Multiple related entities
@freezed
sealed class User with _$User {
  const factory User({
    required String id,
    required String name,
    required String email,
    required DateTime createdAt,
  }) = _User;
}

@freezed
sealed class Post with _$Post {
  const factory Post({
    required String id,
    required String authorId,
    required String title,
    required String content,
    required DateTime createdAt,
    @Default(0) int likeCount,
  }) = _Post;
}

@freezed
sealed class Comment with _$Comment {
  const factory Comment({
    required String id,
    required String postId,
    required String authorId,
    required String content,
    required DateTime createdAt,
  }) = _Comment;
}

ステップ 3:技術スタックの選択

状態管理(必須選択)
オプション説明
Riverpod(推奨)モダンで、コンパイル時に安全性を確保し、テスト可能
BLoCイベント駆動型で、エンタープライズグレード
機能プリセット
プリセット含まれるもの
最小構成コアのみ(Freezed、Drift、DI)
基本構成+ GoRouter、Dio、エラー処理
フル構成+ 認証、ローカライズ、レスポンシブ対応
機能の詳細

前提条件: 最近の安定版 Flutter SDK(Dart >= 3.9)が必要です。古い SDK では、pub が何も生成しない壊れた -dev 版の freezed を警告なしに解決することがあります。 flutter --version で確認し、古い場合は先に flutter upgrade を実行してください。

プリセットに必要なものをすべて、1 つの flutter pub add コマンドでインストールしてください。依存関係の解決は 1 回だけ行います。インストールを順番に実行すると、依存関係の解決が行き詰まります。各回で最新の caret 制約が固定され、コード生成のパッケージ群(freezed / drift_dev / injectable_generator / riverpod_generator)は異なる analyzer メジャーバージョンに依存するため、後続のグループが先に固定された依存関係と解決不能になる場合があります。1 回で解決すれば、pub が相互に互換性のある安定版の組み合わせを選択できます。

# Full preset + Riverpod (remove what your preset doesn't need — but never
# split runtime and dev: codegen packages into separate commands).
# path_provider/path are required by app_database.dart.
# fpdart = Either for error handling (dartz is unmaintained).
flutter pub add freezed_annotation drift path_provider path get_it injectable flutter_riverpod riverpod_annotation go_router dio fpdart easy_localization responsive_framework dev:freezed dev:build_runner dev:injectable_generator dev:drift_dev dev:riverpod_generator

# Using BLoC instead of Riverpod: drop flutter_riverpod, riverpod_annotation
# and dev:riverpod_generator from the command above and run:
flutter pub add flutter_bloc

# Optional (Full preset):
flutter pub add firebase_auth

インストール後、pubspec.yaml に -dev/-beta のプレリリース版がないか確認してください。エコシステムが analyzer のメジャーバージョン間を移行する過程で、そのようなバージョンが含まれる場合があります。それ自体は致命的ではありませんが、ステップ 4.6(コード生成後の flutter analyze)による検証が必須になります。生成処理が何も生成せずに終わっていた場合は、そこで analyze が失敗します。


ステップ 4:プロジェクトの生成

4.1 Flutter プロジェクトの作成
flutter create --org <org> --project-name <name> <name>
cd <name>
4.2 フォルダー構成のセットアップ
lib/
├── core/
│   ├── constants/
│   │   └── app_constants.dart
│   ├── database/
│   │   └── app_database.dart
│   ├── di/
│   │   └── injection.dart
│   ├── errors/
│   │   ├── exceptions.dart
│   │   └── failures.dart
│   ├── router/
│   │   └── app_router.dart
│   ├── theme/
│   │   ├── app_colors.dart
│   │   └── app_theme.dart
│   └── utils/
│       └── extensions.dart
├── features/
│   └── <entity>/
│       ├── domain/
│       │   ├── entities/
│       │   │   └── <entity>.dart
│       │   ├── repositories/
│       │   │   └── <entity>_repository.dart
│       │   └── usecases/
│       │       ├── create_<entity>.dart
│       │       ├── delete_<entity>.dart
│       │       ├── get_<entity>s.dart
│       │       └── update_<entity>.dart
│       ├── data/
│       │   ├── datasources/
│       │   │   └── <entity>_local_datasource.dart
│       │   ├── models/
│       │   │   └── <entity>_model.dart
│       │   └── repositories/
│       │       └── <entity>_repository_impl.dart
│       └── presentation/
│           ├── bloc/          # or providers/
│           │   ├── <entity>_bloc.dart
│           │   ├── <entity>_event.dart
│           │   └── <entity>_state.dart
│           ├── pages/
│           │   ├── <entity>_list_page.dart
│           │   └── <entity>_detail_page.dart
│           └── widgets/
│               └── <entity>_card.dart
├── shared/
│   └── widgets/
│       └── loading_widget.dart
└── main.dart
4.3 基本ファイルの生成
core/errors/failures.dart
import 'package:freezed_annotation/freezed_annotation.dart';

part 'failures.freezed.dart';

@freezed
sealed class Failure with _$Failure {
  const factory Failure.server({required String message, int? code}) = ServerFailure;
  const factory Failure.cache({required String message}) = CacheFailure;
  const factory Failure.network({@Default('No internet connection') String message}) = NetworkFailure;
  const factory Failure.validation({required String message}) = ValidationFailure;
}
core/database/app_database.dart
import 'dart:io';
import 'package:drift/drift.dart';
import 'package:drift/native.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;

part 'app_database.g.dart';

// Tables will be added per domain pattern
@DriftDatabase(tables: [])
class AppDatabase extends _$AppDatabase {
  AppDatabase() : super(_openConnection());

  @override
  int get schemaVersion => 1;
}

LazyDatabase _openConnection() {
  return LazyDatabase(() async {
    final dbFolder = await getApplicationDocumentsDirectory();
    final file = File(p.join(dbFolder.path, 'app.db'));
    return NativeDatabase.createInBackground(file);
  });
}
core/di/injection.dart
import 'package:get_it/get_it.dart';
import 'package:injectable/injectable.dart';
import 'injection.config.dart';

final getIt = GetIt.instance;

@InjectableInit(preferRelativeImports: true)
Future<void> configureDependencies() async => getIt.init();
4.4 pubspec.yaml の更新

選択したプリセットに基づいて、必要な依存関係をすべて追加します。

4.5 コード生成の実行
flutter pub get
dart run build_runner build --delete-conflicting-outputs
4.6 検証(必須)
flutter analyze

エラー 0 件で通過する必要があります。 Info/warning レベルの問題は許容されます。

エラーがある場合:

  1. 各エラーを修正します
  2. dart run build_runner build を再実行します
  3. flutter analyze を再実行します
  4. エラーが 0 件になるまで繰り返します

ステップ 5:Git の初期化

git init
git add .
git commit -m "Initial commit: <project_name> with Clean Architecture

- Domain pattern: <selected_pattern>
- State management: <Riverpod/BLoC>
- Features: <selected_preset>

🤖 Generated with flutter-craft"

完了チェックリスト

  • 正しい名前/組織でプロジェクトを作成
  • フォルダー構成が Clean Architecture に準拠
  • Freezed でドメインエンティティを生成
  • Drift でデータベーステーブルを作成
  • injectable で DI を設定
  • flutter pub get が成功
  • dart run build_runner build が成功
  • flutter analyze のエラーが 0 件
  • Git を初期化し、初回コミットを作成

ユーザーへの出力

完了後、次の内容を伝えます。

✅ Project '<name>' created successfully!

📁 Structure: Clean Architecture
📦 Pattern: <selected_pattern>
🔄 State: <Riverpod/BLoC>
✨ Features: <preset>

Next steps:
1. cd <name>
2. flutter run
3. Use /brainstorm to plan your first feature

参考資料

パターンごとの詳細なコードテンプレートについては、以下を参照してください。

  • references/simple-pattern.md
  • references/stateful-pattern.md
  • references/categorized-pattern.md
  • references/tracked-pattern.md
  • references/relational-pattern.md

注意: Custom パターンには専用のテンプレートがありません。ユーザー定義のフィールドはご自身で設計します。

コメント