docs: update docs_v1.0/ documentation
- Fix markdown lint issues (MD030, MD047, MD051, MD028, MD005) - Update AI agents, architecture, implementation docs - Add new identity, face recognition, and API documentation - Remove deprecated face/person API guides
This commit is contained in:
710
docs_v1.0/design/OBJECT_SNAPSHOT_SYSTEM_DESIGN.md
Normal file
710
docs_v1.0/design/OBJECT_SNAPSHOT_SYSTEM_DESIGN.md
Normal file
@@ -0,0 +1,710 @@
|
||||
---
|
||||
document_type: "design"
|
||||
service: "MOMENTRY_CORE"
|
||||
title: "物件快照儲存與產生系統設計"
|
||||
date: "2026-04-30"
|
||||
status: "active"
|
||||
current_state: "approved"
|
||||
owner: "Warren"
|
||||
created_by: "OpenCode"
|
||||
created_at: "2026-04-30"
|
||||
version: "V1.1"
|
||||
tags:
|
||||
- "snapshot"
|
||||
- "storage"
|
||||
- "api"
|
||||
- "agent"
|
||||
- "cache"
|
||||
- "file-centric"
|
||||
- "redis"
|
||||
- "hot-warm-cold"
|
||||
ai_query_hints:
|
||||
- "查詢 物件快照儲存系統設計 的內容"
|
||||
- "快照系統的主要目的是什麼?"
|
||||
- "如何操作或實施 快照系統?"
|
||||
- "快照儲存在哪裡?"
|
||||
- "快照 API 有哪些 endpoints?"
|
||||
- "如何避免快照重複產生?"
|
||||
- "快照快取機制設計"
|
||||
- "dot folder 掃描排除規則"
|
||||
- "Snapshot Agent 實作計畫"
|
||||
- "Redis TTL 快取生命週期管理"
|
||||
- "熱溫冷快照分層策略"
|
||||
related_documents:
|
||||
- "FILE_UUID_SPEC.md"
|
||||
- "STANDARDS/DOCS_STANDARD.md"
|
||||
- "AI_AGENTS/CORE/AGENT_SPEC.md"
|
||||
---
|
||||
|
||||
# 物件快照儲存與產生系統設計
|
||||
|
||||
| 項目 | 內容 |
|
||||
|------|------|
|
||||
| 建立者 | OpenCode |
|
||||
| 建立時間 | 2026-04-30 |
|
||||
| 文件版本 | V1.1 |
|
||||
|
||||
---
|
||||
|
||||
## 版本歷史
|
||||
|
||||
| 版本 | 日期 | 目的 | 操作人 | 工具/模型 |
|
||||
|------|------|------|--------|-----------|
|
||||
| V1.0 | 2026-04-30 | 創建物件快照系統設計與實作計畫 | OpenCode | big-pickle |
|
||||
| V1.1 | 2026-04-30 | 更新快取機制、熱溫冷分層、Redis TTL 管理、遷移 Agent、Auto Tearing 預留 | OpenCode | big-pickle |
|
||||
|
||||
---
|
||||
|
||||
## 關鍵術語定義
|
||||
|
||||
| 術語 | 定義 |
|
||||
|------|------|
|
||||
| Snapshot | 物件截圖快照,包含臉部、商標、產品、文字區域等被識別物件的 JPEG 截圖 |
|
||||
| File-Level Snapshot | 與單一 file_uuid 綁定的快照,來源於處理器檢測結果 |
|
||||
| Identity-Level Snapshot | 與全域 identity_uuid 綁定的快照,跨檔案關聯 |
|
||||
| Dot Folder | 以 `.` 開頭的隱藏目錄,用於存放快照,避免被掃描機制當成需註冊檔案 |
|
||||
| Snapshot Agent | 獨立處理器,按需產生快照截圖,處理遷移邏輯 |
|
||||
| Temp/Cache | 快照性質為運作時快取,可被清除並重新產生 |
|
||||
| Hot/Warm/Cold | 快照存取頻率分層,用於決定遷移與保留策略 |
|
||||
| Auto Tearing | 系統根據存取模式自動拆除不再需要的快照快取 |
|
||||
|
||||
---
|
||||
|
||||
## 概述
|
||||
|
||||
本文件定義 Momentry Core 的物件快照儲存與產生系統。
|
||||
|
||||
快照系統提供 GUI 呈現 (WordPress/Tauri Portal) 所需的物件截圖,包括臉部、商標、產品、OCR 文字區域等。快照儲存在 dot folder 中,避免被掃描機制誤判為需註冊檔案。快照按需產生,由獨立的 Snapshot Agent 負責處理。快取生命週期由 Redis TTL 管理,支援熱溫冷分層與自動遷移。
|
||||
|
||||
---
|
||||
|
||||
## 1. 檔案生命週期與快照關係
|
||||
|
||||
### 1.1 檔案物件儲存性質
|
||||
|
||||
原始檔案納管後是 object storage file 的性質,操作模式為:
|
||||
|
||||
| 動作 | 說明 |
|
||||
|------|------|
|
||||
| **納管 (註冊)** | `register` → 新 file_uuid → 產生快照 |
|
||||
| **Copy** | 複製檔案,但尚未註冊 |
|
||||
| **重新註冊** | Copy 後 `register` → 新 file_uuid → 快照可遷移或重新產生 |
|
||||
| **刪除** | 刪除原檔 (快照可選擇保留或清除) |
|
||||
|
||||
### 1.2 遷移模式
|
||||
|
||||
檔案遷移 = copy → 重新註冊 → 刪除原檔
|
||||
|
||||
```
|
||||
原檔 uuid_A → Copy → 新位置 → register → 新 uuid_B (parent_uuid = uuid_A) → 刪除原檔
|
||||
```
|
||||
|
||||
### 1.3 快照與 file_uuid 關係
|
||||
|
||||
| 規則 | 說明 |
|
||||
|------|------|
|
||||
| **快照與當前 file_uuid 綁定** | 每個 file_uuid 有獨立的快照目錄 |
|
||||
| **遷移後快照獨立** | uuid_B 的快照與 uuid_A 分開存放,不共用 |
|
||||
| **出生 uuid 追溯** | `parent_uuid` 記錄 lineage,用於身份追溯,不影響快照位置 |
|
||||
|
||||
---
|
||||
|
||||
## 2. 儲存架構
|
||||
|
||||
### 2.1 目錄結構
|
||||
|
||||
```
|
||||
{SFTPGO_DATA}/{user}/.momentry_snapshots/
|
||||
├── {file_uuid}/ # File-Level 快照
|
||||
│ ├── faces/
|
||||
│ │ ├── face_001.jpg
|
||||
│ │ ├── face_002.jpg
|
||||
│ │ └── ...
|
||||
│ ├── logos/
|
||||
│ │ └── logo_001.jpg
|
||||
│ ├── products/
|
||||
│ │ └── product_001.jpg
|
||||
│ └── ocr/
|
||||
│ └── ocr_001.jpg
|
||||
│
|
||||
└── identities/ # Identity-Level 快取 (Temp/Cache)
|
||||
└── {identity_uuid}/
|
||||
├── reference.jpg # 代表快照(最佳品質)
|
||||
└── faces/ # 該 identity 在不同檔案中的參考快照
|
||||
├── {file_uuid}_face_001.jpg
|
||||
└── {file_uuid}_face_002.jpg
|
||||
```
|
||||
|
||||
### 2.2 儲存位置說明
|
||||
|
||||
| 項目 | 路徑範例 | 說明 |
|
||||
|------|----------|------|
|
||||
| SFTPGO 資料目錄 | `/Users/accusys/momentry/var/sftpgo/data/` | SFTPGo 使用者家目錄的父層 |
|
||||
| 使用者目錄 | `{SFTPGO_DATA}/demo/` | 單一使用者的 SFTPGo 家目錄 |
|
||||
| 快照根目錄 | `{SFTPGO_DATA}/demo/.momentry_snapshots/` | dot folder,避免被掃描 |
|
||||
| File-Level | `{SFTPGO_DATA}/demo/.momentry_snapshots/{file_uuid}/` | 與 file_uuid 綁定 |
|
||||
| Identity-Level | `{SFTPGO_DATA}/demo/.momentry_snapshots/identities/{identity_uuid}/` | 全域身份快取 |
|
||||
|
||||
### 2.3 設計理念
|
||||
|
||||
| 概念 | 說明 |
|
||||
|------|------|
|
||||
| **User 隔離** | 每個 user 有自己的快照目錄,權限自然隔離 |
|
||||
| **Dot Folder** | `.momentry_snapshots/` 不被 scan,不會被當成需註冊檔案 |
|
||||
| **Temp/Cache** | 快照性質為運作時快取,可被清除,必要時重新產生 |
|
||||
| **Identity 快取** | Identity 是全域概念,但快照依 user 查找快取在該 user 下 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 快照類型
|
||||
|
||||
### 3.1 File-Level Snapshots
|
||||
|
||||
| 類型 | 來源 | 命名 | 說明 |
|
||||
|------|------|------|------|
|
||||
| `faces` | Face Processor | `face_{id}.jpg` | 檢測到的臉部截圖 |
|
||||
| `logos` | YOLO/Logo 檢測 | `logo_{id}.jpg` | 商標/品牌識別截圖 |
|
||||
| `products` | YOLO 物件檢測 | `product_{id}.jpg` | 產品/物件識別截圖 |
|
||||
| `ocr` | OCR Processor | `ocr_{chunk_id}.jpg` | 文字區域截圖 |
|
||||
|
||||
### 3.2 Identity-Level Snapshots (Temp/Cache)
|
||||
|
||||
| 檔案 | 說明 |
|
||||
|------|------|
|
||||
| `reference.jpg` | 該 identity 的最佳臉部截圖(用於展示/辨識) |
|
||||
| `faces/{file_uuid}_face_{id}.jpg` | 在不同檔案中的參考快照,帶有來源標記 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 存取設計
|
||||
|
||||
### 4.1 存取方式
|
||||
|
||||
| 存取者 | 方式 | 說明 |
|
||||
|--------|------|------|
|
||||
| **Momentry Core** | 本地寫入 | 處理器產生快照到對應 user 目錄 |
|
||||
| **WordPress (Portal/GUI)** | 本地路徑讀取 | 同一台機器直接讀取檔案路徑 |
|
||||
| **Portal (Tauri)** | 本地路徑或 API | 透過 `convertFileSrc()` 轉為可顯示 URL,或呼叫 API 取得路徑 |
|
||||
|
||||
### 4.2 權限設計
|
||||
|
||||
| 層級 | 說明 |
|
||||
|------|------|
|
||||
| **User 隔離** | 快照存在 user 的 dot folder 下,自然隔離 |
|
||||
| **無公開 URL** | 快照不透過公開 URL 存取,避免數據外洩 |
|
||||
| **API 認證** | Portal 透過 API 存取時需帶 API key |
|
||||
|
||||
---
|
||||
|
||||
## 5. API 設計
|
||||
|
||||
### 5.1 File Snapshots API
|
||||
|
||||
| Endpoint | Method | 認證 | 說明 |
|
||||
|----------|--------|------|------|
|
||||
| `/api/v1/files/:uuid/snapshots` | GET | API Key | 查詢快照狀態,若不存在則觸發產生 |
|
||||
| `/api/v1/files/:uuid/snapshots/status` | GET | API Key | 查詢快照產生進度 |
|
||||
| `/api/v1/files/:uuid/snapshots/generate` | POST | API Key | 手動觸發快照產生 |
|
||||
| `/api/v1/files/:uuid/snapshots/migrate` | POST | API Key | 從 parent_uuid 遷移快照 (由 Agent 處理) |
|
||||
|
||||
### 5.2 Identity Snapshots API
|
||||
|
||||
| Endpoint | Method | 認證 | 說明 |
|
||||
|----------|--------|------|------|
|
||||
| `/api/v1/identities/:uuid/snapshots` | GET | API Key | 查詢 identity 快照狀態 |
|
||||
| `/api/v1/identities/:uuid/snapshots/generate` | POST | API Key | 手動觸發 identity 快照產生 |
|
||||
|
||||
### 5.3 API 回應範例
|
||||
|
||||
#### File Snapshots Query (首次 - 觸發產生)
|
||||
|
||||
```json
|
||||
GET /api/v1/files/:uuid/snapshots
|
||||
{
|
||||
"file_uuid": "abc123",
|
||||
"snapshot_tier": "cold",
|
||||
"snapshot_hits": 0,
|
||||
"last_access": null,
|
||||
"snapshots": {
|
||||
"faces": { "status": "pending", "count": 0, "items": [] },
|
||||
"logos": { "status": "pending", "count": 0, "items": [] }
|
||||
},
|
||||
"message": "Snapshot generation triggered"
|
||||
}
|
||||
```
|
||||
|
||||
#### File Snapshots Query (產生中 - 輪詢)
|
||||
|
||||
```json
|
||||
GET /api/v1/files/:uuid/snapshots/status
|
||||
{
|
||||
"file_uuid": "abc123",
|
||||
"snapshot_tier": "cold",
|
||||
"snapshot_hits": 1,
|
||||
"last_access": "2026-04-30T10:00:00Z",
|
||||
"snapshots": {
|
||||
"faces": {
|
||||
"status": "generating",
|
||||
"progress": 60,
|
||||
"current_type": "faces",
|
||||
"items": [
|
||||
{ "id": "face_001", "status": "ready", "image_path": "/Users/.../demo/.momentry_snapshots/abc123/faces/face_001.jpg" }
|
||||
]
|
||||
},
|
||||
"logos": { "status": "pending", "count": 0, "items": [] }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### File Snapshots Query (完成)
|
||||
|
||||
```json
|
||||
GET /api/v1/files/:uuid/snapshots
|
||||
{
|
||||
"file_uuid": "abc123",
|
||||
"snapshot_tier": "hot",
|
||||
"snapshot_hits": 5,
|
||||
"last_access": "2026-04-30T12:00:00Z",
|
||||
"snapshots": {
|
||||
"faces": {
|
||||
"status": "ready",
|
||||
"count": 5,
|
||||
"items": [
|
||||
{
|
||||
"id": "face_001",
|
||||
"confidence": 0.95,
|
||||
"timestamp": 12.5,
|
||||
"image_path": "/Users/accusys/momentry/var/sftpgo/data/demo/.momentry_snapshots/abc123/faces/face_001.jpg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"logos": {
|
||||
"status": "ready",
|
||||
"count": 2,
|
||||
"items": [
|
||||
{
|
||||
"id": "logo_001",
|
||||
"label": "Nike",
|
||||
"image_path": "/Users/accusys/momentry/var/sftpgo/data/demo/.momentry_snapshots/abc123/logos/logo_001.jpg"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### File Snapshots Query (遷移情境 - 偵測到 parent 有快照)
|
||||
|
||||
```json
|
||||
GET /api/v1/files/:uuid/snapshots
|
||||
{
|
||||
"file_uuid": "uuid_B",
|
||||
"parent_uuid": "uuid_A",
|
||||
"snapshot_tier": "cold",
|
||||
"snapshot_hits": 0,
|
||||
"migration_hint": {
|
||||
"parent_has_snapshots": true,
|
||||
"parent_snapshot_count": 5,
|
||||
"recommendation": "migrate",
|
||||
"message": "Parent file has 5 face snapshots. Agent will handle migration based on usage frequency."
|
||||
},
|
||||
"snapshots": {
|
||||
"faces": { "status": "pending", "count": 0, "items": [] }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### Identity Snapshots Query (完成)
|
||||
|
||||
```json
|
||||
GET /api/v1/identities/:uuid/snapshots
|
||||
{
|
||||
"identity_uuid": "xyz789",
|
||||
"name": "John Doe",
|
||||
"snapshots": {
|
||||
"reference": {
|
||||
"status": "ready",
|
||||
"image_path": "/Users/.../demo/.momentry_snapshots/identities/xyz789/reference.jpg"
|
||||
},
|
||||
"faces": {
|
||||
"status": "ready",
|
||||
"count": 3,
|
||||
"items": [
|
||||
{
|
||||
"id": "face_001",
|
||||
"source_file_uuid": "abc123",
|
||||
"image_path": "/Users/.../demo/.momentry_snapshots/identities/xyz789/faces/abc123_face_001.jpg"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 5.4 狀態定義
|
||||
|
||||
| 狀態 | 說明 | 前端行為 |
|
||||
|------|------|----------|
|
||||
| `pending` | 已收到請求,等待處理 | 顯示 loading spinner |
|
||||
| `generating` | 正在產生中 | 顯示 loading spinner + 進度條 |
|
||||
| `ready` | 已完成 | 載入圖片 |
|
||||
| `failed` | 產生失敗 | 顯示錯誤訊息 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 快取機制與 Redis TTL 管理
|
||||
|
||||
### 6.1 避免重複產生
|
||||
|
||||
```
|
||||
使用者查詢快照
|
||||
↓
|
||||
1. 檢查快照檔案是否已存在
|
||||
↓
|
||||
存在 → 回傳 image_path (status: ready),更新 Redis 計數
|
||||
↓
|
||||
不存在 → 檢查 Redis 是否有進行中的產生任務
|
||||
↓
|
||||
進行中 → 回傳目前進度 (status: generating)
|
||||
↓
|
||||
無任務 → 觸發新的產生任務 (status: pending)
|
||||
```
|
||||
|
||||
### 6.2 快取判斷方式
|
||||
|
||||
| 判斷方式 | 說明 |
|
||||
|----------|------|
|
||||
| **檔案存在檢查** | 檢查 `.momentry_snapshots/{file_uuid}/{type}/` 目錄下是否有 `.jpg` |
|
||||
| **Redis 狀態快取** | Redis key 記錄產生狀態與計數,TTL 管理生命週期 |
|
||||
|
||||
### 6.3 Redis Key 設計
|
||||
|
||||
| Key | Value | TTL | 說明 |
|
||||
|-----|-------|-----|------|
|
||||
| `snapshot:status:{file_uuid}` | `{"status": "ready", "generated_at": "2026-04-30T10:00:00Z"}` | 24 小時 | 快照產生狀態 |
|
||||
| `snapshot:generating:{file_uuid}` | `{"progress": 60, "current_type": "faces"}` | 30 分鐘 | 產生中進度 |
|
||||
| `snapshot:hits:{file_uuid}` | `{count: 8}` | 7 天 | 查詢次數計數 |
|
||||
| `snapshot:last_access:{file_uuid}` | `{"timestamp": "2026-04-30T12:00:00Z"}` | 7 天 | 最後存取時間 |
|
||||
| `snapshot:migrate_hint:{file_uuid}` | `{"parent_uuid": "uuid_A", "count": 5}` | 1 小時 | 遷移提示 |
|
||||
|
||||
### 6.4 快照存在判定
|
||||
|
||||
| 條件 | 行為 |
|
||||
|------|------|
|
||||
| 快照目錄存在且有 `.jpg` | `status: ready` |
|
||||
| 快照目錄不存在或無 `.jpg` | 觸發產生 (`status: pending`) |
|
||||
|
||||
**無需時間比對或過期策略。** 原始檔案修改 = 重新註冊 = 新 file_uuid = 新快照 (新生)。
|
||||
|
||||
---
|
||||
|
||||
## 7. 熱溫冷分層策略
|
||||
|
||||
### 7.1 層級定義
|
||||
|
||||
| 層級 | 查詢次數 | 最近存取 | Redis 狀態 | Agent 行為 |
|
||||
|------|----------|----------|------------|------------|
|
||||
| **Hot** | ≥ 5 次 | ≤ 24 小時 | Key 存在且命中率高 | 快照保留,自動遷移 |
|
||||
| **Warm** | 1-4 次 | ≤ 7 天 | Key 存在但 TTL 將到期 | 快照保留,可遷移 |
|
||||
| **Cold** | 0 次 | > 7 天 或無存取 | Key 已過期/不存在 | 快照不保留,查詢時產生 |
|
||||
|
||||
### 7.2 層級與遷移的關係
|
||||
|
||||
| 情境 | Hot | Warm | Cold |
|
||||
|------|-----|------|------|
|
||||
| 檔案遷移 (uuid_A → uuid_B) | 自動遷移快照 | Agent 決定 | 不遷移,重新產生 |
|
||||
| 新檔案註冊 | - | - | 不產生快照 |
|
||||
| 首次查詢 | 觸發產生 | 觸發產生 | 觸發產生 |
|
||||
| 定期維護 | 不清理 | 可清理 | 清理 (Auto Tearing) |
|
||||
|
||||
### 7.3 層級 API 回應
|
||||
|
||||
```json
|
||||
{
|
||||
"file_uuid": "abc123",
|
||||
"snapshot_tier": "hot",
|
||||
"snapshot_hits": 8,
|
||||
"last_access": "2026-04-30T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 快照遷移 Agent
|
||||
|
||||
### 8.1 遷移行為
|
||||
|
||||
遷移行為 **只預留提示**,由 Agent 處理:
|
||||
|
||||
| 階段 | 說明 |
|
||||
|------|------|
|
||||
| **註冊時** | 記錄 `parent_uuid`,檢查是否有舊快照,產生提示訊息 |
|
||||
| **API 回應** | 若偵測到 parent_uuid 有快照,回傳遷移提示 |
|
||||
| **Agent 處理** | 根據提示 + 熱溫冷層級,自動決定遷移策略 |
|
||||
|
||||
### 8.2 Agent 決策邏輯
|
||||
|
||||
```
|
||||
收到遷移提示 (parent_uuid 有快照)
|
||||
↓
|
||||
檢查 parent 快照層級
|
||||
↓
|
||||
Hot → 自動複製快照到新 file_uuid
|
||||
Warm → 根據設定遷移
|
||||
Cold → 不遷移,重新產生
|
||||
↓
|
||||
更新 Redis 計數器到新 file_uuid
|
||||
```
|
||||
|
||||
### 8.3 遷移 API
|
||||
|
||||
| Endpoint | Method | 說明 |
|
||||
|----------|--------|------|
|
||||
| `POST /api/v1/files/:uuid/snapshots/migrate` | POST | 手動觸發快照遷移(從 parent_uuid) |
|
||||
|
||||
### 8.4 Agent 架構
|
||||
|
||||
```rust
|
||||
pub struct SnapshotAgent {
|
||||
file_uuid: String,
|
||||
user_path: String,
|
||||
snapshot_types: Vec<SnapshotType>,
|
||||
}
|
||||
|
||||
pub enum SnapshotType {
|
||||
Face,
|
||||
Logo,
|
||||
Product,
|
||||
Ocr,
|
||||
}
|
||||
|
||||
impl SnapshotAgent {
|
||||
pub fn new(file_uuid: &str, user_path: &str, types: Vec<SnapshotType>) -> Self { ... }
|
||||
|
||||
pub fn generate(&self) -> Result<SnapshotResult> { ... }
|
||||
|
||||
pub fn migrate_from_parent(&self, parent_uuid: &str, tier: SnapshotTier) -> Result<SnapshotResult> {
|
||||
match tier {
|
||||
SnapshotTier::Hot => self.copy_snapshots(parent_uuid)?,
|
||||
SnapshotTier::Warm => self.selective_copy(parent_uuid)?,
|
||||
SnapshotTier::Cold => self.generate(), // 不遷移,直接產生
|
||||
}
|
||||
}
|
||||
|
||||
fn extract_faces(&self) -> Result<()> { ... }
|
||||
fn extract_logos(&self) -> Result<()> { ... }
|
||||
fn extract_products(&self) -> Result<()> { ... }
|
||||
fn extract_ocr(&self) -> Result<()> { ... }
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Auto Tearing 觀念紀錄 (待決定)
|
||||
|
||||
### 9.1 概念定義
|
||||
|
||||
**Auto Tearing** 指的是系統根據存取模式和資源狀況,**自動拆除(Tear)** 不再需要的快照快取,而非由使用者手動管理。
|
||||
|
||||
### 9.2 與熱溫冷調節的關係
|
||||
|
||||
| 層級 | 行為 | Auto Tearing 角色 |
|
||||
|------|------|-------------------|
|
||||
| **Hot** | 保留快照 | 不觸發 tearing |
|
||||
| **Warm** | 觀察期 | 若降為 Cold,觸發 tearing 提示 |
|
||||
| **Cold** | 可清理 | 自動或手動觸發 tearing |
|
||||
|
||||
### 9.3 待決定問題
|
||||
|
||||
| 問題 | 說明 |
|
||||
|------|------|
|
||||
| **Tearing 觸發時機** | 時間到期?空間不足?層級降級? |
|
||||
| **Tearing 策略** | 立即刪除?先移動到備份區?延遲刪除? |
|
||||
| **空間閾值** | 快照總大小超過多少時觸發 tearing? |
|
||||
| **與遷移的關係** | 檔案遷移時,舊快照是否自動 tearing? |
|
||||
| **使用者控制** | 是否允許使用者設定 tearing 規則? |
|
||||
|
||||
### 9.4 未來實作預留點
|
||||
|
||||
| 位置 | 預留內容 |
|
||||
|------|----------|
|
||||
| `snapshot_manager.rs` | `tear_snapshot()` 方法 |
|
||||
| `redis_db.rs` | `snapshot_tear_policy` 設定 |
|
||||
| `snapshot_agent.rs` | 背景 tearing 任務 |
|
||||
| `config.rs` | tearing 相關設定參數 |
|
||||
|
||||
---
|
||||
|
||||
## 10. 前端等待流程
|
||||
|
||||
### 10.1 WordPress / Tauri Portal
|
||||
|
||||
```
|
||||
1. 呼叫 GET /api/v1/files/:uuid/snapshots
|
||||
↓
|
||||
2. 若 status = pending/generating
|
||||
→ 顯示 loading spinner
|
||||
→ 每 2 秒輪詢 GET /api/v1/files/:uuid/snapshots/status
|
||||
↓
|
||||
3. 若 status = ready
|
||||
→ 隱藏 loading
|
||||
→ 載入 items 中的 image_path 顯示圖片
|
||||
↓
|
||||
4. 若 status = failed
|
||||
→ 顯示錯誤訊息 + 重新嘗試按鈕
|
||||
```
|
||||
|
||||
### 10.2 圖片載入方式
|
||||
|
||||
| 前端 | 載入方式 |
|
||||
|------|----------|
|
||||
| **WordPress** | 直接讀取本地檔案路徑,或 PHP `file_get_contents()` 轉 base64 |
|
||||
| **Tauri Portal** | 使用 `convertFileSrc()` 將本地路徑轉為可顯示 URL |
|
||||
|
||||
---
|
||||
|
||||
## 11. 掃描排除規則
|
||||
|
||||
### 11.1 Dot Folder 排除
|
||||
|
||||
所有檔案掃描機制必須跳過以 `.` 開頭的目錄。
|
||||
|
||||
### 11.2 需要修改的掃描位置
|
||||
|
||||
| 檔案 | 函數 | 修改內容 |
|
||||
|------|------|----------|
|
||||
| `src/watcher/watcher.rs` | `scan_videos()` | 跳過 dot folder |
|
||||
| `src/api/server.rs` | `scan_directory_recursive()` | 跳過 dot folder |
|
||||
|
||||
### 11.3 排除邏輯
|
||||
|
||||
```rust
|
||||
// 跳過 dot folder (以 . 開頭的目錄)
|
||||
if path.is_dir() {
|
||||
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
if name.starts_with('.') {
|
||||
return; // 不進入隱藏目錄
|
||||
}
|
||||
}
|
||||
// 遞迴進入子目錄
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 12. 環境變數
|
||||
|
||||
| 變數 | 預設值 | 說明 |
|
||||
|------|--------|------|
|
||||
| `MOMENTRY_SNAPSHOT_DIR_NAME` | `.momentry_snapshots` | 快照目錄名稱 |
|
||||
| `MOMENTRY_SNAPSHOT_POLL_INTERVAL_MS` | `2000` | 前端輪詢間隔 (毫秒) |
|
||||
| `MOMENTRY_SNAPSHOT_HOT_THRESHOLD` | `5` | Hot 層級查詢次數閾值 |
|
||||
| `MOMENTRY_SNAPSHOT_HOT_TTL_SECS` | `86400` | Hot 層級 TTL (24 小時) |
|
||||
| `MOMENTRY_SNAPSHOT_WARM_TTL_SECS` | `604800` | Warm 層級 TTL (7 天) |
|
||||
|
||||
---
|
||||
|
||||
## 13. 實作計畫
|
||||
|
||||
### 13.1 需要新增的檔案
|
||||
|
||||
| 檔案 | 說明 |
|
||||
|------|------|
|
||||
| `src/core/storage/snapshot_manager.rs` | Snapshot Manager 模組 (快取檢查、路徑管理、層級判斷) |
|
||||
| `src/core/processor/snapshot_agent.rs` | Snapshot Agent 模組 (產生 + 遷移邏輯) |
|
||||
|
||||
### 13.2 需要修改的檔案
|
||||
|
||||
| 檔案 | 修改內容 |
|
||||
|------|----------|
|
||||
| `src/watcher/watcher.rs` | 跳過 dot folder |
|
||||
| `src/api/server.rs` | 跳過 dot folder + 新增 snapshot API endpoints |
|
||||
| `src/api/identity_api.rs` | 新增 identity snapshot API endpoints |
|
||||
| `src/core/config.rs` | 新增 snapshot 設定常數 |
|
||||
| `src/core/db/redis_db.rs` | 新增 snapshot 計數器/狀態/TTL 方法 |
|
||||
| `src/core/lib.rs` | 匯出 snapshot 模組 |
|
||||
|
||||
### 13.3 實作順序
|
||||
|
||||
| 步驟 | 任務 | 預估時間 |
|
||||
|------|------|----------|
|
||||
| 1 | `config.rs` 新增 snapshot 設定 | 5 min |
|
||||
| 2 | `snapshot_manager.rs` 基本功能 (路徑、檢查、層級) | 30 min |
|
||||
| 3 | `redis_db.rs` 新增計數器/TTL 方法 | 20 min |
|
||||
| 4 | `watcher.rs` + `server.rs` 跳過 dot folder | 20 min |
|
||||
| 5 | `server.rs` 新增 file snapshot API (含遷移提示) | 45 min |
|
||||
| 6 | `identity_api.rs` 新增 identity snapshot API | 30 min |
|
||||
| 7 | `snapshot_agent.rs` 產生邏輯 | 60 min |
|
||||
| 8 | `snapshot_agent.rs` 遷移邏輯 (預留提示) | 30 min |
|
||||
| 9 | 編譯測試 | 15 min |
|
||||
|
||||
### 13.4 Snapshot Manager 模組設計
|
||||
|
||||
| 方法 | 說明 |
|
||||
|------|------|
|
||||
| `get_snapshot_dir(user_path, file_uuid)` | 取得 file-level 快照目錄路徑 |
|
||||
| `get_identity_snapshot_dir(user_path, identity_uuid)` | 取得 identity-level 快照目錄路徑 |
|
||||
| `save_snapshot(user_path, file_uuid, object_type, object_id, image_data)` | 儲存快照 JPEG |
|
||||
| `get_snapshot_path(user_path, file_uuid, object_type, object_id)` | 取得快照本地路徑 |
|
||||
| `list_snapshots(user_path, file_uuid)` | 列出所有快照 (給 list API 用) |
|
||||
| `get_snapshot_details(user_path, file_uuid)` | 取得快照詳細列表 (給 detail API 用) |
|
||||
| `is_snapshot_ready(user_path, file_uuid)` | 檢查快照是否已存在 |
|
||||
| `get_snapshot_tier(file_uuid)` | 取得快照熱溫冷層級 (查 Redis) |
|
||||
|
||||
### 13.5 Redis 狀態追蹤方法
|
||||
|
||||
| 方法 | 說明 |
|
||||
|------|------|
|
||||
| `increment_snapshot_hits(file_uuid)` | 查詢計數 +1 |
|
||||
| `get_snapshot_hits(file_uuid)` | 取得查詢次數 |
|
||||
| `update_last_access(file_uuid)` | 更新最後存取時間 |
|
||||
| `set_snapshot_status(file_uuid, status, progress)` | 設定快照狀態 |
|
||||
| `get_snapshot_status(file_uuid)` | 取得快照狀態 |
|
||||
| `clear_snapshot_status(file_uuid)` | 清除快照狀態 |
|
||||
| `set_migrate_hint(file_uuid, parent_uuid, count)` | 設定遷移提示 |
|
||||
|
||||
### 13.6 Dot Folder 排除修改
|
||||
|
||||
#### `src/watcher/watcher.rs`
|
||||
|
||||
```rust
|
||||
// 在 scan_videos() 的 read_dir 迴圈中
|
||||
if path.is_dir() {
|
||||
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
if name.starts_with('.') {
|
||||
continue; // 跳過 dot folder
|
||||
}
|
||||
}
|
||||
// 遞迴進入子目錄
|
||||
}
|
||||
```
|
||||
|
||||
#### `src/api/server.rs`
|
||||
|
||||
```rust
|
||||
// 在 scan_directory_recursive() 中
|
||||
if path.is_dir() {
|
||||
if let Some(name) = path.file_name().and_then(|n| n.to_str()) {
|
||||
if name.starts_with('.') {
|
||||
return; // 不進入 dot folder
|
||||
}
|
||||
}
|
||||
scan_directory_recursive(&path, root, ...);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 14. 相關文件
|
||||
|
||||
- `FILE_UUID_SPEC.md` - File UUID 規格定義
|
||||
- `STANDARDS/DOCS_STANDARD.md` - 文件創建規範
|
||||
- `AI_AGENTS/CORE/AGENT_SPEC.md` - Agent 規格定義
|
||||
|
||||
---
|
||||
|
||||
## 版本資訊
|
||||
|
||||
- 版本: V1.1
|
||||
- 建立日期: 2026-04-30
|
||||
- 文件更新: 2026-04-30
|
||||
Reference in New Issue
Block a user