Wayne English Platform · 效能與可擴展性設計 500–10,000 人規模
整體架構概覽
從 Genspark 移轉至 GCP,確保 500–10,000 人同時上線不會造成系統緩慢的完整設計藍圖
👥
10,000+
同時上線人數上限
自動擴容支援
< 200ms
目標 API 回應時間
快取命中率 > 80%
🔄
99.9%
系統可用性 SLA
GCP 官方保障
💰
$19–59
月費 USD (1000人)
含快取優化
GCP 完整架構圖
學生 / 老師 / 管理員
瀏覽器 Browser
Cloud Armor
WAF + DDoS 防護
Cloud CDN
靜態資源加速
+
Load Balancer
自動分流
Cloud Run
API 後端 (自動擴容)
Cloud Storage
靜態檔案
Firestore
主要資料庫
Memorystore
Redis 快取
Gemini API
AI 算力
Cloud Monitoring + Logging
監控 / 告警 / 日誌
Firebase Authentication
身份驗證
三層防慢架構設計原則
🛡️
第一層:邊緣加速
  • Cloud CDN 快取靜態資源
  • 全球邊緣節點(含台灣)
  • HTML/CSS/JS 不觸碰伺服器
  • 減少 90% 靜態請求負載
第二層:快取層
  • Redis (Memorystore) 熱點資料
  • 瀏覽器 sessionStorage 快取
  • API 回應快取 5-60 分鐘
  • 減少 60-80% 資料庫讀取
🔄
第三層:自動擴容
  • Cloud Run 0→N 自動擴容
  • Firestore 無限水平擴展
  • 負載平衡自動分流
  • 人數翻倍系統自動應對
核心保證:以下介紹的架構可讓系統從 500 人平滑擴展至 10,000+ 人,且無需手動調整伺服器。只要流量增加,GCP 自動增加運算資源;流量減少,自動縮回節省費用。
效能瓶頸分析
現有系統在高並發下的潛在問題點,以及對應的解決方向
瓶頸診斷雷達
高風險瓶頸
1
🔴 Tables API 並發限制(最高風險)
1000 人 × 3 次/分 = 3,000 請求/分鐘,Genspark 無公開限流文件,易觸發 429 錯誤。GCP Firestore 沒有此限制,自動擴展。
2
🔴 student.html 體積過大(581 KB)
首次載入需下載 581 KB HTML + 200+ KB JS,在行動網路(4G)需 3-8 秒。需拆分模組 + 啟用 Gzip 壓縮。
3
🔴 Gemini API Key 暴露在前端
任何人可從開發者工具取得 API Key,遭濫用將導致費用暴增或服務中斷。必須移至後端保管。
中等風險項目
4
🟡 無 sessionStorage 快取
每次頁面切換都重新呼叫 API,相同資料反覆請求。加入快取可減少 60% API 呼叫。
5
🟡 db-words.js 等大型 JS 一次全載
db-words.js (71 KB)、db-exam.js (70 KB) 等在用到前就全部載入,佔用記憶體。應改為動態 import()。
6
🟡 無監控與告警機制
目前無法得知系統是否正常運行、哪個模組出錯。在 GCP 需設定 Cloud Monitoring 告警。
請求量預估(1000人同時上線)
瓶頸對照表
瓶頸點現狀(Genspark)移轉後(GCP)改善幅度
API 並發❌ 未知上限✅ Firestore 自動擴展↑ 無限
靜態資源⚠️ 單一節點✅ 全球 CDN 邊緣↑ 90%
API 回應時間⚠️ 200-800ms✅ <100ms(快取)↑ 80%
資料庫讀寫❌ 無快取✅ Redis 快取層↑ 70%
AI API 安全❌ Key 暴露前端✅ 後端環境變數✅ 安全
自動擴容❌ 無法擴展✅ Cloud Run 自動0→N 彈性
CDN 靜態加速策略
讓靜態資源從離使用者最近的邊緣節點提供,大幅降低載入時間
靜態資源(HTML/CSS/JS/圖片/音效)佔頁面載入的 80-90%。透過 CDN,這些資源從台灣本地節點提供,延遲從 300ms 降至 <20ms。
部署靜態資源到 GCP Cloud Storage + CDN
1
建立 GCS Bucket 並啟用靜態網站托管
# 建立儲存桶(asia-east1 = 台灣最近) gsutil mb -l asia-east1 gs://wayne-english-app # 設定公開讀取 gsutil iam ch allUsers:objectViewer gs://wayne-english-app # 設定靜態網站入口 gsutil web set -m index.html -e 404.html gs://wayne-english-app # 上傳所有靜態檔案(-Z 自動 gzip 壓縮) gsutil -m -h "Cache-Control:public,max-age=3600" \ cp -Z -r ./*.html gs://wayne-english-app/ gsutil -m -h "Cache-Control:public,max-age=86400" \ cp -Z -r ./js/ gs://wayne-english-app/js/ gsutil -m -h "Cache-Control:public,max-age=604800" \ cp -Z -r ./images/ gs://wayne-english-app/images/
2
設定 Cloud CDN(Google Cloud Console)
# 建立負載平衡器 + 啟用 CDN(也可用 Console UI) gcloud compute backend-buckets create wayne-backend \ --gcs-bucket-name=wayne-english-app \ --enable-cdn \ --cache-mode=CACHE_ALL_STATIC # 建立 URL 映射 gcloud compute url-maps create wayne-url-map \ --default-backend-bucket=wayne-backend # 建立 HTTPS Proxy(需先申請 SSL 憑證) gcloud compute managed-ssl-certificates create wayne-cert \ --domains=english.yourschool.tw gcloud compute target-https-proxies create wayne-https-proxy \ --url-map=wayne-url-map \ --ssl-certificates=wayne-cert
3
快取標頭設定建議
資源類型快取時間說明
HTML 頁面Cache-Control: public, max-age=36001小時,功能更新後手動清除
JS 資料庫(db-*.js)Cache-Control: public, max-age=864001天,詞庫更新後清除
圖片 / 音效Cache-Control: public, max-age=6048007天,幾乎不更新
API 回應Cache-Control: private, max-age=0不快取,每次即時
啟用 Gzip 壓縮(降低傳輸量)

