---
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
