---
document_type: "architecture_design"
service: "MOMENTRY_CORE"
title: "統一會員系統 + 影片歸屬追蹤實作計畫"
date: "2026-03-24"
version: "V1.0"
status: "active"
owner: "Warren"
created_by: "OpenCode"
tags:
  - "影片歸屬追蹤實作計畫"
  - "統一會員系統"
ai_query_hints:
  - "查詢 統一會員系統 + 影片歸屬追蹤實作計畫 的內容"
  - "統一會員系統 + 影片歸屬追蹤實作計畫 的主要目的是什麼？"
  - "如何操作或實施 統一會員系統 + 影片歸屬追蹤實作計畫？"
---

# 統一會員系統 + 影片歸屬追蹤實作計畫

| 項目 | 內容 |
|------|------|
| 建立者 | Warren |
| 建立時間 | 2026-03-24 |
| 文件版本 | V1.0 |
| 狀態 | 待確認 |

---

## 版本歷史

| 版本 | 日期 | 目的 | 操作人 |
|------|------|------|--------|
| V1.0 | 2026-03-24 | 創建實作計畫 | OpenCode |

---

## 1. 背景與目標

### 1.1 現有問題

目前 Momentry 生態系統中，各服務有獨立的用戶管理：

| 服務 | 用戶系統 | 問題 |
|------|----------|------|
| WordPress | wp_users (2 admin) | 無會員系統，無 API 認證 |
| SFTPGo | users 表 (3 users) | 獨立管理 |
| n8n | users 表 | 獨立管理 |
| Gitea | `user` 表 | 獨立管理 |
| Momentry Core | api_keys (未啟用) | 無 user 關聯 |

**問題**：
1. 無法追蹤影片歸屬（誰上傳的影片）
2. 無法實作 per-user 配額管理
3. API 端點全部公開，無認證
4. 用戶創建需要多處操作

### 1.2 目標

建立統一的會員系統，讓 WordPress 成為唯一登入入口：

```
┌─────────────────────────────────────────────────────────────────┐
│                         目標架構                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│    WordPress (會員系統)                                          │
│         │                                                        │
│         ├─► SFTPGo (檔案上傳)                                  │
│         ├─► Momentry Core (影片處理)                             │
│         └─► n8n (自動化流程)                                    │
│                                                                 │
│    統一的 user_id 追蹤                                          │
│         │                                                        │
│         └─► videos 表關聯 user_id                               │
│         └─► monitor_jobs 表關聯 user_id                         │
│         └─► per-user 配額管理                                    │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

---

## 2. 現有系統分析

### 2.1 WordPress

| 項目 | 狀態 |
|------|------|
| 安裝插件 | Elementor, Akismet, Code Snippets, All-in-One WP Migration |
| 用戶表 | wp_users (2 users: wp_user, sc_demo) |
| 會員插件 | 無 |
| REST API | 標準端點 (`/wp-json/wp/v2/users`) |
| 認證方式 | Cookie / Application Passwords |
| JWT | 無 |

### 2.2 SFTPGo

| 項目 | 值 |
|------|-----|
| 用戶數 | 3 (demo, warren, momentry) |
| API | REST API v2 (`/api/v2/users`) |
| Admin | admin:Test3200Test3200 |
| Hook | `/Users/accusys/sftpgo_test/register_hook.sh` |

### 2.3 Momentry Core

| 項目 | 狀態 |
|------|------|
| api_keys 表 | 已存在 |
| users 表 | 不存在 |
| videos.user_id | 不存在 |
| API 認證 | 未啟用（所有端點公開） |

---

## 3. 實作計畫

### Phase 1: WordPress 認證機制啟用

#### 1.1 啟用 Application Passwords

**WordPress 5.6+ 內建功能**，無需額外插件。

```php
// wp-config.php (如需自訂設定)
define('WP APPLICATION_PASSWORDS_ENABLED', true);
```

**使用方式**：
```bash
# Basic Auth 格式
curl -X POST "https://wp.momentry.ddns.net/wp-json/wp/v2/users" \
  -u "username:application_password" \
  -H "Content-Type: application/json" \
  -d '{"username": "newuser", "email": "user@example.com", "password": "password"}'
```

#### 1.2 測試 WordPress REST API

```bash
# 取得用戶列表（需要 admin 權限）
curl -s -u "wp_user:xxxx xxxx xxxx xxxx xxxx xxxx" \
  "https://wp.momentry.ddns.net/wp-json/wp/v2/users"

# 創建新用戶
curl -X POST "https://wp.momentry.ddns.net/wp-json/wp/v2/users" \
  -u "wp_user:xxxx xxxx xxxx xxxx xxxx xxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "username": "testuser",
    "email": "test@example.com",
    "password": "TestPass123!",
    "roles": ["subscriber"]
  }'
```

---

### Phase 2: 資料庫結構調整

#### 2.1 新增 users 表（Momentry Core）

```sql
-- migrations/002_user_management.sql