目前各主要檔案大小 vs 壓縮後預估:

檔案原始大小Gzip 後節省
student.html581 KB~145 KB75%
db-words.js71 KB~22 KB69%
db-exam.js70 KB~21 KB70%
db-grammar.js50 KB~16 KB68%
teacher.html63 KB~20 KB68%

GCS 上傳時自動啟用壓縮:

# -Z 參數 = 自動 gzip 並設定 Content-Encoding gsutil cp -Z index.html gs://wayne-english-app/ # 驗證:檢查 Content-Encoding header curl -I https://your-domain.com/student.html # 應看到:Content-Encoding: gzip
資料庫擴展策略
Firestore 的水平擴展設計,以及如何優化讀寫操作避免過多費用
Tables API → Firestore 對照轉換

❌ 舊版:Genspark Tables API

// 舊版:直接呼叫 Tables API async function loadProgress() { const res = await fetch( 'tables/student_progress?limit=100' ); const data = await res.json(); return data.data; } async function saveProgress(id, score) { await fetch(`tables/student_progress/${id}`, { method: 'PATCH', body: JSON.stringify({ total_score: score }) }); }

✅ 新版:Firestore SDK

// 新版:Firestore(加入 sessionStorage 快取) import { getFirestore, doc, getDoc, setDoc } from 'firebase/firestore'; async function loadProgress(userId) { // 先查 sessionStorage const cached = sessionStorage.getItem('progress'); if (cached) return JSON.parse(cached); const db = getFirestore(); const snap = await getDoc( doc(db, 'student_progress', userId) ); const data = snap.data(); sessionStorage.setItem('progress', JSON.stringify(data)); return data; }
Firestore 資料結構設計(對應現有 Tables)
// Firestore Collection 結構(對應現有 4 個 Tables) { // 對應 users table "users": { "[userId]": { username, display_name, role, status, email, avatar_key, last_login, login_count } }, // 對應 student_progress table "student_progress": { "[userId]": { streak, last_study_date, total_words_learned, total_score, level, badges: [...] } }, // 對應 activity_log table(Sub-collection 設計) "users": { "[userId]/activity_logs/[logId]": { activity_type, module_name, score, duration_seconds, timestamp } }, // 對應 teacher_messages table "teacher_messages": { "[msgId]": { teacher_id, student_id, message_type, content, is_read, created_at } }, // 對應 weekly_tasks + class_groups tables "weekly_tasks": { ... }, "class_groups": { ... } }
Firestore 讀寫優化(降低成本)
✅ 批次寫入

