レシピ#3-4: Cursor + Claudeでデータ永続化を実装する

これまでのレシピで、アプリはメモを追加・削除できるようになりました。しかし、現状ではアプリを再起動すると、すべてのデータが消えてしまいます。 なぜなら、データはメモリ上にしか存在しないからです。

このレシピでは、Cursor + Claudeと協力して、アプリのデータをデバイス内に永続的に保存する仕組みを実装します。これにより、ユーザーはいつでも自分のデータに再アクセスできるようになります。

1. 永続化の方法を選ぶ

Flutterでデータをローカルに保存する方法はいくつかありますが、今回は以下の組み合わせを使います。 * sqflite: SQLiteデータベースをFlutterで利用するための、最も標準的で強力なパッケージ。リレーショナルデータを扱うのに適しています。 * path_provider: デバイスのファイルシステム上で、データベースファイルを保存するのに安全な場所のパスを取得するためのパッケージ。

2. データ層の設計をCursor + Claudeに依頼する

アプリのロジック(Serviceクラスなど)が、直接データベースを操作するのは良い設計ではありません。間に「データ層(Data Layer)」を設けることで、関心を分離し、テストしやすいコードになります。

このデータ層の設計と実装を、Cursor + Claudeに任せましょう。

💬 Cursor活用プロンプト (データ層の設計)

あなたは、Flutterアプリのローカルデータベース設計に詳しいエキスパートです。

sqfliteパッケージを使って、写真メモアプリのデータを永続化するための「データ層」を設計してください。

要件: 1. データベースヘルパーの作成: データベースへの接続を開き、メモを保存するためのテーブルを作成するクラス(例: DatabaseHelper)を実装してください。 - テーブル名: memos - カラム: id (TEXT, PRIMARY KEY), title (TEXT), imagePath (TEXT), createdAt (TEXT) 2. データソースの作成: DatabaseHelperを使い、メモのCRUD(作成, 読み取り, 更新, 削除)操作を行う具体的なメソッドを持つクラス(例: MemoLocalDataSource)を実装してください。 - addMemo(Memo memo) - getMemos() - deleteMemo(String id)

これらのクラスの完全なコードを、data/local_data_source.dartというファイルに記述することを想定して生成してください。

なぜこれが良いのか? * SQLの知識が不要: CREATE TABLE文やINSERT, SELECT, DELETEといった、SQLの面倒な記述をCursor + Claudeがすべて肩代わりしてくれます。 * 非同期処理の考慮: データベース操作はすべて非同期です。Cursor + Claudeは、async/awaitを正しく使ったコードを自然に生成してくれます。 * 定石パターンの適用: データベース接続をシングルトンで管理するなど、sqfliteを使う上での一般的なベストプラクティスをCursor + Claudeが適用してくれます。


3. Serviceクラスとデータ層を接続する

データ層が完成したら、次は既存のServiceクラス(MemoService)を修正し、メモリ上ではなく、データベースとデータをやり取りするように変更します。

💬 Cursor活用プロンプト (Serviceクラスの修正)

ありがとうございます。データ層のコードが完成しました。

次に、以前作成したservices/memo_service.dartMemoServiceを、この新しいデータ層と連携するように修正してください。

元のServiceクラス】 @services/memo_service.dart を参照してください。 (Claude Codeの場合は「services/memo_service.dartを読んで修正して」と依頼します)

新しいデータ層のクラス】 - MemoLocalDataSource

要件: 1. addMemoメソッドが呼ばれたら、メモリ上のリストを操作する代わりに、MemoLocalDataSource.addMemo()を呼び出し、データベースにメモを保存するように変更してください。 2. removeMemoメソッドも同様に、MemoLocalDataSource.deleteMemo()を呼び出すように変更してください。 3. アプリ起動時に、MemoLocalDataSource.getMemos()を呼び出して、データベースからすべてのメモを読み込み、状態を初期化する処理を追加してください。

修正後のMemoServiceの完全なコードを提示してください。

なぜこれが良いのか? * 差分的なリファクタリング: Cursor + Claudeに「前と後」の情報を提供することで、どこをどう変更すれば良いかを正確に理解させることができます。 * 依存性の注入: この修正プロセスを通じて、MemoServiceDataSourceに依存する形になります。これは、DI(Dependency Injection)という重要な設計パターンの実践的な学習にもなります。


4. 動作確認とデバッグ

すべての接続が完了したら、アプリを実行してみましょう。

  1. メモを追加し、一度アプリを完全に終了させます。
  2. 再度アプリを起動します。
  3. 前に追加したメモが、正しく画面に表示されていれば成功です!

もしうまく動かない場合、例えばデータベースのテーブル作成に失敗しているかもしれません。その際は、Cursor + Claudeにエラーログを渡し、デバッグの助けを求めましょう。

💬 Cursor活用プロンプト (デバッグ支援)

sqfliteを導入しましたが、アプリ起動時に以下のエラーが発生します。

(ここにエラーログを貼り付ける)

関連するコードは @data/local_data_source.dart と @services/memo_service.dart を参照してください。 (Claude Codeの場合は「local_data_source.dartmemo_service.dartを読んで調査して」と依頼します)

原因と解決策を教えてください。

Cursor + Claudeと協力することで、複雑に見えるデータベース操作も、一つ一つのステップに分解し、着実に実装していくことができます。