409 lines
No EOL
12 KiB
Markdown
409 lines
No EOL
12 KiB
Markdown
# 制作小プロジェクト - 企画設計指示書
|
||
|
||
## 1. プロジェクト概要
|
||
|
||
### 1.1 目的
|
||
リッチなマスター編集機能を持つ販売アシスタントアプリを効率的に開発するための、AI(LLM)による自動コーディングを支援する企画設計指示書。
|
||
|
||
### 1.2 スコープ
|
||
- マスターデータの CRUD 機能強化
|
||
- リッチな入力フィールド(画像/動画アップロード、QR コード生成)
|
||
- フォームバリデーションとヒント表示
|
||
- 汎用ウィジェットによるコード削減
|
||
|
||
---
|
||
|
||
## 2. コンテンツ定義
|
||
|
||
### 2.1 データモデル一覧
|
||
|
||
#### Customer(得意先)
|
||
| プロパティ | タイプ | キー | ビルンール | ヒント |
|
||
|----------|--------|------|-----------|--------|
|
||
| id | int? | PK | autoincrement | - |
|
||
| name | String | UK | not null, max 50 | 例:株式会社〇〇、個人名で可 |
|
||
| email | String | | unique, nullable, max 100 | メールアドレス形式(*@example.com)|
|
||
| phone | String | | nullable, max 20 | 電話番号(区切りなし:090-1234-5678→09012345678)|
|
||
| address | String | | nullable, max 200 | 住所(省スペース表示・多言語対応)|
|
||
| created_at | DateTime? | - | null allow | DB レコード作成時 |
|
||
|
||
#### Product(商品)
|
||
| プロパティ | タイプ | キー | ビルンール | ヒント |
|
||
|----------|--------|------|-----------|--------|
|
||
| id | int? | PK | autoincrement | - |
|
||
| name | String | UK | not null, max 50 | 例:iPhone、ノートパソコンなど |
|
||
| price | double? | - | null allow | 円単位(小数点以下 2 桁)|
|
||
| stock | int? | - | null allow | 在庫数 |
|
||
| description | String | - | nullable, max 500 | 商品の説明・特徴 |
|
||
| created_at | DateTime? | - | null allow | DB レコード作成時 |
|
||
|
||
#### Supplier(仕入先)
|
||
| プロパティ | タイプ | キー | ビルンール | ヒント |
|
||
|----------|--------|------|-----------|--------|
|
||
| id | int? | PK | autoincrement | - |
|
||
| name | String | UK | not null, max 50 | 例:株式会社〇〇、個人名で可 |
|
||
| email | String | | unique, nullable, max 100 | メールアドレス形式(*@example.com)|
|
||
| phone | String | | nullable, max 20 | 電話番号(区切りなし)|
|
||
| address | String | | nullable, max 200 | 住所 |
|
||
| created_at | DateTime? | - | null allow | DB レコード作成時 |
|
||
|
||
#### Warehouse(倉庫)
|
||
| プロパティ | タイプ | キー | ビルンール | ヒント |
|
||
|----------|--------|------|-----------|--------|
|
||
| id | int? | PK | autoincrement | - |
|
||
| name | String | UK | not null, max 50 | 例:東京都千代田区〇丁目倉庫、大阪支店倉庫 |
|
||
| address | String | | nullable, max 200 | 住所 |
|
||
| capacity | int? | - | null allow | 保管容量(単位:坪)|
|
||
| created_at | DateTime? | - | null allow | DB レコード作成時 |
|
||
|
||
#### Employee(担当者)
|
||
| プロパティ | タイプ | キー | ビルンール | ヒント |
|
||
|----------|--------|------|-----------|--------|
|
||
| id | int? | PK | autoincrement | - |
|
||
| name | String | UK | not null, max 50 | 例:田中太郎、鈴木花子 |
|
||
| email | String | | unique, nullable, max 100 | メールアドレス形式(*@example.com)|
|
||
| phone | String | | nullable, max 20 | 電話番号(区切りなし)|
|
||
| role | String | - | nullable, max 30 | 例:管理者、営業、倉庫員など |
|
||
| created_at | DateTime? | - | null allow | DB レコード作成時 |
|
||
|
||
---
|
||
|
||
## 3. UI コンポーネント定義
|
||
|
||
### 3.1 汎用ウィジェット一覧
|
||
|
||
#### RichMasterTextField(テキスト入力)
|
||
```dart
|
||
RichMasterTextField(
|
||
label: '商品名',
|
||
initialValue: 'iPhone',
|
||
hintText: '例:iPhone、ノートパソコンなど',
|
||
maxLines: 1,
|
||
)
|
||
```
|
||
|
||
#### RichMasterNumberField(数値入力)
|
||
```dart
|
||
RichMasterNumberField(
|
||
label: '価格',
|
||
initialValue: 128000.0,
|
||
hintText: '例:128,000円、98,500 円など',
|
||
decimalDigits: 2,
|
||
)
|
||
```
|
||
|
||
#### RichMasterDateField(日付選択)
|
||
```dart
|
||
RichMasterDateField(
|
||
label: '作成日',
|
||
initialValue: DateTime.now(),
|
||
hintText: '例:2024/03/10、今日などの指定可',
|
||
)
|
||
```
|
||
|
||
#### RichMasterAddressField(住所入力・省スペース)
|
||
```dart
|
||
RichMasterAddressField(
|
||
label: '住所',
|
||
initialValue: '東京都千代田区〇丁目 1-1',
|
||
hintText: '例:都道府県名から検索可',
|
||
)
|
||
```
|
||
|
||
#### RichMasterFileUploader(ファイル・画像アップロード)
|
||
```dart
|
||
RichMasterFileUploader(
|
||
label: '商品画像',
|
||
onPickImage: () => print('画像選択'),
|
||
onPickVideo: () => print('動画選択'), // Android 限定
|
||
)
|
||
```
|
||
|
||
#### RichMasterQRCodeGenerator(QR コード生成)
|
||
```dart
|
||
RichMasterQRCodeGenerator(
|
||
label: 'QR コード',
|
||
text: 'https://example.com/product/123',
|
||
)
|
||
```
|
||
|
||
#### RichMasterCheckboxField(チェックボックス)
|
||
```dart
|
||
RichMasterCheckboxField(
|
||
label: '在庫あり',
|
||
initialValue: true,
|
||
onChanged: (value) => print(value),
|
||
)
|
||
```
|
||
|
||
#### RichMasterDropdownField(ドロップダウンリスト)
|
||
```dart
|
||
RichMasterDropdownField<String>(
|
||
label: '担当部署',
|
||
initialValue: '営業部',
|
||
items: ['営業部', '総務部', '開発部'],
|
||
itemToString: (item) => item,
|
||
)
|
||
```
|
||
|
||
### 3.2 アプリバー(AppBar)定義
|
||
|
||
| ID | 名乘 |
|
||
|-----|------|
|
||
| /S1. 見積書 | Sales - Estimate |
|
||
| /S2. 請求書 | Sales - Invoice |
|
||
| /S3. 受発注一覧 | Order List |
|
||
| /S4. 売上入力(レジ) | Sales Register |
|
||
| /S5. 売上返品入力 | Return Input |
|
||
| /M1. 商品マスタ | Master - Product |
|
||
| /M2. 得意先マスタ | Master - Customer |
|
||
| /M3. 仕入先マスタ | Master - Supplier |
|
||
| /M4. 倉庫マスタ | Master - Warehouse |
|
||
| /M5. 担当者マスタ | Master - Employee |
|
||
|
||
---
|
||
|
||
## 4. ビヘイビア仕様
|
||
|
||
### 4.1 フォームバリデーション
|
||
- **必須フィールド**: 空文字の場合は赤いエラー表示 + ヒント文の再表示
|
||
- **メール形式検証**: *@example.com の形式のみ許可(正規表現:^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$)
|
||
- **電話番号検証**: 数字のみ、最大 11 桁まで許可
|
||
- **数値フィールド**: 小数点以下指定桁数を超える入力時の自動補正
|
||
|
||
### 4.2 ヒント・エラー表示
|
||
```dart
|
||
// エラー状態
|
||
TextField(
|
||
errorText: hintText, // 初期値がヒントとなる
|
||
)
|
||
|
||
// カスタムエラー
|
||
TextField(
|
||
decoration: InputDecoration(errorText: '必須入力をしてください'),
|
||
)
|
||
```
|
||
|
||
### 4.3 ショートカットキー対応(オプション)
|
||
```dart
|
||
RichMasterShortcutSettings(
|
||
label: '編集ヘルプ',
|
||
showShortcuts: true,
|
||
shortcuts: {
|
||
'Ctrl+S': () => print('保存'),
|
||
'Ctrl+Z': () => print('取り消し'),
|
||
},
|
||
)
|
||
```
|
||
|
||
### 4.4 セクション分割表示
|
||
```dart
|
||
RichMasterSectionHeader(
|
||
title: '基本情報',
|
||
icon: Icons.info_outline,
|
||
color: Colors.blue.shade700,
|
||
)
|
||
```
|
||
|
||
---
|
||
|
||
## 5. コーディングワークフロー
|
||
|
||
### 5.1 マスタ画面作成手順
|
||
|
||
#### ステップ 1: モデル定義
|
||
```dart
|
||
// lib/models/customer.dart
|
||
class Customer {
|
||
int? id;
|
||
String name = '';
|
||
String? email;
|
||
String? phone;
|
||
String? address;
|
||
DateTime? createdAt;
|
||
|
||
Customer({
|
||
this.id,
|
||
required this.name,
|
||
this.email,
|
||
this.phone,
|
||
this.address,
|
||
this.createdAt,
|
||
});
|
||
|
||
factory Customer.fromJson(Map<String, dynamic> json) => Customer(
|
||
id: json['id'] as int?,
|
||
name: json['name'] as String,
|
||
email: json['email'] as String?,
|
||
phone: json['phone'] as String?,
|
||
address: json['address'] as String?,
|
||
createdAt: json['created_at'] != null ? DateTime.parse(json['created_at']) : null,
|
||
);
|
||
|
||
Map<String, dynamic> toJson() => {
|
||
'id': id,
|
||
'name': name,
|
||
'email': email,
|
||
'phone': phone,
|
||
'address': address,
|
||
'created_at': createdAt?.toIso8601String(),
|
||
};
|
||
|
||
Customer copyWith({
|
||
int? id,
|
||
String? name,
|
||
String? email,
|
||
String? phone,
|
||
String? address,
|
||
DateTime? createdAt,
|
||
}) => Customer(
|
||
id: id ?? this.id,
|
||
name: name ?? this.name,
|
||
email: email ?? this.email,
|
||
phone: phone ?? this.phone,
|
||
address: address ?? this.address,
|
||
createdAt: createdAt ?? this.createdAt,
|
||
);
|
||
}
|
||
```
|
||
|
||
#### ステップ 2: スクリーン定義(master_edit_fields.dart を使用)
|
||
```dart
|
||
// lib/screens/master/customer_master_screen.dart
|
||
class CustomerMasterScreen extends StatefulWidget {
|
||
const CustomerMasterScreen({super.key});
|
||
|
||
@override
|
||
State<CustomerMasterScreen> createState() => _CustomerMasterScreenState();
|
||
}
|
||
|
||
class _CustomerMasterScreenState extends State<CustomerMasterScreen> {
|
||
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
|
||
|
||
// データモデル(データベース連携)
|
||
late Customer _customer;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
_customer = Customer(name: ''); // 初期値設定
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(title: Text('/M2. 得意先マスタ')),
|
||
body: Form(
|
||
key: _formKey,
|
||
child: ListView(
|
||
children: [
|
||
// RichMasterTextField(商品名)
|
||
RichMasterTextField(
|
||
label: '得意先名',
|
||
initialValue: _customer.name,
|
||
hintText: '例:株式会社〇〇、個人名で可',
|
||
onChanged: (value) => setState(() => _customer.name = value),
|
||
),
|
||
|
||
// RichMasterTextField(メール)
|
||
RichMasterTextField(
|
||
label: 'メールアドレス',
|
||
initialValue: _customer.email,
|
||
keyboardType: TextInputType.emailAddress,
|
||
hintText: '@example.com の形式(例:info@example.com)',
|
||
onChanged: (value) => setState(() => _customer.email = value),
|
||
),
|
||
|
||
// RichMasterNumberField(電話番号)
|
||
RichMasterTextField(
|
||
label: '電話番号',
|
||
initialValue: _customer.phone,
|
||
hintText: '例:090-1234-5678、区切り不要',
|
||
onChanged: (value) => setState(() => _customer.phone = value),
|
||
),
|
||
|
||
// RichMasterDateField(作成日)
|
||
RichMasterDateField(
|
||
label: '登録日',
|
||
initialValue: _customer.createdAt?.toLocal(),
|
||
hintText: '例:2024/03/10、今日などの指定可',
|
||
),
|
||
|
||
// 保存ボタン
|
||
SizedBox(
|
||
width: double.infinity,
|
||
child: ElevatedButton(
|
||
onPressed: () => Navigator.pop(context, _customer.toJson()),
|
||
child: Text('保存'),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.2 汎用マスター作成テンプレート(AI 生成用)
|
||
|
||
AI に自動生成させるためのプロンプト例:
|
||
|
||
```text
|
||
以下のデータモデルでマスター画面を作成してください:
|
||
|
||
- データモデル: {model_definition}
|
||
- スクリーン ID: {screen_id, e.g., /M3. 仕入先マスタ}
|
||
- 使用ウィジェット: RichMasterTextField, RichMasterNumberField, RichMasterDateField など(master_edit_fields.dart を参照)
|
||
|
||
要件:
|
||
1. AppBar に「{screen_id}」を表示
|
||
2. フォームキーでバリデーションを行う
|
||
3. 保存ボタンでデータを JSON 形式で返す
|
||
4. 必須フィールドは空文字をエラー扱いに
|
||
```
|
||
|
||
---
|
||
|
||
## 6. テスト用データ
|
||
|
||
### 6.1 Customer(得意先)テストデータ
|
||
```json
|
||
{
|
||
"name": "株式会社 ABC",
|
||
"email": "info@abc-company.com",
|
||
"phone": "03-1234-5678",
|
||
"address": "東京都千代田区〇丁目 1-1"
|
||
}
|
||
```
|
||
|
||
### 6.2 Product(商品)テストデータ
|
||
```json
|
||
{
|
||
"name": "iPhone 15 Pro Max",
|
||
"price": 199440.0,
|
||
"description": "チタニウム素材の高級スマートフォン。A17 Pro チップ搭載。"
|
||
}
|
||
```
|
||
|
||
### 6.3 Warehouse(倉庫)テストデータ
|
||
```json
|
||
{
|
||
"name": "東京都千代田区支店倉庫",
|
||
"address": "東京都千代田区〇丁目 1-1",
|
||
"capacity": 50
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 7. まとめ
|
||
|
||
この指示書を使用することで、以下が可能になります:
|
||
|
||
1. **AI による自動コーディング**: データモデルから画面コードを生成
|
||
2. **一貫性のある UI**: 汎用ウィジェットでデザイン統一
|
||
3. **保守性の向上**: 部品レベルでの再利用・修正
|
||
4. **開発効率化**: テンプレートベースの迅速な実装
|
||
|
||
この指示書を元に、LLM(GPT-4 など)に自動コーディングを依頼するか、自前で実装を進めてください。 |