將多次小更新合併為一次 batch write,從每分鐘 5-10 次寫入降至 1 次。

const batch = writeBatch(db); batch.update(ref1, { score: 95 }); batch.update(ref2, { streak: 7 }); await batch.commit(); // 1次寫入
✅ 定時批次寫入

學習過程中快取到記憶體,每 60 秒或離頁時才寫入 Firestore。

// 離頁時強制寫入 window.addEventListener('beforeunload', () => flushProgress() ); // 定時每60秒同步 setInterval(syncProgress, 60000);
✅ 只讀必要欄位

使用 field mask 只取需要的欄位,減少傳輸量與讀取費用。

// 只取 score 和 streak const snap = await getDoc( doc(db, 'student_progress', uid) ); // 僅存取必要欄位 const { score, streak } = snap.data();
後端自動擴容
Cloud Run 是最適合本系統的後端選擇:只在有請求時才運行,自動從 0 擴展到 1000+ 個實例
Cloud Run 自動擴容原理
Cloud Run 後端完整程式碼(Node.js)
// server.js - Cloud Run 後端(安全保管 Gemini API Key) const express = require('express'); const { GoogleGenerativeAI } = require('@google/generative-ai'); const admin = require('firebase-admin'); const rateLimit = require('express-rate-limit'); const app = express(); app.use(express.json()); // ✅ CORS 設定(只允許自己的網域) app.use((req, res, next) => { res.header('Access-Control-Allow-Origin', process.env.ALLOWED_ORIGIN || 'https://english.yourschool.tw'); res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization'); next(); }); // ✅ 速率限制:每個 IP 每分鐘最多 20 次 AI 請求 const aiLimiter = rateLimit({ windowMs: 60 * 1000, max: 20, message: { error: '請求過於頻繁,請稍候再試' } }); // ✅ Gemini AI 端點(API Key 存在環境變數,前端看不到) app.post('/api/ai/chat', aiLimiter, async (req, res) => { const { prompt, context } = req.body; const genAI = new GoogleGenerativeAI(process.env.GEMINI_KEY); const model = genAI.getGenerativeModel({ model: 'gemini-2.0-flash' }); const result = await model.generateContent(prompt); res.json({ text: result.response.text() }); }); // ✅ 前端改成呼叫後端 // 舊版:fetch('https://generativelanguage.googleapis.com/v1beta/...') // 新版:fetch('/api/ai/chat', { method:'POST', body:JSON.stringify({prompt}) }) app.listen(process.env.PORT || 8080);
部署 Cloud Run
# 1. 建立 Dockerfile FROM node:20-alpine WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . EXPOSE 8080 CMD ["node", "server.js"] # 2. 建置 & 推送到 Artifact Registry gcloud builds submit --tag asia-east1-docker.pkg.dev/[PROJECT]/wayne/api # 3. 部署到 Cloud Run(設定自動擴容) gcloud run deploy wayne-api \ --image asia-east1-docker.pkg.dev/[PROJECT]/wayne/api \ --region asia-east1 \ --min-instances 0 \ # 無流量時縮至 0(省費) --max-instances 100 \ # 最大 100 個實例 --concurrency 80 \ # 每實例最多 80 並發 --memory 512Mi \ --set-env-vars GEMINI_KEY=your-key-here \ --allow-unauthenticated
自動擴容效果:500 人同時上線 → Cloud Run 自動啟動 ~7 個實例(每實例 80 並發),5000 人 → 自動擴至 63 個實例,無需人工介入。縮容時自動關閉多餘實例節省費用。
多層快取策略
從瀏覽器到資料庫建立三層快取,讓 80% 的請求不需觸碰資料庫
快取層次架構
Layer 1
瀏覽器
sessionStorage / localStorage
學習進度、使用者資料、訊息列表。快取時效:sessionStorage = 關頁清空,localStorage = 永久。命中率:90%(同一 session 內多次查詢)
Layer 2
CDN 快取
Cloud CDN Edge Cache
靜態 HTML/JS/CSS/圖片。快取時效:依 Cache-Control 設定(1小時~7天)。命中率:95%(熱門頁面)。全球 PoP 節點,台灣用戶從台北/彰化節點取得。
Layer 3
Redis
Cloud Memorystore (Redis)
熱點 API 回應、班級排行榜、老師訊息列表。快取時效:5-60 分鐘。回應速度:<5ms(vs Firestore 50-200ms)。月費:~$30 USD(基本方案)。
前端 sessionStorage 快取實作(直接可用)
// ✅ 可立即加入 student.html / teacher.html 的快取工具 const Cache = { set(key, data, ttlMinutes = 60) { sessionStorage.setItem(key, JSON.stringify({ data, exp: Date.now() + ttlMinutes * 60000 })); }, get(key) { const item = sessionStorage.getItem(key); if (!item) return null; const { data, exp } = JSON.parse(item); if (Date.now() > exp) { sessionStorage.removeItem(key); return null; } return data; }, del(key) { sessionStorage.removeItem(key); } }; // 使用範例:快取學習進度 60 分鐘 async function getProgress(userId) { const cached = Cache.get(`progress_${userId}`); if (cached) { console.log('⚡ 從快取取得進度'); return cached; } const data = await fetchFromFirestore(userId); Cache.set(`progress_${userId}`, data, 60); return data; } // 使用範例:快取班級訊息 5 分鐘 async function getMessages(classId) { const cached = Cache.get(`msgs_${classId}`); if (cached) return cached; const msgs = await loadMessagesFromDB(classId); Cache.set(`msgs_${classId}`, msgs, 5); return msgs; }
快取後 API 呼叫量估算
AI API 管理與限流
確保 Gemini API 不被濫用,同時控制成本並維持服務品質
重要安全警告:目前 Gemini API Key 直接寫在 student.html 前端,任何人打開開發者工具(F12)即可看到並濫用。移轉 GCP 後必須將 Key 移至後端。
AI API 三層保護機制
❌ 現狀(危險)
  • API Key 在 student.html 明碼
  • 任何人可無限呼叫
  • 遭盜用費用暴增
  • 無使用量追蹤