CREATE TABLE users (
    id BIGSERIAL PRIMARY KEY,
    wordpress_id BIGINT UNIQUE NOT NULL,
    username VARCHAR(60) NOT NULL,
    email VARCHAR(100) NOT NULL,
    api_key_hash VARCHAR(64),
    quota_size BIGINT DEFAULT 10737418240,  -- 10GB
    quota_used BIGINT DEFAULT 0,
    sftpgo_username VARCHAR(60),
    status VARCHAR(20) DEFAULT 'active',  -- active, suspended, deleted
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX idx_users_wordpress_id ON users(wordpress_id);
CREATE INDEX idx_users_username ON users(username);

-- videos 表新增 user_id
ALTER TABLE videos ADD COLUMN user_id BIGINT REFERENCES users(id);
CREATE INDEX idx_videos_user_id ON videos(user_id);

-- monitor_jobs 表新增 user_id
ALTER TABLE monitor_jobs ADD COLUMN user_id BIGINT REFERENCES users(id);
CREATE INDEX idx_monitor_jobs_user_id ON monitor_jobs(user_id);

-- api_keys 表新增 user_id
ALTER TABLE api_keys ADD COLUMN user_id BIGINT REFERENCES users(id);
```

#### 2.2 更新 api_keys 表結構

```sql
-- 新增欄位
ALTER TABLE api_keys ADD COLUMN user_id BIGINT REFERENCES users(id);
ALTER TABLE api_keys ADD COLUMN wordpress_id BIGINT;
ALTER TABLE api_keys ADD COLUMN sftpgo_username VARCHAR(60);
```

---

### Phase 3: API 認證中介層

#### 3.1 中介層設計

```rust
// src/api/middleware/auth.rs

#[derive(Clone)]
pub struct AuthState {
    pub db: Arc<PostgresDb>,
    pub cache: Arc<RedisCache>,
}

pub async fn auth_middleware(
    req: Request,
    next: Next,
    state: AuthState,
) -> Result<Response, StatusCode> {
    // 1. 從 Header 提取 API Key
    //    Header: X-API-Key: muser_xxx
    //    或: Authorization: Bearer muser_xxx
    
    // 2. 驗證並取得 user_id
    let user_id = validate_api_key(&req, &state).await?;
    
    // 3. 附加到 request extensions
    req.extensions_mut().insert(UserContext { user_id });
    
    // 4. 執行 handler
    next.call(req).await
}

#[derive(Clone)]
pub struct UserContext {
    pub user_id: i64,
}
```

#### 3.2 API Key 格式更新

```
新格式: muser_{uuid}_{timestamp}_{random}_{user_id_hash}
```

| 欄位 | 說明 |
|------|------|
| 前綴 | `muser_` = User 類型 |
| uuid | 唯一識別碼 |
| timestamp | 創建時間戳 |
| random | 隨機字串 |
| user_id_hash | 壓縮的 user_id |

---

### Phase 4: 更新 Register API

#### 4.1 修改 register 端點

```rust
// POST /api/v1/register
pub async fn register(
    State(state): State<ApiState>,
    Json(req): Json<RegisterRequest>,
    Extension(ctx): Extension<UserContext>,  // 新增
) -> Result<Json<RegisterResponse>, StatusCode> {
    // ... 現有邏輯 ...
    
    // 驗證用戶配額
    let user = state.db.get_user(ctx.user_id).await?;
    if user.quota_used + file_size > user.quota_size {
        return Err(StatusCode::FORBIDDEN);
    }
    
    // 關聯 user_id 到影片
    let file_uuid = state.db.create_video(req, Some(ctx.user_id)).await?;
    
    // 建立 processing job（帶 user_id）
    state.db.create_monitor_job(
        job_type: "auto_ingestion",
        file_uuid,
        user_id: Some(ctx.user_id),
        processors: vec!["asr", "cut", "yolo", "ocr", "face", "pose"],
    ).await?;
    
    Ok(Json(RegisterResponse { uuid: file_uuid }))
}
```

---

### Phase 5: n8n 自動化流程

#### 5.1 用戶註冊 Workflow

```
┌─────────────────────────────────────────────────────────────────┐
│              WordPress 用戶註冊自動化流程                         │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  Trigger: Webhook (或 WordPress Plugin)                         │
│                                                                 │
│  Step 1: 驗證管理員權限                                         │
│           └─► 檢查 WordPress REST API 憑證                       │
│                                                                 │
│  Step 2: 在 Momentry Core 建立用戶記錄                           │
│           └─► POST /api/v1/admin/users                          │
│           └─► 產生 API Key                                       │
│                                                                 │
│  Step 3: 在 SFTPGo 建立用戶                                      │
│           └─► POST /api/v2/users (SFTPGo API)                   │
│           └─► 設定 home_dir: /data/{username}                   │
│                                                                 │
│  Step 4: 更新用戶記錄                                           │
│           └─► 關聯 sftpgo_username                              │
│                                                                 │
│  Step 5: 發送歡迎 email                                         │
│           └─► 包含 SFTP 登入資訊                                │
│           └─► 包含 API Key                                      │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘
```

#### 5.2 SFTPGo Hook 更新

```bash
# /Users/accusys/sftpgo_test/register_hook.sh

# 修改為傳遞 user_id
curl -X POST "http://localhost:3002/api/v1/register" \
  -H "X-API-Key: ${SFTPGO_USER_API_KEY}" \
  -H "X-SFTPGo-User: ${SFTPGO_USERNAME}" \
  -d "{\"path\": \"${SFTPGO_FILE_PATH}\"}"
```

---

## 4. 實作優先順序

| Phase | 任務 | 複雜度 | 優先級 | 預估工時 |
|-------|------|--------|--------|----------|
| 1.1 | 測試 WordPress Application Passwords | 低 | P0 | 1h |
| 1.2 | 為 WordPress 產生 Application Password | 低 | P0 | 0.5h |
| 2.1 | 建立 users 表 migration | 中 | P0 | 2h |
| 2.2 | 更新 videos, monitor_jobs 表 | 低 | P0 | 1h |
| 3.1 | 實作 API auth middleware | 中 | P0 | 4h |
| 3.2 | 更新 register API 接受 user_id | 低 | P0 | 2h |
| 4 | 建立 admin users API | 中 | P1 | 4h |
| 5.1 | 建立 n8n 用戶註冊 workflow | 中 | P1 | 6h |
| 5.2 | 更新 SFTPGo hook | 低 | P1 | 2h |
| 6 | 實作配額管理 | 中 | P2 | 4h |
| 7 | 測試與驗證 | 中 | P2 | 4h |

**總預估工時**: ~30.5h

---

## 5. 待確認事項

### 5.1 WordPress 用戶建立方式

- [ ] 手動在 wp-admin 建立？還是透過 Elementor 表單？
- [ ] 是否需要 email 驗證？
- [ ] 初始角色設定（subscriber / contributor）？

### 5.2 API Key 格式

- [ ] 維持現有 `muser_` 前綴格式？
- [ ] 還是建立新的用戶專用 key 格式？
- [ ] 是否需要 JWT token？

### 5.3 SFTPGo 整合

- [ ] 每個 WordPress 用戶對應一個 SFTPGo 用戶？
- [ ] home_dir 命名規則？（如 `data/{wordpress_username}`）
- [ ] SFTPGo 配額是否同步？

### 5.4 配額管理

- [ ] 每人預設 10GB 空間？
- [ ] 超出配額如何處理？（阻止上傳 / 警告）
- [ ] 配額用完後是否暫停 SFTPGo 用戶？

### 5.5 資料同步

- [ ] WordPress 用戶刪除時是否同步刪除其他系統？
- [ ] 用戶停權時的處理流程？

---

## 6. 參考文件

### 內部文件

| 文件 | 用途 |
|------|------|
| `docs_v1.0/REFERENCE/PENDING_ISSUES.md` | 待解決問題追蹤 |
| `docs_v1.0/REFERENCE/API_KEY_MANAGEMENT.md` | API Key 管理系統 |
| `docs_v1.0/REFERENCE/API_REFERENCE.md` | API 端點參考 |
| `docs_v1.0/IMPLEMENTATION/SFTPGO_DEMO_USER.md` | SFTPGo 用戶設定 |
| `docs_v1.0/IMPLEMENTATION/N8N_INTEGRATION_GUIDE.md` | n8n 整合指南 |
| `docs_v1.0/IMPLEMENTATION/INSTALL_WORDPRESS.md` | WordPress 安裝指南 |

### 外部資源

| 資源 | URL |
|------|-----|
| WordPress REST API | https://developer.wordpress.org/rest-api/ |
| WordPress Application Passwords | https://developer.wordpress.org/rest-api/using-the-rest-api/authentication/#authentication-plugins |
| SFTPGo REST API | https://docs.sftpgo.com/latest/rest-api/ |

---

## 7. 附錄

### A. 現有使用者資料

#### WordPress (wp_users)
| ID | user_login | user_email | display_name |
|----|------------|------------|--------------|
| 1 | wp_user | marketing@accusys.com.tw | wp_user |
| 2 | sc_demo | susan.cheng@accusys.com.tw | Susan Cheng |

#### SFTPGo (users)
| username | email | home_dir | status |
|----------|-------|----------|--------|
| demo | demo@momentry.local | /Users/accusys/momentry/var/sftpgo/data/demo | Active |
| warren | warren@momentry.local | /Users/accusys/momentry/var/sftpgo/data/warren | Active |
| momentry | system@momentry.local | /Users/accusys/momentry/var/sftpgo/data/momentry | Active |

### B. 服務端口

| 服務 | Port | URL |
|------|------|-----|
| WordPress | 9000 (PHP-FPM) | https://wp.momentry.ddns.net |
| SFTPGo | 8080 | http://localhost:8080 |
| Momentry API | 3002 | http://localhost:3002 |
| n8n | 5678 | http://localhost:5678 |
