---
document_type: "spec"
service: "MOMENTRY_CORE"
title: "UUID Encoding Rules V1.0"
date: "2026-05-05"
version: "V1.0"
status: "design"
owner: "Warren"
created_by: "OpenCode"
tags:
  - "momentry"
  - "core"
  - "uuid"
  - "encoding"
  - "v1.0"
ai_query_hints:
  - "UUID encoding rules for identities, files, resources, jobs"
  - "Deterministic UUID v5 for cross-system identity matching"
  - "file_uuid 32-char birth UUID (hash of MAC+time+path+name)"
  - "identity_uuid 32-char stripped UUIDv5"
related_documents:
  - "../DUAL_EMBEDDING_PIPELINE_V1.0.0.md"
  - "../CHUNK_DEFINITION_V1.0.0.md"
---

# UUID Encoding Rules V1.0

## 目的

統一系統內所有資源的 UUID 編碼規則，確保跨系統不衝突、可追溯、無語意歧義。

## 各資源 UUID 規則

| 資源 | 欄位 | 產生方式 | 長度 | 編碼意義 |
|------|------|---------|------|---------|
| **File** | `file_uuid` | Birth UUID: `SHA256(MAC + registration_time + canonical_path + filename)` | 32 | MAC + 時間 + 路徑 + 檔名 → 內容相同但不同機器/時間仍不同 |
| **Identity** | `identity_uuid` | UUIDv5: `UUIDv5(NS, source:external_id)` | 32 | source + external_id → 跨系統唯一確定 |
| **Job** | `job_uuid` | UUIDv4 random | 32 | 每次執行獨立 |
| **Resource** | `resource_uuid` | UUIDv5: `UUIDv5(NS, hostname:resource_id)` | 32 | hostname + resource_id → 同主機同 ID 不變 |

## Identity UUIDv5 編碼規則

### 意義

`identity_uuid` = source + external_id 的確定性映射。  
同一來源系統的同一外部 ID → 永遠相同 UUID。  
跨系統合併 identity 時不衝突。

### Namespace

```
MOMENTRY_IDENTITY_NS = "6ba7b810-9dad-11d1-80b4-00c04fd430c8"  // Standard DNS namespace
```

### Source-specific encoding

| Source | External ID | UUIDv5 Input | 碰撞機率 |
|--------|------------|-------------|---------|
| `tmdb` | `"285"` (person_id) | `"tmdb:285"` | 0（同 source 同 id 同 UUID） |
| `manual` | user-assigned name | `"manual:Cary Grant"` | 0（同名同 source） |
| `face_cluster` | `file_uuid + cluster_id` | `"cluster:384b0ff...:cluster_0"` | 極低（跨 file） |

### 優點

1. **跨系統確定性**：無論哪台機器、哪次執行，同一個 TMDb actor 永遠拿到相同 UUID
2. **合併安全**：兩套系統產生的 identity 集合可以直接合併，UUID 不衝突
3. **可追溯**：從 UUID 本身無法反推 source（單向 hash），但透過 DB metadata 查得到來源
4. **零碰撞**：不同 source + different external_id → different UUID

### 現有資料遷移

```
1. 讀取所有 identities
2. 計算 UUIDv5("tmdb:{tmdb_id}") 為新的 identity_uuid
3. 手動註冊的 identities 用 UUIDv5("manual:{name}")
4. 更新 face_detections.identity_id 指向新 UUID
5. 更新 chunks metadata
```

## File UUID (保持不變)

File UUID = `SHA256(MAC + registration_time + canonical_path + filename)` 的前 128 bits，32 hex chars。  
跨系統不變（同檔案不同機器註冊，UUID 不同但可追溯）。**不更改。**

## Job UUID (升級)

目前用 `INTEGER auto-increment`（單機安全，多機碰撞）。  
改為 `UUIDv4`（32 hex），支援多機 worker 並行。

## Resource UUID (新增)

