Files
momentry_core/docs/USER_MANAGEMENT_PLAN.md
accusys 383201cacd feat: Initial v0.9 release with API Key authentication
## v0.9.20260325_144654

### Features
- API Key Authentication System
- Job Worker System
- V2 Backup Versioning

### Bug Fixes
- get_processor_results_by_job column mapping

Co-authored-by: OpenCode
2026-03-25 14:53:41 +08:00

14 KiB
Raw Blame History

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

項目 內容
建立者 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+ 內建功能,無需額外插件。

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

使用方式

# 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

# 取得用戶列表(需要 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

-- 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 表結構

-- 新增欄位
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 中介層設計

// 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 端點

// 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 video_uuid = state.db.create_video(req, Some(ctx.user_id)).await?;
    
    // 建立 processing job帶 user_id
    state.db.create_monitor_job(
        job_type: "auto_ingestion",
        video_uuid,
        user_id: Some(ctx.user_id),
        processors: vec!["asr", "cut", "yolo", "ocr", "face", "pose"],
    ).await?;
    
    Ok(Json(RegisterResponse { uuid: video_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 更新

# /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/PENDING_ISSUES.md 待解決問題追蹤
docs/API_KEY_MANAGEMENT.md API Key 管理系統
docs/API_REFERENCE.md API 端點參考
docs/SFTPGO_DEMO_USER.md SFTPGo 用戶設定
docs/N8N_INTEGRATION_GUIDE.md n8n 整合指南
docs/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