保護層 1:後端代理
  • Key 存在 Cloud Run 環境變數
  • 前端只看到 /api/ai/chat
  • 驗證 Firebase Token 才放行
  • 記錄每次呼叫 Log
保護層 2+3:限流
  • 每用戶每分鐘最多 10 次
  • 每 IP 每分鐘最多 20 次
  • 每日費用上限警報
  • Cloud Armor 封鎖可疑流量
前端改寫:安全呼叫 AI

❌ 舊版(不安全)

// ❌ Key 直接在前端 const GEMINI_KEY = 'AIzaSy...'; const res = await fetch( `https://generativelanguage.googleapis.com/v1beta/ models/gemini-2.0-flash:generateContent?key=${GEMINI_KEY}`, { method: 'POST', body: JSON.stringify({ contents: [...] }) } );

✅ 新版(安全)

// ✅ 呼叫自己的後端(Key 在伺服器) async function callGemini(prompt) { const token = await firebase.auth().currentUser.getIdToken(); const res = await fetch('/api/ai/chat', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ prompt }) }); return (await res.json()).text; }
AI 費用預警設定
# 在 GCP Console 設定費用警報(CLI 方式) gcloud billing budgets create \ --billing-account=BILLING_ACCOUNT_ID \ --display-name="Wayne English AI Budget" \ --budget-amount=50USD \ # 月費上限 $50 USD --threshold-rule=percent=80 \ # 80% 時發 Email 警告 --threshold-rule=percent=100 # 100% 時再次警告 # 若需要自動停止服務(超支時) # 可透過 Pub/Sub + Cloud Function 自動停用 API Key
監控與告警設定
上線後如何即時掌握系統健康狀況,提早發現問題
關鍵監控指標(KPI)
⏱️
API 回應時間
目標 <200ms
警報 >500ms
錯誤率
目標 <1%
警報 >5%
👥
同時上線人數
即時監控
預測容量需求
💰
每日費用
警報 >$3/天
自動通知
Cloud Monitoring 告警設定
# 方法 1:直接在 GCP Console > Monitoring > Alerting 設定(推薦 UI 操作) # 方法 2:用 gcloud CLI ## 告警 1:API 回應時間 > 500ms gcloud alpha monitoring policies create \ --notification-channels=EMAIL_CHANNEL_ID \ --condition-filter='metric.type="run.googleapis.com/request_latencies" resource.type="cloud_run_revision" metric.labels.response_code_class="2xx"' \ --condition-threshold-value=500 \ --condition-threshold-comparator=GT \ --display-name="API 回應超過 500ms" ## 告警 2:錯誤率 > 5% gcloud alpha monitoring policies create \ --condition-filter='metric.type="run.googleapis.com/request_count" metric.labels.response_code_class="5xx"' \ --display-name="伺服器錯誤率過高" ## 告警 3:Cloud Run 實例數超過 50(預期用量異常) gcloud alpha monitoring policies create \ --condition-filter='metric.type="run.googleapis.com/container/instance_count"' \ --condition-threshold-value=50 \ --display-name="異常高並發警告"
告警通知與對應處理 SOP
告警類型觸發條件通知方式對應處理優先級
API 回應過慢>500ms 持續 5 分鐘Email + LINE Bot檢查 Cloud Run 實例數 / Firestore 查詢⚠️ 高
伺服器錯誤5xx 錯誤率 >5%Email + LINE Bot查看 Cloud Logging,找 Error 原因🔴 緊急
費用異常日費用 >$3 USDEmail檢查是否有異常流量或 API 濫用⚠️ 高
Cloud Run 大量擴容實例 >50Email確認是正常尖峰或 DDoS 攻擊ℹ️ 中
Firestore 讀取過多日讀 >100,000 次Email確認快取是否正常運作ℹ️ 中
建議監控工具組合
  • Cloud Monitoring – 即時指標儀表板,設定告警規則,免費包含基本功能
  • Cloud Logging – 所有 API 請求 / 錯誤日誌集中管理,可查詢分析
  • Cloud Trace – 追蹤每個請求的完整路徑,找出慢查詢
  • Firebase Performance Monitoring – 前端頁面載入速度、網路請求追蹤(免費)
  • GCP Billing 費用警報 – 設定月費上限,超過自動 Email 通知
