ponshu-room-lite/docs/archive/FINAL_REQUIREMENTS.md

924 lines
23 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 新生ぽんるーむ - 最終完全要件定義書
**プロジェクト名**: 新生ぽんるーむ (Reborn Ponshu Room)
**バージョン**: 2.0 - "My Digital Sake Cellar"
**作成日**: 2025-12-29
**設計**: Claude (Anthropic) + Gemini (Google AI) + posimai
**実装担当**: Antigravity + Claude
---
## 🎯 プロジェクトビジョン
> **「目の前の一本を撮るだけで、魔法のようにデータが溜まっていく」**
### 3つの核心コンセプト
#### 🍶 1. 「瞬撮」- 魔法の解析体験
カメラを向けて撮るだけで、AIが全てを読み取る。
ユーザーはただ「撮る」だけ。
#### 🎨 2. 「美録」- インスタ映えする情報の見せ方
雑誌のようなレイアウトで、いつでも見返したくなる。
そのままインスタに投稿できる美しさ。
#### 🧩 3. 「遊び心」- 意味のあるデータ分析
自分の好みを「発見」する楽しさ。
日本全国制覇マップ、フレーバーマトリックス。
---
## 📱 技術スタック
### 必須要件
```yaml
Flutter SDK: 3.38.3+
Dart: 3.10.1+
Android:
compileSdk: 36
targetSdk: 35 (Android 15対応)
minSdk: 21 (Android 5.0+)
```
### 依存パッケージ
```yaml
dependencies:
flutter:
sdk: flutter
# 状態管理Riverpod - スキャンアプリで実績あり)
flutter_riverpod: ^2.6.1
hooks_riverpod: ^2.6.1
flutter_hooks: ^0.20.5
# ローカルDB
hive: ^2.2.3
hive_flutter: ^1.1.0
# AI解析Gemini 3.0
google_generative_ai: ^0.4.7
http: ^1.6.0
# カメラ・画像
camera: ^0.11.0+2
image_picker: ^1.2.1
image: ^4.3.0
# UI
google_fonts: ^6.2.1
fl_chart: ^1.1.1
# 共有・保存
share_plus: ^12.0.1
path_provider: ^2.1.5
# その他
intl: ^0.20.2
package_info_plus: ^9.0.0
url_launcher: ^6.3.2
countries_world_map: ^1.3.0
cupertino_icons: ^1.0.8
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^6.0.0
hive_generator: ^2.0.1
build_runner: ^2.4.13
```
---
## 🎨 UI/UXデザイン原則
### デザインコンセプト
**「雑誌のような洗練、魔法のような心地よさ」**
### カラーパレット
```dart
// posimaiブランドカラー
static const Color posimaiBlue = Color(0xFF376495);
// ベースカラー
static const Color warmOffWhite = Color(0xFFFAFAF9); // 背景
static const Color richBlack = Color(0xFF1A1A1A); // テキスト
static const Color charcoalGray = Color(0xFF4A4A4A); // サブテキスト
static const Color warmGray = Color(0xFF8A8A8A); // 補助テキスト
// アクセントカラー
static const Color dustyPink = Color(0xFFE8B4B8); // お気に入り
static const Color softYellow = Color(0xFFFEF3C7); // ウィッシュリスト
```
### タイポグラフィ
```dart
// 銘柄名・タイトル: 明朝体(格調高く)
headlineMedium: GoogleFonts.notoSerifJp(
fontSize: 20,
fontWeight: FontWeight.w600,
letterSpacing: 0.5,
color: richBlack,
)
// データ・ボディ: ゴシック体(読みやすく)
bodyMedium: GoogleFonts.notoSansJp(
fontSize: 13,
fontWeight: FontWeight.w400,
color: charcoalGray,
)
// ラベル・キャプション: ゴシック体
bodySmall: GoogleFonts.notoSansJp(
fontSize: 11,
fontWeight: FontWeight.w500,
color: warmGray,
)
```
---
## 🍶 1. 「瞬撮」- 魔法の解析体験
### APIキー設定
```dart
// lib/secrets.dart
class Secrets {
static const String geminiApiKey = 'AIzaSyA2BSr16R2k0bHjSYcSUdmLoY8PKwaFts0';
}
```
### Gemini 3.0統合
**重要**: 以下のいずれかを使用
```dart
// オプション1: 最新の3.0プレビュー(推奨)
model: 'gemini-3.0-flash-latest'
// オプション2: 安定版2.5 Flashスキャンアプリで実績
model: 'gemini-2.5-flash-latest'
```
### AIソムリエのリアルタイム実況
**解析中のUI**:
```dart
class AnalyzingOverlay extends StatelessWidget {
final String currentStage;
const AnalyzingOverlay({required this.currentStage});
@override
Widget build(BuildContext context) {
return Container(
color: Colors.black.withOpacity(0.7),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation(posimaiBlue),
),
SizedBox(height: 24),
Text(
currentStage,
style: GoogleFonts.notoSansJp(
fontSize: 16,
color: Colors.white,
),
),
],
),
),
);
}
}
```
**ステージの例**:
```dart
[
'ラベルを読んでいます...',
'お、これは〇〇県の銘柄ですね...',
'精米歩合を確認中...',
'データを整理しています...',
]
```
### 自動ポエム生成
Geminiのレスポンスに以下を追加:
```dart
final prompt = '''
この画像は日本酒のボトルまたはラベルの写真です。
ラベルに書かれているテキスト情報を正確に読み取り、JSON形式で返してください。
【重要な指示】
1. ラベルに明確に書かれている情報のみを抽出してください
2. 推測や想像で値を入れないでください読めない場合はnullまたは省略
3. 数値は必ず数字のみ(単位記号%などは除く)
4. このお酒の印象を一言で表す「キャッチコピー」を自動生成してください
【出力フォーマット】
{
"brandName": "銘柄名",
"type": "特定名称",
"alcoholContent": 数値,
"polishingRatio": 数値,
"breweryName": "酒蔵名",
"prefecture": "都道府県名",
"catchCopy": "夜風と楽しみたい、淡麗な一滴" // ← 自動生成
}
**JSON以外の余計な説明は一切不要です。JSONのみを出力してください。**
''';
```
---
## 🎨 2. 「美録」- インスタ映えする情報の見せ方
### モダン・カタログ・カード
**Web版の縦並びを捨て、左右2段構成を採用**:
```dart
// lib/widgets/sake_card.dart
class SakeCard extends StatelessWidget {
final SakeItem item;
const SakeCard({required this.item});
@override
Widget build(BuildContext context) {
return Card(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(color: Color(0xFFE8E8E8), width: 1),
),
child: Padding(
padding: EdgeInsets.all(16),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 左: 写真角丸12px
ClipRRect(
borderRadius: BorderRadius.circular(12),
child: Image.network(
item.imagePath,
width: 100,
height: 100,
fit: BoxFit.cover,
),
),
SizedBox(width: 16),
// 右: テキスト情報
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// 銘柄名(明朝体、大きく)
Text(
item.brandName ?? '日本酒',
style: GoogleFonts.notoSerifJp(
fontSize: 18,
fontWeight: FontWeight.w600,
color: richBlack,
),
),
SizedBox(height: 4),
// 酒蔵・産地(ゴシック体、控えめ)
Text(
'${item.breweryName ?? ''} | ${item.prefecture ?? ''}',
style: GoogleFonts.notoSansJp(
fontSize: 11,
color: warmGray,
),
),
SizedBox(height: 8),
// 評価
StarRating(rating: item.rating ?? 0),
SizedBox(height: 4),
// 種類
Text(
item.type ?? '',
style: GoogleFonts.notoSansJp(
fontSize: 11,
color: charcoalGray,
),
),
// キャッチコピーNEW!
if (item.catchCopy != null) ...[
SizedBox(height: 8),
Text(
item.catchCopy!,
style: GoogleFonts.notoSerifJp(
fontSize: 12,
fontStyle: FontStyle.italic,
color: posimaiBlue,
),
),
],
],
),
),
],
),
),
);
}
}
```
### インスタ専用・共有カード生成
**正方形1:1の画像を自動生成**:
```dart
// lib/services/instagram_share_service.dart
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:image/image.dart' as img;
class InstagramShareService {
static Future<String> generateInstagramImage(SakeItem item) async {
// 1. 画像を読み込み
final imageBytes = await File(item.imagePath).readAsBytes();
final image = img.decodeImage(imageBytes)!;
// 2. 正方形1080x1080にクロップ
final size = 1080;
final square = img.copyResizeCropSquare(image, size: size);
// 3. 下半分にposimaiカラーのオーバーレイ
final overlay = img.Image(width: size, height: size ~/ 2);
img.fillRect(
overlay,
x1: 0,
y1: 0,
x2: size,
y2: size ~/ 2,
color: img.ColorRgb8(55, 100, 149), // posimaiBlue
);
// 4. オーバーレイを合成
img.compositeImage(
square,
overlay,
dstX: 0,
dstY: size ~/ 2,
);
// 5. テキストを描画(銘柄名、評価、ハッシュタグ)
// TODO: 白抜き明朝体でテキスト描画
// 6. 保存
final directory = await getTemporaryDirectory();
final path = '${directory.path}/instagram_${DateTime.now().millisecondsSinceEpoch}.jpg';
await File(path).writeAsBytes(img.encodeJpg(square));
return path;
}
static Future<void> shareToInstagram(SakeItem item) async {
// インスタ用画像を生成
final imagePath = await generateInstagramImage(item);
// 共有
await Share.shareXFiles(
[XFile(imagePath)],
text: '''
🍶 ${item.brandName ?? '日本酒'}
${item.catchCopy ?? ''}
#ぽんるーむ #日本酒 #${item.prefecture ?? ''} #日本酒好きと繋がりたい
''',
);
}
}
```
**レイアウトイメージ**:
```
┌────────────────────┐
│ │
│ [日本酒ラベル写真] │ ← 上半分540px
│ │
├────────────────────┤
│ posimaiブルー背景 │ ← 下半分540px
│ │
│ 獺祭(明朝体・白) │ ← 銘柄名
│ ⭐⭐⭐⭐⭐ │ ← 評価
│ │
│ 夜風と楽しみたい、 │ ← キャッチコピー
│ 淡麗な一滴 │
│ │
│ #ぽんるーむ │ ← ハッシュタグ
│ [logo] │ ← posimaiロゴ右下
└────────────────────┘
```
---
## 🧩 3. 「遊び心」- 意味のあるデータ分析
### フレーバー・マトリックス
**4象限チャートで味の傾向を可視化**:
```
甘口
濃醇 ←─┼─→ 淡麗
辛口
```
**実装**:
```dart
// lib/widgets/flavor_matrix.dart
class FlavorMatrix extends StatelessWidget {
final List<SakeItem> items;
const FlavorMatrix({required this.items});
@override
Widget build(BuildContext context) {
// AIが解析したフレーバータグから傾向を計算
// 例: "甘口"タグが多い → 甘口寄り
// "フルーティー"タグが多い → 淡麗寄り
return Container(
height: 200,
child: CustomPaint(
painter: FlavorMatrixPainter(
userPosition: _calculateUserPosition(),
),
),
);
}
Offset _calculateUserPosition() {
// ユーザーの好みを計算
// 甘口/辛口、濃醇/淡麗の2軸で位置を決定
return Offset(0.3, 0.6); // 例: やや甘口、やや淡麗
}
}
```
### 日本酒・制覇マップ
**都道府県マップをposimaiカラーで塗りつぶし**:
```dart
// lib/screens/home/map_tab.dart
SimpleMap(
instructions: SMapJapan.instructions,
defaultColor: warmGray, // 未踏破
colors: SMapJapanColors(
// データから自動計算
..._prefectureColors(),
).toMap(),
callback: (id, name, tapDetails) {
// タップで詳細表示
_showPrefectureDetail(name);
},
)
Map<String, Color> _prefectureColors() {
final counts = _countByPrefecture();
return counts.map((prefecture, count) {
if (count == 0) return MapEntry(prefecture, warmGray);
if (count < 3) return MapEntry(prefecture, posimaiBlue.withOpacity(0.3));
return MapEntry(prefecture, posimaiBlue);
});
}
```
**バッジ表示**:
```dart
// マップの上部に表示
Container(
padding: EdgeInsets.all(16),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(8),
),
child: Column(
children: [
Text(
'制覇: ${_completedPrefectures()} / 47',
style: GoogleFonts.notoSerifJp(
fontSize: 24,
fontWeight: FontWeight.bold,
color: posimaiBlue,
),
),
SizedBox(height: 8),
Text(
'あと${47 - _completedPrefectures()}県で全国制覇!',
style: GoogleFonts.notoSansJp(
fontSize: 13,
color: charcoalGray,
),
),
],
),
)
```
### Synology バックアップ・ステータス
**マイページの右上に控えめに表示**:
```dart
// lib/screens/home/profile_tab.dart
Positioned(
top: 16,
right: 16,
child: Container(
padding: EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: Colors.green[50],
borderRadius: BorderRadius.circular(16),
border: Border.all(color: Colors.green[200]!),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.cloud_done, size: 16, color: Colors.green[700]),
SizedBox(width: 4),
Text(
'Home Lab Sync: OK',
style: GoogleFonts.notoSansJp(
fontSize: 11,
color: Colors.green[700],
fontWeight: FontWeight.w500,
),
),
],
),
),
)
```
---
## 📦 データモデル(更新版)
### SakeItem (Hive Model)
**キャッチコピーを追加**:
```dart
import 'package:hive/hive.dart';
part 'sake_item.g.dart';
@HiveType(typeId: 0)
class SakeItem extends HiveObject {
// 基本情報
@HiveField(0)
String? brandName;
@HiveField(1)
String? breweryName;
@HiveField(2)
String? prefecture;
@HiveField(3)
String? type;
@HiveField(4)
double? alcoholContent;
@HiveField(5)
int? polishingRatio;
// 画像
@HiveField(6)
String imagePath;
@HiveField(7)
List<String>? additionalImages;
// 評価・メモ
@HiveField(8)
double? rating;
@HiveField(9)
String? memo;
@HiveField(10)
List<String>? tags;
// フラグ
@HiveField(11)
bool isFavorite;
@HiveField(12)
bool isWishlist;
// 日時
@HiveField(13)
DateTime createdAt;
@HiveField(14)
DateTime? updatedAt;
// 価格(オプション)
@HiveField(15)
int? price;
@HiveField(16)
int? volume;
// 🆕 AIが生成したキャッチコピー
@HiveField(17)
String? catchCopy;
// 🆕 フレーバープロファイル(甘口/辛口、濃醇/淡麗)
@HiveField(18)
double? sweetnessScore; // -1.0(辛口)~ 1.0(甘口)
@HiveField(19)
double? bodyScore; // -1.0(淡麗)~ 1.0(濃醇)
SakeItem({
this.brandName,
this.breweryName,
this.prefecture,
this.type,
this.alcoholContent,
this.polishingRatio,
required this.imagePath,
this.additionalImages,
this.rating,
this.memo,
this.tags,
this.isFavorite = false,
this.isWishlist = false,
required this.createdAt,
this.updatedAt,
this.price,
this.volume,
this.catchCopy,
this.sweetnessScore,
this.bodyScore,
});
}
```
---
## 🚀 実装優先順位
### Phase 1: MVP5時間
#### チェックリスト
- [ ] プロジェクト初期化(`flutter create ponshu_room_reborn`
- [ ] Android設定compileSdk: 36, targetSdk: 35
- [ ] 依存関係追加
- [ ] Hiveセットアップ
- [ ] SakeItemモデルキャッチコピー含む
- [ ] posimaiテーマ
- [ ] ホーム画面骨組み4タブ
- [ ] **Gemini 3.0解析 + リアルタイム実況**
- [ ] カメラ撮影
- [ ] 入力フォーム
- [ ] 詳細画面
- [ ] SafeArea対応
### Phase 2: 「美録」UI洗練3時間
#### チェックリスト
- [ ] モダン・カタログ・カード左右2段構成
- [ ] 明朝体×ゴシック体の適用
- [ ] インスタ専用画像生成機能
- [ ] Hero遷移
- [ ] アニメーション200-300ms
### Phase 3: 「遊び心」機能拡張4時間
#### チェックリスト
- [ ] フレーバー・マトリックス
- [ ] 日本酒・制覇マップ + バッジ
- [ ] Synologyバックアップ・ステータス表示
- [ ] AIソムリエ質問例、チャット形式
- [ ] マイページ統計グラフ
- [ ] 検索・フィルタ・ソート
### Phase 4: 共有機能2時間
#### チェックリスト
- [ ] シンプルテキスト共有
- [ ] Instagram用正方形画像生成
- [ ] キャッチコピー付き共有
**合計所要時間**: 14時間
---
## 📐 画面構成
### ホーム画面HomeScreen
#### ボトムナビゲーション
```
┌─────┬─────┬─────┬─────┐
│ 🍶 │ 🗺️ │ 🤖 │ 👤 │
│ 酒 │ マップ│ AI │ MY │
└─────┴─────┴─────┴─────┘
```
#### タブ1: 酒リストListTab
**モダン・カタログ・カード**:
```
┌────────────────────────────┐
│ [100x100] │ 獺祭 │ ← 明朝体、大きく
│ 写真 │ 旭酒造 | 山口県 │ ← ゴシック体、控えめ
│ 角丸12px │ ⭐⭐⭐⭐⭐ 純米大吟醸 │
│ │ "夜風と楽しみたい、淡麗な一滴" │ ← キャッチコピー
└────────────────────────────┘
```
#### タブ2: マップMapTab
**日本酒・制覇マップ**:
- 未踏破: warmGray
- 3本未満: posimaiBlue (30% opacity)
- 3本以上: posimaiBlue (100%)
- バッジ: 「制覇: 5 / 47」「あと42県で全国制覇
#### タブ3: AIソムリエAiTab
**質問例ボタン**:
```dart
Wrap(
spacing: 8,
children: [
OutlinedButton(
child: Text('純米大吟醸とは?'),
onPressed: () => _askAI('純米大吟醸について詳しく教えて'),
),
OutlinedButton(
child: Text('山田錦について教えて'),
onPressed: () => _askAI('山田錦という酒米の特徴を教えて'),
),
OutlinedButton(
child: Text('刺身に合う日本酒は?'),
onPressed: () => _askAI('刺身に合う日本酒のおすすめを教えて'),
),
OutlinedButton(
child: Text('初心者におすすめの銘柄'),
onPressed: () => _askAI('日本酒初心者におすすめの銘柄を教えて'),
),
],
)
```
#### タブ4: マイページProfileTab
**セクション構成**:
1. **Synologyバックアップステータス**(右上)
```
🏠 Home Lab Sync: OK
```
2. **酒蔵サマリー**
```
┌─────────┬─────────┬─────────┐
│ 1 │ 0 │ 0 │
│ 飲んだ本数│お気に入り│ 買いたい │
└─────────┴─────────┴─────────┘
```
3. **フレーバー・マトリックス**
```
甘口
│ ●(あなた)
濃醇 ←─┼─→ 淡麗
辛口
あなたが選ぶ酒は、フルーティーな甘口に偏っています
```
4. **よく飲む都道府県**
```
🥇 青森県 ━━━━━━━━━━ 1本
```
5. **飲酒傾向グラフ**
- 月別飲酒本数直近6ヶ月
- 評価分布1-5星
---
## 🔐 プライバシー・セキュリティ
### データ保存場所
#### デフォルト(全ユーザー)
```
✅ ローカルHive DBのみ
✅ 写真はアプリ専用ディレクトリ
❌ 外部サーバーへの送信なし
```
#### オプションposimai専用
```
✅ Synology NAS連携WebDAV/FTP
✅ 自動バックアップ
✅ "Home Lab Sync: OK" ステータス表示
```
---
## 📄 ファイル構成
```
lib/
├── main.dart
├── secrets.dart
├── models/
│ ├── sake_item.dart
│ └── sake_item.g.dart
├── providers/
│ ├── sake_repository_provider.dart
│ ├── gemini_provider.dart
│ └── camera_provider.dart
├── services/
│ ├── hive_service.dart
│ ├── gemini_service.dart
│ ├── share_service.dart
│ └── instagram_share_service.dart ← 🆕
├── screens/
│ ├── home/
│ │ ├── home_screen.dart
│ │ ├── list_tab.dart
│ │ ├── map_tab.dart
│ │ ├── ai_tab.dart
│ │ └── profile_tab.dart
│ ├── detail_screen.dart
│ └── input_screen.dart
├── widgets/
│ ├── sake_card.dart ← 🆕 左右2段構成
│ ├── star_rating.dart
│ ├── prefecture_dropdown.dart
│ ├── tag_chip.dart
│ ├── flavor_matrix.dart ← 🆕
│ └── analyzing_overlay.dart ← 🆕 リアルタイム実況
└── theme/
└── app_theme.dart
```
---
## ✅ 完成基準
### MVP完成の定義
- [ ] カメラで日本酒を撮影できる
- [ ] Gemini 3.0でリアルタイム実況しながら解析
- [ ] キャッチコピーが自動生成される
- [ ] データをHiveに保存できる
- [ ] モダン・カタログ・カード左右2段で表示
- [ ] 詳細表示できる
- [ ] SafeAreaで見切れない
- [ ] Android 15 (Xiaomi 14T Pro) で動作する
### 最終完成の定義
- [ ] すべての機能が動作
- [ ] フレーバー・マトリックス表示
- [ ] 日本酒・制覇マップ + バッジ
- [ ] Instagram用正方形画像生成
- [ ] Synologyバックアップステータス表示
- [ ] 「雑誌のような」デザイン
- [ ] 60fpsの滑らかな動作
- [ ] 「魔法のような」心地よさ
---
**最終更新**: 2025-12-29
**設計**: Claude (Anthropic) + Gemini (Google AI) + posimai
**実装担当**: Antigravity + Claude
**Let's create the magic! 🍶✨**