dramaling-vocab-learning/web-setup-guide.md

530 lines
13 KiB
Markdown
Raw 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.

# LinguaForge 網頁版環境設置指南
## 🚀 快速開始15分鐘
### 完整指令(複製貼上即可)
```bash
# 1. 建立專案
npx create-next-app@latest linguaforge-web --typescript --tailwind --app --src-dir=false --import-alias="@/*"
cd linguaforge-web
# 2. 安裝所有套件
npm install @supabase/supabase-js @supabase/ssr @supabase/auth-helpers-nextjs
npm install zustand @tanstack/react-query @google/generative-ai
npm install next-pwa next-themes
npm install lucide-react date-fns zod
npm install -D @types/node
# 3. 安裝 shadcn/ui
npx shadcn-ui@latest init -y
# 4. 安裝常用元件
npx shadcn-ui@latest add button card dialog form input label textarea toast alert badge skeleton tabs
# 5. 建立環境變數檔
touch .env.local
# 6. 啟動開發伺服器
npm run dev
```
## 📋 前置需求檢查
### 必要工具
- [ ] Node.js 18+ (檢查:`node -v`)
- [ ] npm 或 pnpm (檢查:`npm -v`)
- [ ] Git (檢查:`git --version`)
- [ ] VS Code 或其他編輯器
### 必要帳號
- [ ] [Supabase](https://supabase.com) - 資料庫
- [ ] [Google AI Studio](https://makersuite.google.com) - Gemini API
- [ ] [Vercel](https://vercel.com) - 部署平台
- [ ] [GitHub](https://github.com) - 版本控制
## 🔧 詳細設置步驟
### Step 1: Supabase 設置
#### 1.1 建立專案
1. 前往 [app.supabase.com](https://app.supabase.com)
2. 點擊「New project」
3. 設定:
- Project name: `linguaforge`
- Database Password: 設定強密碼
- Region: `Southeast Asia (Singapore)` (離台灣近)
#### 1.2 建立資料表
在 SQL Editor 執行:
```sql
-- 啟用 UUID 擴充
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- 用戶表(使用 Supabase Auth
CREATE TABLE profiles (
id UUID REFERENCES auth.users(id) ON DELETE CASCADE PRIMARY KEY,
username TEXT UNIQUE,
created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW())
);
-- 詞卡表
CREATE TABLE cards (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
word TEXT NOT NULL,
pronunciation TEXT,
definition TEXT NOT NULL,
part_of_speech TEXT,
examples JSONB DEFAULT '[]',
source_sentence TEXT,
difficulty TEXT CHECK (difficulty IN ('beginner', 'intermediate', 'advanced')),
-- SM-2 演算法欄位
next_review_date TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()),
easiness_factor DECIMAL(3,2) DEFAULT 2.5,
interval_days INTEGER DEFAULT 0,
repetition_count INTEGER DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()),
updated_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()),
INDEX idx_user_cards (user_id),
INDEX idx_next_review (user_id, next_review_date)
);
-- 複習記錄表
CREATE TABLE review_logs (
id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
card_id UUID REFERENCES cards(id) ON DELETE CASCADE NOT NULL,
user_id UUID REFERENCES auth.users(id) ON DELETE CASCADE NOT NULL,
quality INTEGER CHECK (quality >= 0 AND quality <= 5) NOT NULL,
reviewed_at TIMESTAMP WITH TIME ZONE DEFAULT TIMEZONE('utc', NOW()),
time_spent_seconds INTEGER,
INDEX idx_user_reviews (user_id, reviewed_at)
);
-- 啟用 Row Level Security
ALTER TABLE profiles ENABLE ROW LEVEL SECURITY;
ALTER TABLE cards ENABLE ROW LEVEL SECURITY;
ALTER TABLE review_logs ENABLE ROW LEVEL SECURITY;
-- RLS 政策
CREATE POLICY "Users can view own profile" ON profiles
FOR SELECT USING (auth.uid() = id);
CREATE POLICY "Users can update own profile" ON profiles
FOR UPDATE USING (auth.uid() = id);
CREATE POLICY "Users can create own profile" ON profiles
FOR INSERT WITH CHECK (auth.uid() = id);
CREATE POLICY "Users can view own cards" ON cards
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Users can create own cards" ON cards
FOR INSERT WITH CHECK (auth.uid() = user_id);
CREATE POLICY "Users can update own cards" ON cards
FOR UPDATE USING (auth.uid() = user_id);
CREATE POLICY "Users can delete own cards" ON cards
FOR DELETE USING (auth.uid() = user_id);
CREATE POLICY "Users can view own reviews" ON review_logs
FOR SELECT USING (auth.uid() = user_id);
CREATE POLICY "Users can create own reviews" ON review_logs
FOR INSERT WITH CHECK (auth.uid() = user_id);
-- 觸發器:自動更新 updated_at
CREATE OR REPLACE FUNCTION update_updated_at_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = TIMEZONE('utc', NOW());
RETURN NEW;
END;
$$ language 'plpgsql';
CREATE TRIGGER update_profiles_updated_at BEFORE UPDATE ON profiles
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
CREATE TRIGGER update_cards_updated_at BEFORE UPDATE ON cards
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
```
#### 1.3 取得 API Keys
1. 進入 Project Settings > API
2. 複製:
- `URL` (Project URL)
- `anon public` key
### Step 2: Gemini API 設置
#### 2.1 取得 API Key
1. 前往 [Google AI Studio](https://makersuite.google.com/app/apikey)
2. 點擊「Get API key」
3. 選擇或建立 Google Cloud 專案
4. 複製 API Key
#### 2.2 測試 API
```bash
curl -X POST "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"contents": [{
"parts": [{
"text": "Hello"
}]
}]
}'
```
### Step 3: 專案配置
#### 3.1 環境變數設置
編輯 `.env.local`
```bash
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
# Gemini API
GEMINI_API_KEY=your-gemini-api-key
# App
NEXT_PUBLIC_APP_URL=http://localhost:3000
```
#### 3.2 TypeScript 配置
更新 `tsconfig.json`
```json
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [
{
"name": "next"
}
],
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}
```
#### 3.3 Tailwind 配置
更新 `tailwind.config.ts`
```typescript
import type { Config } from 'tailwindcss'
const config: Config = {
darkMode: ["class"],
content: [
'./pages/**/*.{ts,tsx}',
'./components/**/*.{ts,tsx}',
'./app/**/*.{ts,tsx}',
],
theme: {
extend: {
colors: {
border: "hsl(var(--border))",
input: "hsl(var(--input))",
ring: "hsl(var(--ring))",
background: "hsl(var(--background))",
foreground: "hsl(var(--foreground))",
primary: {
DEFAULT: "hsl(var(--primary))",
foreground: "hsl(var(--primary-foreground))",
},
secondary: {
DEFAULT: "hsl(var(--secondary))",
foreground: "hsl(var(--secondary-foreground))",
},
destructive: {
DEFAULT: "hsl(var(--destructive))",
foreground: "hsl(var(--destructive-foreground))",
},
muted: {
DEFAULT: "hsl(var(--muted))",
foreground: "hsl(var(--muted-foreground))",
},
accent: {
DEFAULT: "hsl(var(--accent))",
foreground: "hsl(var(--accent-foreground))",
},
},
borderRadius: {
lg: "var(--radius)",
md: "calc(var(--radius) - 2px)",
sm: "calc(var(--radius) - 4px)",
},
},
},
plugins: [require("tailwindcss-animate")],
}
export default config
```
### Step 4: 建立專案結構
```bash
# 建立資料夾結構
mkdir -p app/{api,\(auth\),\(dashboard\)}
mkdir -p app/api/{gemini,cards,review}
mkdir -p app/\(auth\)/{login,register}
mkdir -p app/\(dashboard\)/{cards,generate,review,stats}
mkdir -p components/{ui,cards,layout,providers}
mkdir -p lib/{supabase,gemini,algorithms}
mkdir -p hooks
mkdir -p types
mkdir -p public/{icons,images}
```
### Step 5: 初始化核心檔案
#### 5.1 Supabase Client
建立 `lib/supabase/client.ts`
```typescript
import { createBrowserClient } from '@supabase/ssr'
export function createClient() {
return createBrowserClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
)
}
```
#### 5.2 根 Layout
更新 `app/layout.tsx`
```tsx
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import './globals.css'
const inter = Inter({ subsets: ['latin'] })
export const metadata: Metadata = {
title: 'LinguaForge - AI 英語詞彙學習',
description: 'AI 驅動的個人化英語詞彙學習平台',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="zh-TW">
<body className={inter.className}>{children}</body>
</html>
)
}
```
#### 5.3 首頁
更新 `app/page.tsx`
```tsx
import Link from 'next/link'
import { Button } from '@/components/ui/button'
export default function HomePage() {
return (
<div className="flex min-h-screen flex-col items-center justify-center">
<div className="text-center space-y-6">
<h1 className="text-4xl font-bold">LinguaForge</h1>
<p className="text-xl text-muted-foreground">
AI 驅動的英語詞彙學習平台
</p>
<div className="flex gap-4 justify-center">
<Button asChild>
<Link href="/register">開始學習</Link>
</Button>
<Button variant="outline" asChild>
<Link href="/login">登入</Link>
</Button>
</div>
</div>
</div>
)
}
```
### Step 6: 測試運行
```bash
# 啟動開發伺服器
npm run dev
# 開啟瀏覽器
open http://localhost:3000
```
## 🚀 部署到 Vercel
### 6.1 準備部署
```bash
# 初始化 Git
git init
git add .
git commit -m "Initial commit"
# 推送到 GitHub
git remote add origin https://github.com/your-username/linguaforge-web.git
git push -u origin main
```
### 6.2 Vercel 部署
1. 前往 [vercel.com](https://vercel.com)
2. 點擊「Import Project」
3. 選擇 GitHub repo
4. 設定環境變數:
- `NEXT_PUBLIC_SUPABASE_URL`
- `NEXT_PUBLIC_SUPABASE_ANON_KEY`
- `GEMINI_API_KEY`
5. 點擊「Deploy」
### 6.3 自訂網域(可選)
1. 在 Vercel Dashboard > Settings > Domains
2. 新增自訂網域
3. 按照指示設定 DNS
## 🛠️ VS Code 設置
### 推薦擴充套件
```json
{
"recommendations": [
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"bradlc.vscode-tailwindcss",
"prisma.prisma",
"ms-vscode.vscode-typescript-next",
"christian-kohler.path-intellisense",
"aaron-bond.better-comments",
"usernamehw.errorlens"
]
}
```
### 工作區設定
`.vscode/settings.json`
```json
{
"editor.formatOnSave": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.codeActionsOnSave": {
"source.fixAll.eslint": true
},
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true,
"tailwindCSS.experimental.classRegex": [
["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
["cx\\(([^)]*)\\)", "(?:'|\"|`)([^']*)(?:'|\"|`)"]
]
}
```
## 🧪 測試檢查清單
### 功能測試
- [ ] 首頁正常顯示
- [ ] Supabase 連線成功
- [ ] 可以註冊新用戶
- [ ] 可以登入
- [ ] Gemini API 可以呼叫
### 效能測試
```bash
# Lighthouse 測試
npm run build
npm run start
# 開啟 Chrome DevTools > Lighthouse
```
## 🐛 常見問題
### 1. Supabase 連線失敗
```bash
# 檢查環境變數
echo $NEXT_PUBLIC_SUPABASE_URL
echo $NEXT_PUBLIC_SUPABASE_ANON_KEY
# 確認 .env.local 有被載入
# 重啟開發伺服器
```
### 2. Gemini API 錯誤
```bash
# 檢查 API Key
curl "https://generativelanguage.googleapis.com/v1beta/models?key=YOUR_KEY"
# 檢查配額
# 前往 Google Cloud Console 查看
```
### 3. TypeScript 錯誤
```bash
# 重新生成類型
npm run build
# 清除快取
rm -rf .next
npm run dev
```
### 4. Vercel 部署失敗
```bash
# 本地測試 production build
npm run build
npm run start
# 檢查環境變數
vercel env pull
```
## 📝 下一步
環境設置完成後:
1. 參考 `web-mvp-master-plan.md` 開始開發
2. 參考 `web-technical-architecture.md` 了解技術細節
3. 開始 Week 1 的任務
## 🎉 完成確認
如果以下都完成,你就可以開始開發了:
- ✅ 專案在 http://localhost:3000 運行
- ✅ Supabase 資料表建立完成
- ✅ Gemini API Key 測試成功
- ✅ Git repository 初始化
- ✅ 首次 commit 完成
**恭喜!你的開發環境已經準備就緒!🚀**
現在可以開始按照 6 週計劃開發你的 MVP 了!