成本規劃
不同人數規模下的月費估算,以及如何控制成本
人數 vs 月費趨勢
🤖 AI 算力費用詳細拆解(Gemini API)
重要提醒:AI 算力費用是本系統成本中最大的單一項目,且會隨使用頻率大幅波動。以下為三種情境的詳細計算。
😊 輕度使用(保守估計)
每人每天:2 次 AI 互動
每次 Token:輸入 300 + 輸出 200 = 500 token
每日總量:1,000人 × 2次 × 500 = 100萬 token
月總量:100萬 × 30天 = 3,000萬 token

輸入費:1,500萬 × $0.075/1M = $1.1
輸出費:1,500萬 × $0.30/1M = $4.5
月費合計:≈ $6 USD(NT$192)
😐 中度使用(一般情境)
每人每天:5 次 AI 互動
每次 Token:輸入 400 + 輸出 300 = 700 token
每日總量:1,000人 × 5次 × 700 = 350萬 token
月總量:350萬 × 30天 = 1.05億 token

輸入費:5,250萬 × $0.075/1M = $3.9
輸出費:5,250萬 × $0.30/1M = $15.8
月費合計:≈ $20 USD(NT$640)
😰 重度使用(作文批改為主)
每人每天:10 次 AI 互動
每次 Token:輸入 800 + 輸出 600 = 1,400 token
每日總量:1,000人 × 10次 × 1,400 = 1,400萬 token
月總量:1,400萬 × 30天 = 4.2億 token