目前用 `resource_id` 字串（任意）。  
改為 `UUIDv5(namespace, hostname:resource_id)`（32 hex），支援多機註冊不碰撞。

### Resource 分類

| 類別 | resource_type | 說明 | 目前實例 |
|------|--------------|------|---------|
| `compute` | worker, server | 運算節點 | momentry_playground worker/server |
| `storage` | postgres, mongodb, redis, qdrant, mariadb | 資料儲存 | localhost 服務 |
| `ai` | ollama, llama_cpp, embedding | AI/ML 推理服務 | Ollama serve, llama-server |
| `proxy` | caddy, sftpgo | 反向代理/檔案服務 | Caddy, SFTPGo |
| `web` | wordpress, php-fpm | 前端 portal | WordPress |
| `external` | tmdb, n8n | 外部 API 整合 | TMDb API, n8n |

### Resource 生命週期欄位

| 欄位 | 型別 | 說明 | 範例 |
|------|------|------|------|
| `resource_uuid` | 32 hex | UUIDv5 唯一識別 | `a4f288...` |
| `resource_type` | enum | compute/storage/ai/proxy/external | `ai` |
| `resource_subtype` | string | ollama, llama_cpp, postgres... | `ollama` |
| `hostname` | string | 執行主機 | `mac-studio.local` |
| `port` | int | service port | `11434` |
| `started_at` | timestamp | 啟動時間 | `2026-05-05T10:00:00Z` |
| `stopped_at` | timestamp | 停止時間 (NULL=運行中) | `NULL` |
| `config` | jsonb | 執行參數/環境設定 | `{"model":"nomic-embed-text-v2-moe","dim":768}` |
| `install_source` | string | 安裝來源 | `homebrew`, `docker`, `binary`, `source` |
| `install_path` | string | 安裝路徑 | `/opt/homebrew/opt/ollama` |
| `location` | string | 實體位置/網路位置 | `localhost`, `rackserver-01` |
| `status` | enum | running/stopped/error/unknown | `running` |

### 目前 service 實例

| resource_type | subtype | port | license | 商用 |
|--------------|---------|------|---------|------|
| ai | ollama | 11434 | MIT | ✅ |
| ai | llama_cpp | 8081 | MIT | ✅ |
| storage | postgres | 5432 | PostgreSQL | ✅ |
| storage | mongodb | 27017 | SSPL v1 | ⚠️ 非 OSI 開源。內部使用不受限制，不可轉售為 DB 服務 |
| storage | redis | 6379 | RSALv2 / SSPL | ⚠️ 7.4+ 雙授權。內部使用不受限制，不可轉售為雲端服務 |
| storage | qdrant | 6333 | Apache 2.0 | ✅ |
| proxy | caddy | 443 | Apache 2.0 | ✅ |
| proxy | sftpgo | 8080 | AGPL-3.0 | ⚠️ 網路服務觸發 copyleft。未修改原始碼風險較低，商用建議評估替代方案 |

### sftpgo 替代方案

sftpgo 提供 SFTP + HTTP file serve + Web UI + user management。可依需求分層替代：

| 功能 | 替代方案 | License | 說明 |
|------|---------|---------|------|
| HTTP file serve | **Caddy** `file_server` | Apache 2.0 ✅ | 已運行中。一行 config 即可提供目錄服務 |
| WebDAV | **Caddy** `webdav` plugin | Apache 2.0 ✅ | 如需 WebDAV 掛載 |
| SFTP protocol | **OpenSSH** `internal-sftp` | MIT ✅ | macOS 內建，無需額外安裝 |
| User management | **Caddy** `basicauth` | Apache 2.0 ✅ | 基本 auth 已夠用 |
| Web admin UI | 不需要 | — | 若只需 file serve，Web UI 非必要 |

**建議**：先用 Caddy `file_server` 取代 HTTP 端，SFTP 用 OpenSSH。sftpgo 可在商用授權前逐步退役。Caddy 已處理 TLS、reverse proxy、basic auth，不需要 sftpgo 的重複功能。

