745 lines
14 KiB
Markdown
745 lines
14 KiB
Markdown
# LinguaForge MVP 開發環境設置指南
|
||
|
||
## 快速開始檢查清單
|
||
|
||
- [ ] 安裝 Flutter SDK 3.16.0+
|
||
- [ ] 安裝 VS Code + Flutter 擴充套件
|
||
- [ ] 設置 iOS 開發環境 (Xcode)
|
||
- [ ] 設置 Android 開發環境 (Android Studio)
|
||
- [ ] 申請 Gemini API Key
|
||
- [ ] 註冊 Supabase 帳號
|
||
- [ ] 設置 Firebase 專案
|
||
- [ ] 初始化 Git repository
|
||
|
||
## 1. Flutter 環境設置
|
||
|
||
### 1.1 安裝 Flutter SDK
|
||
|
||
```bash
|
||
# macOS 安裝
|
||
brew install flutter
|
||
|
||
# 或手動下載
|
||
git clone https://github.com/flutter/flutter.git
|
||
export PATH="$PATH:`pwd`/flutter/bin"
|
||
|
||
# 檢查安裝
|
||
flutter doctor
|
||
```
|
||
|
||
### 1.2 解決 Flutter Doctor 問題
|
||
|
||
```bash
|
||
# 常見問題解決
|
||
flutter doctor --android-licenses # 接受 Android 授權
|
||
sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer # Xcode 路徑
|
||
sudo xcodebuild -runFirstLaunch # Xcode 初始化
|
||
```
|
||
|
||
### 1.3 VS Code 設置
|
||
|
||
```bash
|
||
# 安裝必要擴充套件
|
||
code --install-extension Dart-Code.flutter
|
||
code --install-extension Dart-Code.dart-code
|
||
code --install-extension usernamehw.errorlens
|
||
code --install-extension esbenp.prettier-vscode
|
||
```
|
||
|
||
## 2. 專案初始化
|
||
|
||
### 2.1 建立 Flutter 專案
|
||
|
||
```bash
|
||
# 建立專案
|
||
flutter create --org com.linguaforge --project-name linguaforge_app linguaforge
|
||
|
||
cd linguaforge
|
||
|
||
# 確認可運行
|
||
flutter run
|
||
```
|
||
|
||
### 2.2 專案結構設置
|
||
|
||
```bash
|
||
# 建立資料夾結構
|
||
mkdir -p lib/{config,core,data,domain,presentation,l10n}
|
||
mkdir -p lib/core/{errors,utils,extensions,algorithms}
|
||
mkdir -p lib/data/{models,repositories,services}
|
||
mkdir -p lib/domain/{entities,usecases}
|
||
mkdir -p lib/presentation/{providers,screens,widgets}
|
||
mkdir -p lib/presentation/screens/{auth,home,cards,review,profile}
|
||
mkdir -p lib/presentation/widgets/{common,cards}
|
||
mkdir -p assets/{images,animations,fonts}
|
||
mkdir -p test/{unit,widget,integration}
|
||
```
|
||
|
||
### 2.3 安裝核心套件
|
||
|
||
```yaml
|
||
# pubspec.yaml
|
||
name: linguaforge_app
|
||
description: AI-powered vocabulary learning app
|
||
version: 0.1.0+1
|
||
|
||
environment:
|
||
sdk: ">=3.2.0 <4.0.0"
|
||
|
||
dependencies:
|
||
flutter:
|
||
sdk: flutter
|
||
|
||
# 狀態管理
|
||
provider: ^6.1.0
|
||
|
||
# 網路請求
|
||
dio: ^5.4.0
|
||
dio_retry: ^4.1.0
|
||
|
||
# 本地存儲
|
||
hive: ^2.2.3
|
||
hive_flutter: ^1.1.0
|
||
shared_preferences: ^2.2.2
|
||
|
||
# Firebase
|
||
firebase_core: ^2.24.0
|
||
firebase_auth: ^4.15.0
|
||
firebase_crashlytics: ^3.4.0
|
||
firebase_performance: ^0.9.3
|
||
firebase_analytics: ^10.7.0
|
||
|
||
# Supabase
|
||
supabase_flutter: ^2.0.0
|
||
|
||
# UI 組件
|
||
flutter_screenutil: ^5.9.0
|
||
shimmer: ^3.0.0
|
||
lottie: ^2.7.0
|
||
cached_network_image: ^3.3.0
|
||
|
||
# 工具
|
||
intl: ^0.18.0
|
||
uuid: ^4.2.0
|
||
connectivity_plus: ^5.0.0
|
||
flutter_dotenv: ^5.1.0
|
||
path_provider: ^2.1.0
|
||
|
||
dev_dependencies:
|
||
flutter_test:
|
||
sdk: flutter
|
||
flutter_lints: ^3.0.0
|
||
build_runner: ^2.4.0
|
||
hive_generator: ^2.0.0
|
||
mockito: ^5.4.0
|
||
|
||
flutter:
|
||
uses-material-design: true
|
||
|
||
assets:
|
||
- assets/images/
|
||
- assets/animations/
|
||
- .env
|
||
|
||
fonts:
|
||
- family: NotoSansTC
|
||
fonts:
|
||
- asset: assets/fonts/NotoSansTC-Regular.ttf
|
||
- asset: assets/fonts/NotoSansTC-Medium.ttf
|
||
weight: 500
|
||
- asset: assets/fonts/NotoSansTC-Bold.ttf
|
||
weight: 700
|
||
```
|
||
|
||
安裝套件:
|
||
```bash
|
||
flutter pub get
|
||
```
|
||
|
||
## 3. 外部服務設置
|
||
|
||
### 3.1 Gemini API 設置
|
||
|
||
1. 前往 [Google AI Studio](https://makersuite.google.com/app/apikey)
|
||
2. 點擊「Get API Key」
|
||
3. 建立新專案或選擇現有專案
|
||
4. 複製 API Key
|
||
|
||
```bash
|
||
# .env 檔案
|
||
GEMINI_API_KEY=AIzaSy...your_key_here
|
||
```
|
||
|
||
測試 API:
|
||
```bash
|
||
curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=${GEMINI_API_KEY}" \
|
||
-H "Content-Type: application/json" \
|
||
-d '{
|
||
"contents": [{
|
||
"parts": [{
|
||
"text": "Hello, Gemini!"
|
||
}]
|
||
}]
|
||
}'
|
||
```
|
||
|
||
### 3.2 Supabase 設置
|
||
|
||
1. 前往 [Supabase](https://supabase.com)
|
||
2. 建立新專案
|
||
3. 設定資料庫
|
||
|
||
```sql
|
||
-- 建立 users 表
|
||
CREATE TABLE users (
|
||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
email VARCHAR(255) UNIQUE NOT NULL,
|
||
nickname VARCHAR(50),
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
preferences JSONB DEFAULT '{}'
|
||
);
|
||
|
||
-- 建立 cards 表
|
||
CREATE TABLE cards (
|
||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||
word VARCHAR(100) NOT NULL,
|
||
pronunciation VARCHAR(100),
|
||
definition TEXT NOT NULL,
|
||
part_of_speech VARCHAR(20),
|
||
examples JSONB DEFAULT '[]',
|
||
source_sentence TEXT,
|
||
difficulty VARCHAR(20),
|
||
created_at TIMESTAMP DEFAULT NOW(),
|
||
next_review_date TIMESTAMP DEFAULT NOW(),
|
||
easiness_factor DECIMAL(3,2) DEFAULT 2.5,
|
||
interval_days INTEGER DEFAULT 0,
|
||
repetition_count INTEGER DEFAULT 0
|
||
);
|
||
|
||
-- 建立索引
|
||
CREATE INDEX idx_cards_user_review ON cards(user_id, next_review_date);
|
||
|
||
-- 建立 review_logs 表
|
||
CREATE TABLE review_logs (
|
||
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
||
card_id UUID REFERENCES cards(id) ON DELETE CASCADE,
|
||
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
|
||
quality INTEGER CHECK (quality BETWEEN 1 AND 5),
|
||
reviewed_at TIMESTAMP DEFAULT NOW(),
|
||
time_spent INTEGER
|
||
);
|
||
|
||
-- Row Level Security
|
||
ALTER TABLE cards ENABLE ROW LEVEL SECURITY;
|
||
ALTER TABLE review_logs ENABLE ROW LEVEL SECURITY;
|
||
|
||
-- Policies
|
||
CREATE POLICY "Users can only see their own cards"
|
||
ON cards FOR ALL
|
||
USING (auth.uid() = user_id);
|
||
|
||
CREATE POLICY "Users can only see their own reviews"
|
||
ON review_logs FOR ALL
|
||
USING (auth.uid() = user_id);
|
||
```
|
||
|
||
4. 取得連線資訊
|
||
|
||
```bash
|
||
# .env 檔案
|
||
SUPABASE_URL=https://xxxxx.supabase.co
|
||
SUPABASE_ANON_KEY=eyJhbGc...
|
||
```
|
||
|
||
### 3.3 Firebase 設置
|
||
|
||
1. 前往 [Firebase Console](https://console.firebase.google.com)
|
||
2. 建立新專案
|
||
3. 啟用 Authentication
|
||
|
||
```bash
|
||
# 安裝 Firebase CLI
|
||
npm install -g firebase-tools
|
||
|
||
# 登入
|
||
firebase login
|
||
|
||
# 初始化
|
||
firebase init
|
||
|
||
# 選擇:
|
||
# - Authentication
|
||
# - Crashlytics
|
||
# - Performance Monitoring
|
||
# - Analytics
|
||
```
|
||
|
||
4. 下載設定檔
|
||
|
||
iOS: `GoogleService-Info.plist` → `ios/Runner/`
|
||
Android: `google-services.json` → `android/app/`
|
||
|
||
5. 設定 iOS
|
||
|
||
```ruby
|
||
# ios/Podfile
|
||
platform :ios, '12.0'
|
||
|
||
# 在 target 'Runner' do 後加入
|
||
pod 'Firebase/Analytics'
|
||
pod 'Firebase/Auth'
|
||
pod 'Firebase/Crashlytics'
|
||
pod 'Firebase/Performance'
|
||
```
|
||
|
||
```bash
|
||
cd ios && pod install
|
||
```
|
||
|
||
6. 設定 Android
|
||
|
||
```gradle
|
||
// android/build.gradle
|
||
buildscript {
|
||
dependencies {
|
||
classpath 'com.google.gms:google-services:4.4.0'
|
||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.9'
|
||
classpath 'com.google.firebase:perf-plugin:1.4.2'
|
||
}
|
||
}
|
||
|
||
// android/app/build.gradle
|
||
apply plugin: 'com.google.gms.google-services'
|
||
apply plugin: 'com.google.firebase.crashlytics'
|
||
apply plugin: 'com.google.firebase.firebase-perf'
|
||
|
||
android {
|
||
defaultConfig {
|
||
minSdkVersion 21
|
||
multiDexEnabled true
|
||
}
|
||
}
|
||
|
||
dependencies {
|
||
implementation 'com.google.firebase:firebase-analytics'
|
||
implementation 'androidx.multidex:multidex:2.0.1'
|
||
}
|
||
```
|
||
|
||
## 4. 開發環境配置
|
||
|
||
### 4.1 Git 設置
|
||
|
||
```bash
|
||
# 初始化 Git
|
||
git init
|
||
|
||
# 設定 .gitignore
|
||
cat > .gitignore << EOF
|
||
# Flutter
|
||
.dart_tool/
|
||
.packages
|
||
.pub/
|
||
build/
|
||
.flutter-plugins
|
||
.flutter-plugins-dependencies
|
||
|
||
# iOS
|
||
ios/Pods/
|
||
ios/.symlinks/
|
||
ios/Flutter/Flutter.framework
|
||
ios/Flutter/Flutter.podspec
|
||
|
||
# Android
|
||
android/.gradle/
|
||
android/captures/
|
||
android/local.properties
|
||
*.jks
|
||
*.keystore
|
||
|
||
# Environment
|
||
.env
|
||
.env.*
|
||
|
||
# IDE
|
||
.idea/
|
||
.vscode/
|
||
*.iml
|
||
|
||
# macOS
|
||
.DS_Store
|
||
|
||
# Test
|
||
coverage/
|
||
EOF
|
||
|
||
# 第一次提交
|
||
git add .
|
||
git commit -m "Initial commit: Flutter project setup"
|
||
```
|
||
|
||
### 4.2 VS Code 專案設定
|
||
|
||
```json
|
||
// .vscode/launch.json
|
||
{
|
||
"version": "0.2.0",
|
||
"configurations": [
|
||
{
|
||
"name": "linguaforge (debug)",
|
||
"request": "launch",
|
||
"type": "dart",
|
||
"program": "lib/main.dart",
|
||
"args": ["--dart-define=ENV=development"]
|
||
},
|
||
{
|
||
"name": "linguaforge (profile)",
|
||
"request": "launch",
|
||
"type": "dart",
|
||
"flutterMode": "profile",
|
||
"program": "lib/main.dart"
|
||
},
|
||
{
|
||
"name": "linguaforge (release)",
|
||
"request": "launch",
|
||
"type": "dart",
|
||
"flutterMode": "release",
|
||
"program": "lib/main.dart",
|
||
"args": ["--dart-define=ENV=production"]
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
```json
|
||
// .vscode/settings.json
|
||
{
|
||
"dart.flutterSdkPath": "/opt/homebrew/bin/flutter",
|
||
"editor.formatOnSave": true,
|
||
"editor.codeActionsOnSave": {
|
||
"source.fixAll": true,
|
||
"source.organizeImports": true
|
||
},
|
||
"files.exclude": {
|
||
"**/.dart_tool": true,
|
||
"**/.idea": true,
|
||
"**/android/.gradle": true,
|
||
"**/ios/Pods": true
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.3 環境變數設置
|
||
|
||
```bash
|
||
# 建立 .env 檔案
|
||
cat > .env << EOF
|
||
# API Keys
|
||
GEMINI_API_KEY=your_gemini_api_key_here
|
||
|
||
# Supabase
|
||
SUPABASE_URL=https://xxxxx.supabase.co
|
||
SUPABASE_ANON_KEY=your_anon_key_here
|
||
|
||
# Environment
|
||
ENV=development
|
||
EOF
|
||
|
||
# 建立範例檔案
|
||
cp .env .env.example
|
||
# 移除敏感資訊
|
||
sed -i '' 's/=.*/=your_value_here/g' .env.example
|
||
```
|
||
|
||
## 5. 開發工具設置
|
||
|
||
### 5.1 Postman 設置
|
||
|
||
建立以下集合測試 API:
|
||
|
||
```json
|
||
{
|
||
"info": {
|
||
"name": "LinguaForge API",
|
||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||
},
|
||
"item": [
|
||
{
|
||
"name": "Gemini API Test",
|
||
"request": {
|
||
"method": "POST",
|
||
"header": [
|
||
{
|
||
"key": "Content-Type",
|
||
"value": "application/json"
|
||
}
|
||
],
|
||
"body": {
|
||
"mode": "raw",
|
||
"raw": "{\n \"contents\": [{\n \"parts\": [{\n \"text\": \"Generate a vocabulary card for the word 'abandon'\"\n }]\n }]\n}"
|
||
},
|
||
"url": {
|
||
"raw": "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key={{GEMINI_API_KEY}}"
|
||
}
|
||
}
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 5.2 測試資料準備
|
||
|
||
```dart
|
||
// test/fixtures/test_data.dart
|
||
class TestData {
|
||
static const testSentences = [
|
||
"I need to abandon this bad habit immediately.",
|
||
"She managed to achieve her goals through hard work.",
|
||
"The ancient ruins were discovered by archaeologists.",
|
||
"He demonstrated excellent leadership skills.",
|
||
"The experiment yielded unexpected results.",
|
||
];
|
||
|
||
static const testWords = [
|
||
"abandon",
|
||
"achieve",
|
||
"ancient",
|
||
"demonstrate",
|
||
"experiment",
|
||
];
|
||
|
||
static final testCard = CardModel(
|
||
id: 'test-id',
|
||
word: 'abandon',
|
||
pronunciation: '/əˈbændən/',
|
||
definition: '放棄、遺棄',
|
||
partOfSpeech: 'verb',
|
||
examples: [
|
||
Example(
|
||
english: 'He abandoned his car in the snow.',
|
||
chinese: '他把車遺棄在雪地裡。',
|
||
),
|
||
],
|
||
sourceSentence: 'I need to abandon this bad habit.',
|
||
difficulty: 'intermediate',
|
||
createdAt: DateTime.now(),
|
||
nextReviewDate: DateTime.now().add(Duration(days: 1)),
|
||
easinessFactor: 2.5,
|
||
intervalDays: 1,
|
||
repetitionCount: 0,
|
||
);
|
||
}
|
||
```
|
||
|
||
## 6. 第一個功能測試
|
||
|
||
### 6.1 建立簡單測試頁面
|
||
|
||
```dart
|
||
// lib/main.dart
|
||
import 'package:flutter/material.dart';
|
||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||
import 'package:firebase_core/firebase_core.dart';
|
||
import 'package:supabase_flutter/supabase_flutter.dart';
|
||
|
||
Future<void> main() async {
|
||
WidgetsFlutterBinding.ensureInitialized();
|
||
|
||
// 載入環境變數
|
||
await dotenv.load();
|
||
|
||
// 初始化 Firebase
|
||
await Firebase.initializeApp();
|
||
|
||
// 初始化 Supabase
|
||
await Supabase.initialize(
|
||
url: dotenv.env['SUPABASE_URL']!,
|
||
anonKey: dotenv.env['SUPABASE_ANON_KEY']!,
|
||
);
|
||
|
||
runApp(MyApp());
|
||
}
|
||
|
||
class MyApp extends StatelessWidget {
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return MaterialApp(
|
||
title: 'LinguaForge',
|
||
theme: ThemeData(
|
||
primarySwatch: Colors.indigo,
|
||
useMaterial3: true,
|
||
),
|
||
home: TestScreen(),
|
||
);
|
||
}
|
||
}
|
||
|
||
class TestScreen extends StatelessWidget {
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
title: Text('LinguaForge MVP'),
|
||
),
|
||
body: Center(
|
||
child: Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
Text(
|
||
'環境設置成功!',
|
||
style: Theme.of(context).textTheme.headlineMedium,
|
||
),
|
||
SizedBox(height: 20),
|
||
ElevatedButton(
|
||
onPressed: () {
|
||
// 測試 Gemini API
|
||
_testGeminiAPI();
|
||
},
|
||
child: Text('測試 Gemini API'),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
Future<void> _testGeminiAPI() async {
|
||
// 實作 API 測試
|
||
print('Testing Gemini API...');
|
||
}
|
||
}
|
||
```
|
||
|
||
### 6.2 執行測試
|
||
|
||
```bash
|
||
# 執行 App
|
||
flutter run
|
||
|
||
# 執行測試
|
||
flutter test
|
||
|
||
# 檢查程式碼品質
|
||
flutter analyze
|
||
|
||
# 格式化程式碼
|
||
dart format .
|
||
```
|
||
|
||
## 7. 常見問題排除
|
||
|
||
### 7.1 iOS 建置問題
|
||
|
||
```bash
|
||
# CocoaPods 問題
|
||
cd ios
|
||
pod deintegrate
|
||
pod cache clean --all
|
||
pod install
|
||
|
||
# 證書問題
|
||
open ios/Runner.xcworkspace
|
||
# Xcode > Signing & Capabilities > 選擇 Team
|
||
```
|
||
|
||
### 7.2 Android 建置問題
|
||
|
||
```bash
|
||
# Gradle 問題
|
||
cd android
|
||
./gradlew clean
|
||
./gradlew build
|
||
|
||
# SDK 版本問題
|
||
# 修改 android/app/build.gradle
|
||
# minSdkVersion 21
|
||
# targetSdkVersion 33
|
||
```
|
||
|
||
### 7.3 套件衝突
|
||
|
||
```bash
|
||
# 清理快取
|
||
flutter clean
|
||
flutter pub cache clean
|
||
flutter pub get
|
||
|
||
# 更新套件
|
||
flutter pub upgrade --major-versions
|
||
```
|
||
|
||
## 8. 每日開發流程
|
||
|
||
### 8.1 開始工作
|
||
|
||
```bash
|
||
# 1. 更新程式碼
|
||
git pull origin main
|
||
|
||
# 2. 安裝相依套件
|
||
flutter pub get
|
||
|
||
# 3. 執行 App
|
||
flutter run
|
||
|
||
# 4. 開始開發
|
||
code .
|
||
```
|
||
|
||
### 8.2 提交程式碼
|
||
|
||
```bash
|
||
# 1. 檢查程式碼
|
||
flutter analyze
|
||
flutter test
|
||
|
||
# 2. 格式化
|
||
dart format .
|
||
|
||
# 3. 提交
|
||
git add .
|
||
git commit -m "feat: implement feature X"
|
||
git push origin feature/branch-name
|
||
```
|
||
|
||
## 9. 效能監控設置
|
||
|
||
### 9.1 開發階段監控
|
||
|
||
```dart
|
||
// 顯示效能覆蓋層
|
||
MaterialApp(
|
||
showPerformanceOverlay: true, // 顯示 FPS
|
||
checkerboardRasterCacheImages: true, // 檢查快取圖片
|
||
checkerboardOffscreenLayers: true, // 檢查離屏圖層
|
||
)
|
||
```
|
||
|
||
### 9.2 Flutter Inspector
|
||
|
||
VS Code: `Cmd + Shift + P` > `Flutter: Open DevTools`
|
||
|
||
## 10. 準備就緒檢查清單
|
||
|
||
### 必要項目 ✅
|
||
- [ ] Flutter 環境運行正常 (`flutter doctor` 無錯誤)
|
||
- [ ] 可以在模擬器/實機運行基礎 App
|
||
- [ ] Gemini API Key 可正常使用
|
||
- [ ] Supabase 資料庫已建立
|
||
- [ ] Firebase 專案已設置
|
||
- [ ] Git repository 已初始化
|
||
|
||
### 可選項目 ⚠️
|
||
- [ ] Postman 已安裝並設置
|
||
- [ ] 實機測試環境就緒
|
||
- [ ] CI/CD 環境設置
|
||
|
||
## 下一步
|
||
|
||
環境設置完成後,參考以下文件開始開發:
|
||
1. `mvp-feature-spec.md` - 功能規格
|
||
2. `mvp-technical-spec.md` - 技術實作
|
||
3. `solo-mvp-master-plan.md` - 開發時程
|
||
|
||
**準備就緒?開始 Week 1 的開發吧!🚀** |