輸入費:2.1億 × $0.075/1M = $15.8
輸出費:2.1億 × $0.30/1M = $63.0
月費合計:≈ $79 USD(NT$2,528)
本系統 AI 功能使用頻率分析
AI 功能使用場景每次 Token 估算使用頻率費用占比
✏️ 作文/翻譯批改student.html輸入600 + 輸出400 = 1,000⭐⭐⭐ 最高~45%
🗣️ 口語對話(chat.html)Chat 場景輸入500 + 輸出350 = 850⭐⭐⭐ 高~35%
📝 出題生成student.html 週測輸入300 + 輸出600 = 900⭐⭐ 中~12%
🔊 Gemini STT 語音辨識chat.html 麥克風音訊 token(較貴)⭐⭐ 中~8%
🌱 國小 AI 批改elementary.html輸入200 + 輸出200 = 400⭐ 低~5%
💡 Gemini 2.0 Flash 定價(2025年):
輸入 Token:$0.075 / 1M token(免費額度:每日 100萬 token,每分鐘 15 次)
輸出 Token:$0.30 / 1M token
語音/音訊 Token:$0.075 / 1M token(約普通文字的 1-2 倍成本)
⚠️ 注意:超過免費額度才開始計費,1000人一般情況下每天會超過免費額度約 2-3 倍
完整月費總表(含 AI 算力,1000人)
以下費用已包含 Gemini AI 算力費用(以中度使用情境計算)。AI 費用因使用習慣差異大,請參考上方三種情境選擇適合的估算。
服務項目 費用類型 免費額度 500 人 1,000 人 3,000 人 10,000 人
Cloud Storage(靜態)基礎架構5 GB / 月$0$0$1$3
Cloud CDN基礎架構首 10 GB 免費$1$3$8$25
Firebase Auth基礎架構10K MAU/月$0$0$30$600
Firestore(含快取優化)資料庫50K讀/1K寫/天$0$12$35$110
Cloud Run(後端 API)後端200萬請求/月$0$2$6$20
🤖 Gemini API 輕度使用AI 算力每日 100萬 token$3$6$18$60
🤖 Gemini API 中度使用AI 算力$10$20$60$200
🤖 Gemini API 重度使用AI 算力$40$79$237$790
Memorystore Redis(選配)快取無免費$30$30$60
合計(中度 AI,不含Redis)$14$37$110$358
合計(中度 AI,含 Redis)$14$67$140$418
約台幣(×32)NT$448NT$2,144NT$4,480NT$13,376
NT$2,144
1,000人 / 月(含AI算力)
中度使用,含Redis快取
NT$99/人/月
收費方案(建議)
1,000人月收 NT$99,000
2.2%
伺服器費 / 月收入
$2,144 ÷ $99,000 = 2.2%
⚠️ AI 算力是最大變數:若學生大量使用作文批改 + 口語對話,費用會從 $20 跳升至 $79 USD(重度情境)。建議:
  • 設定每用戶每日 AI 呼叫上限(建議 10-20 次)
  • 設定 GCP 費用警報(超過 $50 USD/月 自動通知)
  • 監控每日 Token 使用量,超出預算時通知管理員
降低成本的 5 個策略
1
啟用 sessionStorage 快取(立即可做,免費)
減少 60-70% Firestore 讀取次數。1000 人的 Firestore 費用從 $35 降至 $12。今天就可以加入 student.html 和 teacher.html。
2
定時批次寫入(每 60 秒一次)
學習過程中暫存到記憶體,每 60 秒或離頁時才寫入。Firestore 寫入費用($0.9/100K)遠高於讀取,此策略效益最高。
3
AI Token 限制(每用戶每日上限)
設定每用戶每天最多呼叫 AI 20 次,防止少數用戶大量消耗 Token 費用。記錄在 Firestore,後端驗證。
4
靜態資源拆分 + 按需載入
將 student.html (581 KB) 拆分為核心頁面 + 按需載入模組。只在進入文法頁面時才載入 db-grammar.js,減少首屏資料量 70%。
5
Cloud Run 設定最小實例為 0(非上課時間省費)
學生通常在上課時間(8am-6pm)使用,其餘時間設定 min-instances=0,Cloud Run 縮至 0 個實例,節省 40-50% 費用。
移轉步驟指南
從 Genspark 移轉至 GCP Firebase 的完整步驟,預計 1-2 天完成
移轉時程規劃
D1
Day 1 上午(2小時):建立 GCP 環境
申請 GCP 帳號 → 建立專案 → 啟用 Firebase → 建立 Firestore → 設定 Firebase Auth → 建立 Cloud Storage Bucket → 申請 SSL 憑證
D1
Day 1 下午(4小時):移轉資料
從 Genspark Tables API 導出所有資料(users, student_progress, activity_log, teacher_messages, weekly_tasks, class_groups)→ 匯入 Firestore
D2
Day 2 上午(3小時):改寫前端程式碼
改寫 auth.js(Tables API Login → Firebase Auth)→ 改寫 API 呼叫(Tables API → Firestore SDK)→ 改寫 Gemini 呼叫(前端直呼 → 後端代理)
D2
Day 2 下午(2小時):部署 & 測試
部署靜態檔案到 Cloud Storage → 部署 Cloud Run 後端 → 設定 CDN → DNS 切換 → 全功能測試(學生/老師/管理員)
D3
Day 3(選擇性):監控設定 & 優化
設定 Cloud Monitoring 告警 → 設定費用警報 → 加入 sessionStorage 快取 → 壓力測試(模擬 500 人並發)→ 正式上線
資料移轉腳本
// migrate.js - 從 Genspark Tables API 匯出到 Firestore const admin = require('firebase-admin'); const fetch = require('node-fetch'); admin.initializeApp({ credential: admin.credential.applicationDefault() }); const db = admin.firestore(); const TABLES = [ 'users', 'student_progress', 'activity_log', 'teacher_messages', 'weekly_tasks', 'class_groups' ]; async function migrateTable(tableName) { console.log(`⏳ 移轉 ${tableName}...`); let page = 1, total = 0; while (true) { const res = await fetch( `https://your-genspark-project/tables/${tableName}?page=${page}&limit=100` ); const { data, total: count } = await res.json(); if (!data.length) break; const batch = db.batch(); data.forEach(row => { const ref = db.collection(tableName).doc(row.id); batch.set(ref, { ...row, migrated_at: Date.now() }); }); await batch.commit(); total += data.length; console.log(` ✅ 已移轉 ${total}/${count} 筆`); page++; if (data.length < 100) break; } console.log(`✅ ${tableName} 移轉完成,共 ${total} 筆`); } (async () => { for (const table of TABLES) { await migrateTable(table); } console.log('🎉 所有資料移轉完成!'); })();
auth.js 改寫對照