```caddyfile
# 範例：Caddy 替代 sftpgo file serve，含 user 管制
files.momentry.ddns.net {
    root * /Users/accusys/momentry/var/sftpgo/data
    
    # 管制方式三選一：
    
    # 1. Basic Auth（最簡單）
    basicauth {
        demo $2a$14$hashed_password_here
    }
    
    # 2. JWT Token（via forward_auth）
    # forward_auth localhost:9001 {
    #     uri /api/v1/auth/verify
    #     copy_headers Authorization
    # }
    
    # 3. IP Whitelist（內網 only）
    # @allowed remote_ip 192.168.1.0/24 127.0.0.1
    
    file_server browse
    import common_log sftpgo_access
}
```

### User 管制方式比較

| 方式 | 複雜度 | 適用場景 |
|------|--------|---------|
| **basicauth** | 低 | 少數固定 user，密碼 hash 存在 config |
| **forward_auth** | 中 | 由 momentry API 統一驗證 token |
| **IP whitelist** | 低 | 內網服務，不開放外部 |
| compute | worker | — | MIT | ✅ |
| compute | server | 3002/3003 | MIT | ✅ |
| external | tmdb | — | TMDb ToS | ⚠️ 替代方案：手動上傳、自有演員資料庫 |
| external | n8n | 5678 | Sustainable Use | ⚠️ 商用需付費 |
| web | wordpress | 80/443 | GPL-2.0 | ✅ portal 前端 |
| storage | mariadb | 3306 | GPL-2.0 | ✅ WordPress DB 後端 |
| web | wordpress | 443 (caddy) | GPLv2 | ✅ |
| web | php | 9000 (php-fpm) | PHP License | ✅ |
| storage | mariadb | 3306 | GPLv2 | ✅ |

### Log 路徑

每個 service 的 log 位於 `/Users/accusys/momentry/var/{service}/log/`：

| service | stdout log | error log |
|---------|-----------|-----------|
| sftpgo | `var/sftpgo/log/stdout.log` | `var/sftpgo/log/stderr.log` |
| n8n | `var/n8n/n8n-main.log` | `var/n8n/n8n-main-error.log` |
| mariadb | `var/mariadb/ddl_recovery.log` | `var/mariadb/tc.log` |

momentry core 本身（playground / production）目前 log 到 `/tmp/`（開發）或 systemd journal（生產）。應統一遷移到：

| 環境 | Port | Log 目錄 |
|------|------|---------|
| dev | 3003 | `/Users/accusys/momentry/log/dev/` |
| public (production) | 3002 | `/Users/accusys/momentry/log/public/` |

每個環境下的 log 命名：
```
momentry/log/dev/
  ├── momentry.log        # API server stdout
  ├── momentry.error.log  # API server stderr
  ├── worker.log          # Worker stdout
  ├── worker.error.log    # Worker stderr
  ├── processor/
  │   ├── face.log        # Face processor output
  │   └── asr.log         # ASR processor output
  └── agent/
      ├── story.log
      └── identity.log

momentry/log/public/
  └── (same structure)
```

### 隔離原則

| 規則 | 說明 |
|------|------|
| 永不交叉 | dev log 不寫入 public，反之亦然 |
| 環境識別 | 從 log 路徑即可判斷來源環境 |
| 獨立 rotation | 各自獨立的 logrotate 規則 |
| 清除安全 | 清除 dev log 不影響 public |

## URL Path 規範

所有 UUID 在 URL 中使用 **32-char hex（無 dash）** 格式：

```
GET /api/v1/files/384b0ff44aaaa1f14cb2cd63b3fea966        ← file
GET /api/v1/identities/3f5d1e09ce86c27aa631162052ec9c97    ← identity
GET /api/v1/jobs/942d0bdf5d6fb6ac18b47deb031e60c3          ← job
```

