昨天完成了 UI/UX 設計,今天要搭建技術架構。這不是選技術棧的炫技大會,而是要設計一個能撐起 MVP、又能優雅擴展到百萬用戶的架構。
很多人覺得 MVP 階段不用管架構,「能動就好」。但我見過太多專案因為初期架構債累積,導致:
正確的架構不是過度設計,而是剛好夠用的設計。
經過與 AI 深度討論,我選擇了這套現代化架構:
前端框架:Next.js 15 (App Router)
後端服務:Supabase (BaaS)
AI 服務:OpenAI + Vercel AI SDK
部署平台:Vercel
監控分析:Vercel Analytics + Sentry
Next.js 15 + App Router 的選擇邏輯:
Supabase 作為 BaaS 的價值:
關鍵決策:不自建後端
傳統架構:前端 + Node.js API + PostgreSQL + Redis + Auth
我的架構:Next.js + Supabase(包含所有後端功能)
省下的時間:至少 3 週
省下的成本:每月 $100+ 的伺服器費用
┌─────────────────────────────────────────┐
│ Presentation Layer │
│ (React Components + Next.js Pages) │
├─────────────────────────────────────────┤
│ Application Layer │
│ (Use Cases + Business Logic) │
├─────────────────────────────────────────┤
│ Domain Layer │
│ (Entities + Domain Services) │
├─────────────────────────────────────────┤
│ Infrastructure Layer │
│ (Supabase + OpenAI + External APIs) │
└─────────────────────────────────────────┘
負責用戶介面和互動,但不包含業務邏輯。
目錄結構:
app/
├── (auth)/ # 認證相關頁面
│ ├── login/
│ └── register/
├── (dashboard)/ # 主要應用頁面
│ ├── page.tsx # 首頁(記帳)
│ ├── timeline/ # 時間軸
│ ├── insights/ # 洞察報表
│ └── settings/ # 設定
├── components/ # 共用元件
│ ├── ui/ # 基礎 UI 元件
│ ├── features/ # 功能元件
│ └── layouts/ # 布局元件
└── hooks/ # Custom Hooks
設計原則:
協調領域層和基礎設施層,實現具體的使用案例。
目錄結構:
lib/
├── use-cases/ # 使用案例
│ ├── expenses/ # 支出相關
│ │ ├── quick-entry.ts
│ │ ├── categorize.ts
│ │ └── bulk-import.ts
│ ├── subscriptions/ # 訂閱相關
│ │ ├── identify.ts
│ │ ├── manage.ts
│ │ └── remind.ts
│ └── insights/ # 洞察相關
│ ├── generate-report.ts
│ └── analyze-pattern.ts
├── services/ # 應用服務
│ ├── auth.ts # 認證服務
│ ├── notification.ts
│ └── export.ts
└── dto/ # 資料傳輸物件
核心職責:
包含核心業務邏輯,與技術無關。
目錄結構:
domain/
├── entities/ # 領域實體
│ ├── expense.ts
│ ├── subscription.ts
│ ├── budget.ts
│ └── category.ts
├── value-objects/ # 值物件
│ ├── money.ts
│ ├── period.ts
│ └── confidence.ts
├── aggregates/ # 聚合根
│ ├── expense-aggregate.ts
│ └── subscription-aggregate.ts
├── services/ # 領域服務
│ ├── categorization.ts
│ └── budget-guardian.ts
└── events/ # 領域事件
├── expense-events.ts
└── subscription-events.ts
DDD 實踐要點:
所有外部系統的介面和實作。
目錄結構:
infrastructure/
├── supabase/ # Supabase 整合
│ ├── client.ts
│ ├── auth.ts
│ ├── database.ts
│ └── migrations/
├── ai/ # AI 服務
│ ├── openai.ts
│ ├── categorizer.ts
│ └── analyzer.ts
├── repositories/ # 資料存取
│ ├── expense.repo.ts
│ └── subscription.repo.ts
└── external/ # 第三方 API
├── telegram.ts
└── bank-api.ts
用戶輸入「星巴克 120」
↓
[Presentation] Input Component
↓
[Application] QuickEntryUseCase
↓
[Domain] ExpenseAggregate.create()
↓
[Infrastructure] AI Categorizer
↓
[Domain] Category.assign()
↓
[Infrastructure] [ExpenseRepository.save](http://ExpenseRepository.save)()
↓
[Application] NotificationService
↓
[Presentation] UI Update
Next.js App Router 的 Server Components 改變了資料流:
// app/(dashboard)/page.tsx
// 這在伺服器端執行,不會發送到客戶端
async function DashboardPage() {
// 直接在元件中 fetch 資料
const expenses = await getRecentExpenses()
const insights = await generateInsights(expenses)
// 只傳送 HTML 到客戶端
return (
<Dashboard
expenses={expenses}
insights={insights}
/>
)
}
優點:
利用 Supabase Realtime 實現即時同步:
訂閱建立 → Supabase Channel
↓
資料變更 → PostgreSQL Trigger
↓
事件廣播 → WebSocket
↓
客戶端更新 → React State
應用場景:
1. Server State(伺服器狀態)
2. Client State(客戶端狀態)
3. URL State(路由狀態)
URL State(篩選、排序、頁數)
↓
Server State(資料查詢)
↓
Client State(UI 互動)
避免的反模式:
AI Gateway Layer
├── Rate Limiting
├── Fallback Logic
└── Response Cache
↓
AI Services
├── Categorization Service
├── Pattern Recognition
└── Insight Generation
↓
Model Layer
├── OpenAI GPT-4
├── Local Fallback Rules
└── User Feedback Loop
// 三層分類策略
class CategorizationStrategy {
async categorize(expense: Expense): Promise<Category> {
// Layer 1: 用戶歷史規則
const userRule = await findUserRule(expense)
if (userRule?.confidence > 0.9) return userRule.category
// Layer 2: AI 預測
const aiPrediction = await openAI.categorize(expense)
if (aiPrediction.confidence > 0.7) return aiPrediction.category
// Layer 3: 預設規則
return applyDefaultRules(expense)
}
}
Request → Cache Check → AI Call → Cache Store
↓ ↓
Cache Hit Token Count
↓ ↓
Return Cache Cost Control
策略:
Layer 1: Edge Security (Vercel)
├── DDoS Protection
├── Rate Limiting
└── Geographic Restrictions
Layer 2: Application Security (Next.js)
├── CSRF Protection
├── Content Security Policy
└── Input Validation
Layer 3: API Security (Supabase)
├── Row Level Security
├── JWT Validation
└── API Key Management
Layer 4: Data Security
├── Encryption at Rest
├── Encryption in Transit
└── PII Masking
Supabase 的 RLS 確保資料隔離:
-- 用戶只能看到自己的支出
CREATE POLICY "Users can only see own expenses"
ON expenses FOR SELECT
USING (auth.uid() = user_id);
-- 防止跨用戶資料洩漏
CREATE POLICY "Users can only insert own expenses"
ON expenses FOR INSERT
WITH CHECK (auth.uid() = user_id);
L1: Browser Cache
├── Static Assets (永久快取)
├── API Responses (SWR)
└── Service Worker
L2: CDN Cache (Vercel Edge)
├── HTML Pages
├── API Routes
└── Images
L3: Database Cache
├── PostgreSQL Query Cache
├── Materialized Views
└── Connection Pool
監控點布局:
User Action → Performance Mark
↓
API Call → Timing Measure
↓
Database Query → Trace
↓
Response → Core Web Vitals
目標指標:
MVP (Now)
├── Vercel Hobby
├── Supabase Free
└── OpenAI Pay-as-you-go
Growth (1K users)
├── Vercel Pro
├── Supabase Pro
└── OpenAI with Cache
Scale (10K users)
├── Vercel Enterprise
├── Supabase Team
├── OpenAI + Self-hosted Models
└── Redis Cache Layer
Enterprise (100K+ users)
├── Multi-region Deployment
├── Database Sharding
├── Custom AI Infrastructure
└── Dedicated Support
雖然 MVP 不需要,但架構已預留:
Local Development
├── Next.js Dev Server
├── Supabase Local (Docker)
├── TypeScript Watch
└── Hot Module Replacement
Testing Environment
├── Unit Tests (Vitest)
├── Integration Tests (Playwright)
├── E2E Tests
└── Visual Regression
CI/CD Pipeline
├── GitHub Actions
├── Vercel Preview
├── Automatic Deploy
└── Rollback Support
// 從資料庫到前端的類型安全
Database Schema (Supabase)
↓
TypeScript Types (Generated)
↓
Zod Schemas (Runtime Validation)
↓
React Components (Type-safe Props)
1. Application Monitoring (Sentry)
- Error Tracking
- Performance Monitoring
- User Sessions
2. Infrastructure Monitoring (Vercel)
- Function Execution
- Edge Network
- Build Performance
3. Business Monitoring (Custom)
- User Behavior
- Feature Usage
- Conversion Funnel
4. AI Monitoring
- Token Usage
- Response Quality
- Cost Tracking
狀態: 採用
決策: 使用單一 repository
原因:
風險: 未來可能需要拆分
緩解: 保持模組邊界清晰
狀態: 延遲
決策: 保持 Monolithic 架構
原因:
未來: 當 DAU > 10K 時重新評估
狀態: 採用
決策: 使用關聯式資料庫
原因:
補充: JSONB 欄位提供彈性
這些是我知道但故意延後的:
## Technical Debt Registry
| ID | Description | Impact | Effort | Priority |
|----|------------|--------|--------|----------|
| TD-001 | No message queue | Medium | High | P2 |
| TD-002 | Simple error handling | Low | Medium | P3 |
| TD-003 | No rate limiting | High | Low | P1 |
今天設計的架構不是終點,而是起點。好的架構應該:
最重要的是:架構服務於業務,而非相反。
Day 17 - 智慧記帳 Day 6:核心功能開發日
今天打好了地基,明天開始蓋房子!