❌ 舊版 auth.js(Tables API)

// 舊版:SHA-256 hash + Tables API 查詢 async function login(username, password) { const hash = await sha256(password); const res = await fetch( `tables/users?search=${username}` ); const { data } = await res.json(); const user = data.find(u => u.username === username && u.password_hash === hash ); if (!user) throw new Error('帳號或密碼錯誤'); return user; }

✅ 新版 auth.js(Firebase Auth)

// 新版:Firebase Auth(安全 + 支援 OAuth) import { getAuth, signInWithEmailAndPassword } from 'firebase/auth'; async function login(email, password) { const auth = getAuth(); const cred = await signInWithEmailAndPassword( auth, email, password ); // 取得用戶角色(存在 Firestore) const db = getFirestore(); const snap = await getDoc( doc(db, 'users', cred.user.uid) ); return { ...cred.user, ...snap.data() }; }
上線檢查清單
正式上線前必須完成的所有項目,確保系統穩定可靠
安全性檢查
  • API Key 已移至後端環境變數(不在前端)
  • Firebase Auth 已設定,舊版帳密登入已停用
  • Firestore Security Rules 已設定(每人只能讀自己的資料)
  • Cloud Armor WAF 已啟用(DDoS 防護)
  • HTTPS 憑證已設定(SSL)
  • CORS 設定只允許自己的網域
  • AI API 速率限制已設定(每用戶每分 10 次)
效能檢查
  • Cloud CDN 已啟用,靜態資源從邊緣節點提供
  • Gzip 壓縮已啟用(gsutil cp -Z)
  • sessionStorage 快取已加入前端程式碼
  • Firestore 批次寫入已實作(每 60 秒)
  • Cloud Run 自動擴容已設定(min=0, max=100)
  • 頁面首屏載入 <3 秒(可用 Lighthouse 測試)
  • Firestore Indexes 已建立(避免全表掃描)
監控與告警
  • Cloud Monitoring 已啟用,儀表板已設定
  • API 回應時間告警 (>500ms) 已設定
  • 錯誤率告警 (>5%) 已設定
  • 費用警報 ($50 USD/月) 已設定
  • 告警通知 Email 已確認可收到
功能測試
  • 學生登入 / 登出功能正常
  • 老師登入 / 儀表板功能正常
  • 管理員 admin 功能正常
  • AI 作文批改功能正常
  • 老師訊息發送 / 學生接收正常
  • 學習進度儲存 / 讀取正常
  • 壓力測試:模擬 500 人並發無異常
壓力測試工具推薦
# 方法 1:k6(免費,推薦) brew install k6 # 建立測試腳本 stress-test.js import http from 'k6/http'; export const options = { vus: 500, // 500 虛擬用戶 duration: '60s', // 持續 60 秒 }; export default function () { http.get('https://english.yourschool.tw/'); http.post('https://api.yourschool.tw/api/progress', ...); } # 執行測試 k6 run stress-test.js # 方法 2:Apache Bench(快速測試) ab -n 10000 -c 500 https://english.yourschool.tw/ # -n = 總請求數 -c = 並發數
🎉 恭喜完成所有檢查!您的系統已準備好在 GCP 上承受 500–10,000 人同時上線,且不會因人數增加而緩慢。接下來只需要關注監控儀表板,享受自動擴容的便利。