### 為何 strip dash

1. **一致**：file_uuid 為 32 hex（無 dash），統一風格
2. **短**：URL 從 36 → 32 chars
3. **容錯**：input 端兩種格式都接受，output 端統一 strip

## 設計說明

### File UUID 為何用 Birth UUID 而非 Content Hash

Content hash（MD5/SHA256 of file content）適用於「相同內容 = 相同檔案」的場景。但 momentry 的情境是：
- 同一影片可能有不同 cut 版本（廣告、預告、完整版）
- 同一影片在不同機器上註冊應區分（追蹤來源）
- 需要追溯「哪台機器在何時註冊了哪個檔案」

因此用 Birth UUID = `SHA256(MAC + time + path + filename)`，而非 content hash。

### Identity 第一參考面取得

TMDb 只是取得第一張參考照片的 **手段之一**，不是唯一來源：

```
1. TMDb (或其他來源) → 下載照片
2. 提取 face embedding → 寫入 identities.face_embedding
3. 刪除照片（不留原始檔案）
4. 用這個 embedding 找到第一個 matching video trace
5. 從 video trace 中取 3 個最佳影片臉 → 取代外部 embedding → 成為 identity reference
```

之後 identity reference 全部來自影片臉，不再依賴外部照片。

**⚠️ TMDb 商用授權**：TMDb API 有商用限制。若產品上線需處理授權，或改用替代方案：
1. 手動上傳參考照片
2. 跨檔案 identity merge（從已有 traces 取 reference）
3. 自有演員資料庫

跨系統合併 identity 時，需要知道「TMDb actor 285」在不同系統上是否為同一個人。UUIDv5 提供確定性映射：
- `tmdb:285` → 永遠是 `cc6b8c2569ff5dec8f9e33164c7756b3`
- 任何系統、任何時間計算都得到相同結果
- 不需要 central registry，mathematically guaranteed

### 現有資料遷移策略

Identity UUID 遷移非破壞性：舊 UUID 保留在 `metadata.legacy_uuid`，新 UUID 寫入 `identities.uuid`。向下相容查詢。

## UUID 與獨立工作空間

每個資源的 working space、輸入、產出各自獨立，互不汙染：

| 資源 | UUID | Working Space | 輸入 | 產出 |
|------|------|--------------|------|------|
| **File** | `file_uuid` | `output_dev/{uuid}/` | `{video_path}` | `{uuid}.cut.json, .asr.json, .face.json, ...` |
| **Identity** | `identity_uuid` | `dev.identities` table | face_detections, voice_embeddings, TMDb API, manual input | `identities.face_embedding`, `identities.voice_embedding`, `identity_bindings`, `file_identities` |
| **Job** | `job_uuid` | `dev.monitor_jobs` + `dev.processor_results` | `processors[]` list | `processor_results.status`, log entries |
| **Resource** | `resource_uuid` | `var/{resource}/log/` | config, exec_path | log files, heartbeat records |

File 的工作空間在 filesystem，Identity/Job/Resource 在 DB。各自目錄/table 獨立，刪除一個不影響其他。

## Dev / Public 完整隔離表

| 資源 | dev | public |
|------|-----|--------|
| DB Schema | `dev.*` | `public.*` |
| Qdrant | `momentry_dev_*` | `momentry_*` |
| Redis prefix | `momentry_dev:` | `momentry:` |
| Output dir | `output_dev/` | `output/` |
| Log | `log/dev/` | `log/public/` |
| Resource UUID | `UUIDv5(hostname:xxx_dev)` | `UUIDv5(hostname:xxx)` |
| Port | 3003 | 3002 |
| .env file | `.env.development` | `.env` |

## 版本歷史

| 版本 | 日期 | 變更 |
|------|------|------|
| V1.0 | 2026-05-05 | Book UUID (file), UUIDv5 (identity), UUIDv4 (job), UUIDv5 (resource)。Resource 分類與生命週期。 |