# MarkBase開發指南

##專案概述

**MarkBase - Momentry Display Engine**

Rust Axum Web伺服器，提供 Markdown渲染與檔案樹管理功能。

-技術棧：Rust 1.92+, Axum 0.7, SQLite, pulldown-cmark
-目標平台：macOS（含音訊控制功能）
-資料庫：Per-user SQLite in `data/users/<user_id>.sqlite`

##核心指令

```bash
#建構與測試
cargo build                              #建構專案
cargo test                               #域行所有測試
cargo test test_insert                   #執行特定測試
cargo clippy                             #代碼品質檢查

#執行伺服器
cargo run -- display                     #啟動顯示伺服器（預設 port 11438）
cargo run -- display -p8080              #自訂 port
cargo run -- display README.md          #顯示指定 Markdown檔案

#渲染工具
cargo run -- render <FILE>               #渲染 Markdown（輸出到 stdout）
cargo run -- render <FILE> -o output.html   #輸出到檔案
````

##架構概覽

###核心模組

|模組 |檔案 |功能 |
|------|------|------|
| CLI入口 | `main.rs` | clap指令解析 |
| Web伺服器 | `server.rs` | Axum REST API（18+路由） |
|檔案樹管理 | `filetree/mod.rs` | SQLite CRUD操作 |
| Markdown渲染 | `render.rs` | pulldown-cmark轉換 |
|音訊控制 | `audio.rs` | macOS音訊裝置管理 |
|指令隊列 | `command.rs` | WebSocket指令處理 |

###資料庫結構

-位置：`data/users/<user_id>.sqlite`
-表：`file_registry`, `file_nodes`, `file_locations`
-每個 user_id獨立資料庫

---

## File Tree核心說明（重點章節）

###架構設計

File Tree是 MarkBase的核心模組，提供檔案樹管理功能。

**核心結構：**
```rust
FileTree {
    user_id: String,           //用戶ID
    nodes: Vec<FileNode>,      //節點列表
}
````

**節點類型：**
- **Folder** -資料夾節點（可包含子節點）
- **File** -檔案節點（指向實體檔案）

###資料庫設計

**SQLite表結構：**

|表名 |功能 |
|------|------|
| file_registry |檔案註冊資訊 |
| file_nodes |檔案樹節點 |
| file_locations |檔案位置記錄 |

**節點欄位：**
```
node_id, label, aliases_json, file_uuid, sha256, 
parent_id, children_json, node_type, icon, color, 
bg_color, file_size, registered_at, created_at, 
updated_at, sort_order
````

###公開API（13個函數）

|函數名 |功能 |檔案位置 |
|--------|------|----------|
| user_db_path | 取得DB路徑 | mod.rs:58 |
| init_user_db | 初始化DB | mod.rs:62 |
| open_user_db | 開啟DB | mod.rs:74 |
| load | 載入檔案樹 | mod.rs:79 |
| insert_node | 插入節點 | mod.rs:112 |
| update_node | 更新節點 | mod.rs:149 |
| update_node_alias | 更新別名 | mod.rs:187 |
| delete_node | 刪除節點 | mod.rs:214 |
| move_node | 移動節點 | mod.rs:220 |
| build_tree | 建立樹狀結構 | mod.rs:240 |
| new_folder | 建立資料夾節點 | node.rs:27 |
| new_file_node | 建立檔案節點 | node.rs:300 |
| add_location | 新增檔案位置 | mod.rs:346 |

### REST API（7個路由）

|路由 |方法 |功能 |server.rs行號 |
|------|------|------|--------------|
| `/api/v2/auth/login` | POST | 登入（返回token） | 1203 |
| `/api/v2/auth/logout` | POST | 登出（需Bearer token） | 1220 |
| `/api/v2/auth/verify` | GET | 验证token有效性 | 1238 |
| `/api/v2/tree/:user_id` | GET | 取得檔案樹（需認證） | 395 |
| `/api/v2/tree/:user_id` | DELETE | 刪除所有節點（需認證） | 64 |
| `/api/v2/tree/:user_id/node` | POST | 建立節點（需認證） | 62 |
| `/api/v2/tree/:user_id/node/:node_id` | PUT | 更新節點（需認證） | 63 |
| `/api/v2/tree/:user_id/node/:node_id` | DELETE | 刪除節點 | 63 |
| `/api/v2/tree/:user_id/node/:node_id/move` | PUT | 移動節點 | 71 |
| `/api/v2/tree/:user_id/node/:node_id/alias` | PATCH | 更新別名 | 72 |
| `/api/v2/tree/:user_id/restore` | POST | 從外部API恢復 | 65 |

**Query參數：**
- `mode` -顯示模式

**使用範例：**
```bash
#登入取得token
curl -X POST http://localhost:11438/api/v2/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"demo","password":"demo123"}'
#返回：{"token":"xxx","expires_at":"...","user_id":"demo"}

#使用token訪問檔案樹
curl http://localhost:11438/api/v2/tree/demo \
  -H "Authorization: Bearer <TOKEN>"
```

**認證說明：**
- 所有 `/api/v2/tree/*` 和 `/api/v2/files/*` API 需要認證
- Token有效期：24小時
- 默認用戶：`demo` /密碼：`demo123`
````
---
##認證系統（Authentication）

###認證方式

**Token-BasedAuthentication：**
- UUID Token（簡單可靠）
- 24小時有效期
- Session管理（in-memory）

**APIEndpoints：**
|Endpoint |方法 |功能 |
|---------|------|------|
| `/api/v2/auth/login` | POST | 登入（返回token） |
| `/api/v2/auth/logout` | POST | 登出（需Bearer token） |
| `/api/v2/auth/verify` | GET | 验证token |

**使用流程：**
```
1.登入 →取得token
2.使用token訪問API（Authorization: Bearer <token>）
3.Token过期 →重新登入
```

###默認用戶

**測試用戶：**
- Username: `demo`
- Password: `demo123`
- UserID: `demo`

**密碼安全：**
- bcrypt加密（DEFAULT_COST）
- 密碼不以明文儲存

###認證範例

**登入：**
```bash
curl -X POST http://localhost:11438/api/v2/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"demo","password":"demo123"}'
```

**返回：**
```json
{
  "token": "b2060c13-2a2d-4d5c-82e9-985bbdadbea2",
  "expires_at": "2026-05-17T09:53:51Z",
  "user_id": "demo"
}
```

**使用Token訪問：**
```bash
curl http://localhost:11438/api/v2/tree/demo \
  -H "Authorization: Bearer b2060c13-2a2d-4d5c-82e9-985bbdadbea2"
```

**验证Token：**
```bash
curl http://localhost:11438/api/v2/auth/verify \
  -H "Authorization: Bearer <TOKEN>"
```

**登出：**
```bash
curl -X POST http://localhost:11438/api/v2/auth/logout \
  -H "Authorization: Bearer <TOKEN>"
```

###保護範圍

**需要認證的API：**
- `/api/v2/tree/*` -檔案樹管理
- `/api/v2/files/*` -檔案操作
- `/api/v2/upload/*` -檔案上傳
- `/api/v2/render/*` -檔案渲染

**公開API（無需認證）：**
- `/` -根路徑
- `/api/v2/auth/*` -認證相關
- `/version` -版本信息
- `/api/v2/modes` -顯示模式

###擴展建議

**可擴展功能：**
1. JWT認證（已添加依賴，未啟用）
2. 用戶管理API（create_user已實現）
3.持久化Session（目前in-memory）
4. RBAC權限控制

---

### DisplayMode（顯示模式）

**顯示模式選項：**

|模式 |檔案 |用途 |
|------|------|------|
| tree | `modes/tree.rs` |樹狀顯示 |
| list | `modes/list.rs` |列表顯示 |
| grid_sm | `modes/grid_sm.rs` |小格狀顯示 |
| grid_lg | `modes/grid_lg.rs` |大格狀顯示 |

**DisplayMode trait定義（mode.rs:19）：**
```rust
pub trait DisplayMode: Send + Sync {
    fn name(&self) -> &'static str;
    fn render(&self, tree: &FileTree) -> Value;
    fn sort_options(&self) -> Vec<SortOption>;
    fn filter_options(&self) -> Vec<FilterOption>;
}
````

###檔案轉換功能（convert.rs）

**支援格式轉換：**

|工具 |支援格式 |
|------|----------|
| textutil（macOS內建） | doc, docx, rtf |
| macOS工具 | pages, key, numbers |
| soffice/qlmanage | pptx, ppt, xlsx, xls, odt, epub |

**核心函數：**
- `is_doc_ext(ext)` - 檢查是否為文檔格式
- `get_cached_preview(file, ext)` - 生成緩存預覽

**緩存目錄：** `data/cache/`

###測試覆蓋現況

**已測試（7個）：**
- ✅ init_and_load_empty_tree
- ✅ insert_and_load_node
- ✅ update_node
- ✅ delete_node
- ✅ move_node
- ✅ update_alias（zh_tw等多語言別名）
- ✅ build_tree（樹狀結構）

**待補測試：**
- ❌ convert.rs - 檔案轉換功能
- ❌ modes/*.rs - DisplayMode渲染
- ❌ API路由 - REST endpoint測試

###開發範例

**新增節點範例：**
```rust
//建立資料夾
let folder = FileTree::new_folder("Videos", None);
tree.insert_node(&conn, &folder)?;

//建立檔案節點
let (file_node, register_sql) = FileTree::new_file_node(
    "demo.mp4",
    "abc123def456...",
    Some("sha256hash"),
    "demo.mp4",
    Some(1024000),
    Some("video/mp4"),
    None,
    Some(folder.node_id),
);
tree.insert_node(&conn, &file_node)?;
````

**查詢範例：**
```rust
//載入檔案樹
let tree = FileTree::load(&conn, &user_id)?;

//建立樹狀結構（parent-child關係）
let roots = tree.build_tree();

//取得特定顯示模式
let mode = filetree::mode::get_mode("tree");
let rendered = mode.render(&tree);
````

---

## SFTPGo同步系統（Authentication Sync）

###系統架構

**同步流程：**
```
SFTPGo (PostgreSQL) → MarkBase (auth.sqlite)
    users表 → sftpgo_users表
    groups表 → sftpgo_groups表
    users_groups_mapping表 → users_groups_mapping表
```

**同步策略：**
-啟動時同步（server.rs startup task）
-每小時自動同步（tokio interval task）
-手動同步API（/api/v2/admin/sync）
-失敗時使用緩存fallback

###數據庫結構

**auth.sqlite位置：** `data/auth.sqlite`

**表結構：**
|表名 |功能 |
|------|------|
| sftpgo_users |用戶信息（username, password_hash, status, permissions） |
| sftpgo_groups |群組信息（name, description） |
| users_groups_mapping |用戶-群組映射（username, group_name） |
| sync_log |同步日志（sync_type, sync_time, status） |

### PostgreSQL連接配置

**默認配置（pg_client.rs）：**
```
host: 127.0.0.1
port: 5432
user: sftpgo
password: sftpgo_pass_2026
database: sftpgo
```

**環境變數配置（優先）：**
```bash
export PG_HOST=127.0.0.1
export PG_PORT=5432
export PG_USER=sftpgo
export PG_PASSWORD=sftpgo_pass_2026
export PG_DATABASE=sftpgo
```

###同步API

**手動同步：**
```bash
curl -X POST http://localhost:11438/api/v2/admin/sync
```

**返回示例：**
```json
{
  "users_synced": 3,
  "groups_synced": 1,
  "mappings_synced": 0,
  "status": "success"
}
```

**同步狀態查詢：**
```bash
curl http://localhost:11438/api/v2/admin/sync/status
```

**返回示例：**
```json
{
  "status": "ok",
  "latest_sync": {
    "sync_type": "full",
    "sync_time": 1778927765,
    "users_synced": 3,
    "groups_synced": 1,
    "mappings_synced": 0,
    "status": "success"
  }
}
```

###認證流程

**登入流程：**
```
1.客戶端發送登入請求（username, password）
2.服務器從auth.sqlite查詢用戶
3.bcrypt驗證密碼
4.生成UUID token（24小時有效）
5.返回token、expires_at、groups、permissions
```

**登入API：**
```bash
curl -X POST http://localhost:11438/api/v2/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"demo","password":"your_password"}'
```

**返回示例：**
```json
{
  "token": "8d85c37d-8cc2-4633-a838-5400bb88dc6f",
  "expires_at": "2026-05-17T10:39:05Z",
  "user_id": "demo",
  "groups": [],
  "permissions": "{\"/*\": [\"*\"]}"
}
```

###測試用戶

**SFTPGo用戶（狀態=1）：**
- warren（原始密碼hash：\$2a\$10\$TpGOufSlx...）
- momentry（原始密碼hash：\$2a\$10\$Yn/43aBY...）
- demo（原始密碼hash：\$2a\$10\$wCQC0wGRe...）

**測試密碼：**
為測試目的，可設置統一密碼：
```bash
# 在PostgreSQL中更新密碼為demo123
psql -h 127.0.0.1 -p 5432 -U sftpgo -d sftpgo -c "
UPDATE users SET password = '\$2b\$10\$ha5wU.mOi8fHLJCfun860u2cfVopa04jwe/q82IKOwqp5uG70qsH6' 
WHERE username IN ('warren', 'momentry', 'demo');
"

# 重新同步
curl -X POST http://localhost:11438/api/v2/admin/sync

#測試登入
curl -X POST http://localhost:11438/api/v2/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"warren","password":"demo123"}'
```

###同步模組

**sync.rs：**
- `AuthDb` - auth.sqlite操作（get_user, get_user_groups, save_user）
- `SyncResult` -同步結果統計（users_synced, groups_synced, status）
- `PgUser, PgGroup, PgUserGroupMapping` - PostgreSQL數據結構

**pg_client.rs：**
- `PgClient` - PostgreSQL連接客戶端
- `SftpGoSync` -同步器（fetch_users, fetch_groups, full_sync）

**server.rs：**
- `/api/v2/admin/sync` -手動同步endpoint
- `/api/v2/admin/sync/status` -同步狀態endpoint
- startup sync task -啟動時同步
- hourly sync task -每小時同步（tokio::spawn）

###測試結果（2026-05-16）

**測試時間：**18:39

**測試狀態：** ✅ 全部成功

**測試項目：**
- ✅ PostgreSQL連接成功
- ✅ 手動同步API成功（3用戶, 1群組）
- ✅ 登入測試成功（demo/momentry/warren）
- ✅ Token驗證成功
- ✅ 保護API訪問成功

**密碼測試：**
使用統一密碼demo123測試，bcrypt驗證成功。

---

##測試執行

###執行測試

```bash
cargo test                          #域行所有測試
cargo test test_insert              #執行特定測試
cargo test -- --nocapture           #顯示詳細輸出
rm data/users/test_*.sqlite         #清理暫存資料庫
````

###測試現況

|模組 |狀態 |說明 |
|------|------|------|
| filetree/mod.rs | ✅已測試 | 7個 CRUD測試 |
| filetree/convert.rs | ❌待補 | 檔案轉換測試 |
| filetree/modes/*.rs | ❌待補 | DisplayMode測試 |
| server.rs（API路由） | ❌待補 | API handler測試 |
| render.rs | ❌待補 | Markdown渲染測試 |
| audio.rs | ❌待補 | macOS音訊功能測試 |

###測試清理

測試會產生暫存資料庫：`data/users/test_*.sqlite`

階段性任務結束後應手動清除：
```bash
rm data/users/test_*.sqlite
````

---

##展示執行

###啟動伺服器

```bash
cargo run -- display                #啟動（自動開啟瀏覽器）
cargo run -- render <file>          #渲染 Markdown檔案
````

###Demo資料

- `data/users/demo.sqlite` - 50節點範例資料
  - 5個 Folder節點
  - 45個 File節點
- `data/cache/` -範例檔案
  - 29ffd4c12ef6481da6bee7ae4c36a89f.jpg
  - 2c62f90aacc542a9bcfa0c65b63be02a.txt

###Demo資料庫結構

```
Home（根資料夾）
├── Movies（子資料夾，包含影片檔案）
├── Marketing（子資料夾，包含行銷素材）
├── Cartoons（子資料夾，包含動畫檔案）
└── Other（子資料夾，包含其他檔案）
````

---

## macOS環境需求

###必要工具

- **SwitchAudioSource** -音訊裝置切換CLI
  ```bash
  brew install switchaudio-source
  SwitchAudioSource -a              #列出所有音訊裝置
  ````

### macOS限定功能

|功能 |依賴 |說明 |
|------|------|------|
|音訊裝置切換 | SwitchAudioSource | `/devices` API |
|音量控制 | osascript | `/volume` API |
|語音測試 | say命令 | `/command` API（test_voice） |
|文檔轉換 | textutil | convert.rs（doc/rtf轉換） |

---

## CI/CD配置（Gitea Actions）

### Access Token 配置

**Token資訊：**
- **Token名稱：** OpenCode_M4Mini
- **建立日期：** 2026-05-16
- **擁有者：** warren (Warren Lo)
- **權限範圍：** repo (完整倉庫權限)
- **用途：** CI/CD部署、倉庫管理、自動化操作

**Token值：** `c5e025496ebc3c7408a971d64a33bd56aac9186c`

**使用方式：**
```bash
# API認證
curl -H "Authorization: token c5e025496ebc3c7408a971d64a33bd56aac9186c" \
  https://gitea.momentry.ddns.net/api/v1/user

# Git推送（需配置遠端）
git remote set-url origin https://oauth2:c5e025496ebc3c7408a971d64a33bd56aac9186c@gitea.momentry.ddns.net/warren/markbase.git
```

**安全提醒：**
- ⚠️ 此Token僅用於本機開發環境
- ⚠️ 請勿提交到公開倉庫
- ⚠️ 定期更換Token（建議每90天）
- ⚠️ 如需撤銷：Gitea → Settings → Applications → Access Tokens → Delete

###環境資訊

- **Gitea Server**: https://gitea.momentry.ddns.net
- **Gitea版本**: 1.25.3（支援 Actions）
- **Runner**: 本機Mac（實機測試）
- **Workflow**: `.gitea/workflows/*.yml`

### Runner配置步驟

**1. 取得 Runner Token**
- 登入 Gitea: https://gitea.momentry.ddns.net
- Settings → Actions → Runners →建立新 Runner

**2. 下載並安裝 Runner**
```bash
# macOS ARM版本
wget https://dl.gitea.com/act_runner/latest/act_runner-darwin-arm64
chmod +x act_runner-darwin-arm64
sudo mv act_runner-darwin-arm64 /usr/local/bin/act_runner
````

**3. 註冊 Runner**
```bash
act_runner register --instance https://gitea.momentry.ddns.net --token <YOUR_TOKEN>
````

**4.啟動 Runner**
```bash
act_runner daemon
````

###Workflow範例

```yaml
# .gitea/workflows/test.yml
name: Test
on: [push, pull_request]

jobs:
  test:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Setup Rust
        uses: actions-rust-lang/setup-rust-toolchain@v1
      
      - name: Install SwitchAudioSource
        run: brew install switchaudio-source
      
      - name: Run tests
        run: cargo test --all
      
      - name: Run clippy
        run: cargo clippy --all-targets --all-features -- -D warnings
      
      - name: Check formatting
        run: cargo fmt -- --check
      
      - name: Clean test databases
        run: rm -f data/users/test_*.sqlite
````

---

##開發環境設定

###開發環境API Key

`server.rs:192`包含開發環境 API key：
```rust
let api_key = "muser_68600856036340bcafc01930eb4bd839_1774418104_97221b69";
let api_url = "http://localhost:3002/api/v1/files";
````

用途：`restore_tree`功能從外部 API恢復檔案樹。

**改進建議：**
-應改用環境變數配置
- 建立 `.env.example`範例

###環境變數配置（待實作）

```bash
# .env（未來配置）
RESTORE_API_KEY=muser_your_api_key_here
RESTORE_API_URL=http://localhost:3002
SERVER_PORT=11438
DB_DIR=data/users
````

---

##代碼風格

###Rust標準工具

```bash
cargo fmt                           #代碼格式化
cargo clippy                        #代碼品質檢查
````

**現有clippy警告：**
- server.rs:609 -未使用變數 `state`
- server.rs:1020 -未使用變數 `pg_url`

---

##專案結構

```
markbase/
├── src/
│   ├── main.rs                 # CLI入口
│   ├── lib.rs                  #模組宣告
│   ├── server.rs               # Web伺服器（18+路由）
│   ├── render.rs               # Markdown渲染
│   ├── audio.rs                # macOS音訊
│   ├── command.rs              #指令隊列
│   ├── page.html               # HTML模板
│   └── filetree/
│       ├── mod.rs              #檔案樹核心（553行）
│       ├── convert.rs          #檔案轉換（253行）
│       ├── mode.rs             # DisplayMode trait（43行）
│       ├── node.rs             #節點定義（82行）
│       └── modes/
│           ├── tree.rs         #樹狀模式（57行）
│           ├── list.rs         #列表模式（87行）
│           ├── grid_sm.rs      #小格狀模式（72行）
│           ├── grid_lg.rs      #大格狀模式（83行）
│           └── mod.rs          #模式匯出（4行）
├── data/
│   ├── users/                  # SQLite資料庫
│   │   ├── demo.sqlite        # Demo資料（50節點）
│   │   └── test_*.sqlite      #測試暫存（已清理）
│   └── cache/                  #檔案緩存
│       ├── *.jpg               #圖片緩存
│       └── *.txt               #文本緩存
├── tests/                      #整合測試（待建立）
├── examples/                   #範例檔案（待建立）
├── .gitea/
│   └ workflows/
│       ├── test.yml            #測試workflow（待建立）
│       ├── build.yml           #建構workflow（待建立）
│       └── release.yml         #發布workflow（待建立）
├── Cargo.toml                  # Rust配置
├── Cargo.lock                  #依賴鎖定
└── AGENTS.md                   # 本文件
````

---

##常見問題

###測試暫存檔清理

```bash
rm data/users/test_*.sqlite
````

###音訊功能無效

確認 `SwitchAudioSource`已安裝：
```bash
brew install switchaudio-source
SwitchAudioSource -a              #列出音訊裝置
````

###File Tree API測試

```bash
curl http://localhost:11438/api/v2/tree/demo
curl http://localhost:11438/api/v2/tree/demo?mode=tree
````

###CI/CD Runner連接失敗

確認 Runner已配置並啟動：
```bash
act_runner list                   #查看 Runner狀態
act_runner daemon                 #啟動 Runner
```

###CI/CD日志查看方式

**方法1：通過 Gitea Web UI查看（推薦）**
```
https://gitea.momentry.ddns.net/warren/markbase/actions
```

**方法2：通過 API獲取詳細日志**

**步驟：**
1. **獲取所有 Actions Runs**
   ```bash
   curl -H "Authorization: token c5e025496ebc3c7408a971d64a33bd56aac9186c" \
     https://gitea.momentry.ddns.net/api/v1/repos/warren/markbase/actions/runs | jq '.workflow_runs[] | {id, status, conclusion}'
   ```

2. **獲取特定 Run的所有 Jobs**
   ```bash
   curl -H "Authorization: token c5e025496ebc3c7408a971d64a33bd56aac9186c" \
     https://gitea.momentry.ddns.net/api/v1/repos/warren/markbase/actions/runs/<RUN_ID>/jobs | jq '.jobs[] | {id, name, status, conclusion}'
   ```

3. **獲取 Job詳細日志**
   ```bash
   curl -H "Authorization: token c5e025496ebc3c7408a971d64a33bd56aac9186c" \
     https://gitea.momentry.ddns.net/api/v1/repos/warren/markbase/actions/jobs/<JOB_ID>/logs
   ```

**範例：查看 Run ID 6的 test job日志**
```bash
# Step 1: 獲取 jobs列表
curl -s -H "Authorization: token c5e025496ebc3c7408a971d64a33bd56aac9186c" \
  https://gitea.momentry.ddns.net/api/v1/repos/warren/markbase/actions/runs/6/jobs | jq '.jobs[] | {id, name}'

# Step 2:獲取 job 11（test job）的完整日志
curl -s -H "Authorization: token c5e025496ebc3c7408a971d64a33bd56aac9186c" \
  https://gitea.momentry.ddns.net/api/v1/repos/warren/markbase/actions/jobs/11/logs
```

**日志格式：**
- 每行以時間戳開頭：`2026-05-16T08:26:07.5859940Z`
- 包含完整執行過程、命令輸出、錯誤信息
- 錯誤行通常包含 `##[error]`標記

**常見錯誤診斷：**
- `conditional binary operator expected` → bash腳本語法問題
- `Process completed with exit code 2` →腳本執行失敗
- `Unable to pull refs/heads/v3` → Git clone問題（通常可忽略）`

---

##部署狀況記錄（2026-05-16）

###已完成部署

**倉庫建立：**
- ✅ warren/markbase 倉庫已建立（ID: 27）
- ✅ URL: https://gitea.momentry.ddns.net/warren/markbase
- ✅ 代碼已推送（4 commits）

**Runner配置：**
- ✅ Runner已註冊（ID: 2）
- ✅ Runner名稱: accusys-Mac-mini-M4-2.local
- ✅ Runner標籤: macos-latest:host, macos-arm64:host
- ✅ Runner進程運行中（PID: 90905）

**Actions狀態：**
- ✅ Actions已觸發並執行
- ✅ Run ID 7: 成功（test + build jobs均通過） ← 最新
- ⚠️ Run ID 1-6: 失敗（Setup Rust bash兼容性問題）
- ✅ 本地測試全部通過（62 tests）
- ✅ Clippy檢查已通過
- ✅ 格式檢查已通過

###CI問題已解決（2026-05-16）

**問題根本原因：**
- GitHub Action（actions-rust-lang/setup-rust-toolchain@v1）與Gitea Runner bash環境不兼容
- 錯誤：`conditional binary operator expected`（line 2）

**解決方案：**
- 替換為原生rustup安裝：`curl | sh.rustup.rs`
- 在所有cargo命令前添加：`source $HOME/.cargo/env`

**結果：**
- ✅ Run ID 7: 成功（5分22秒，正常執行）
- ✅ test job: success
- ✅ build job: success
- ✅ CI/CD完全正常運行

**Commits記錄：**
- 87a3eea: 記錄CI日志獲取方式和問題診斷
- 34b6839: 替換GitHub Action為原生rustup安裝 ←修復提交

---

##部署測試經驗（2026-05-16）

###核心方法論

**CI日志獲取方法：**
```bash
#1.獲取 Run列表
curl -H "Authorization: token <TOKEN>" \
  <GITEA_URL>/api/v1/repos/<OWNER>/<REPO>/actions/runs

#2.獲取 Job ID
curl -H "Authorization: token <TOKEN>" \
  <GITEA_URL>/api/v1/repos/<OWNER>/<REPO>/actions/runs/<RUN_ID>/jobs

#3.獲取 Job日志
curl -H "Authorization: token <TOKEN>" \
  <GITEA_URL>/api/v1/repos/<OWNER>/<REPO>/actions/jobs/<JOB_ID>/logs
```

**問題診斷思路：**
```
觀察現象 →獲取日志 →定位錯誤 →分析原因 →設計方案 →實施修復 →验证結果
```

**關鍵認知：**
- GitHub Actions ≠Gitea Runner環境（不完全兼容）
- 原生工具安裝 >Action依賴（更穩定可靠）
- 環境變數載入是必要步驟（`source $HOME/.cargo/env`）

**測試結果：**
-失敗→成功迭代：6次失敗 →1次成功
-執行時間對比：5秒（失敗）→5分22秒（成功）
-修復方案：原生rustup安裝替代GitHub Action

---

**最後更新：2026-05-16**
**版本：1.4（部署測試經驗版）**
---

## 配置系统

### 配置文件位置

**默认位置：** `config/markbase.toml`

**创建配置文件：**
```bash
cargo run -- config init          # 创建默认配置文件
cargo run -- config init --force  # 强制覆盖现有配置
```

### 配置参数说明

#### Server配置
- **host**: 服务器监听地址（默认：127.0.0.1）
- **port**: 服务器端口（默认：11438，范围：>=1024）
- **log_level**: 日志级别
- **auth_db_path**: 认证数据库路径（默认：data/auth.sqlite）
- **users_db_dir**: 用户数据库目录（默认：data/users）

#### PostgreSQL配置
- **host**: PostgreSQL服务器地址（默认：127.0.0.1）
- **port**: PostgreSQL端口（默认：5432）
- **user**: PostgreSQL用户名（默认：sftpgo）
- **password**: PostgreSQL密码（默认：sftpgo_pass_2026）
- **database**: PostgreSQL数据库（默认：sftpgo）
- **connection_pool_size**: 连接池大小（默认：5）

#### Authentication配置
- **bcrypt_cost**: bcrypt加密强度（默认：10，范围：4-31）
- **token_validity_hours**: Token有效期（默认：24小时）
- **session_storage**: Session存储方式（默认：memory）
- **max_sessions_per_user**: 每用户最大Session数（默认：5）
- **default_user**: 默认用户（默认：demo）
- **default_password**: 默认密码（默认：demo123）

#### Test配置
- **users**: 测试用户列表（默认：["warren", "momentry", "demo"]）
- **password**: 测试统一密码（默认：demo123）
- **login_test_iterations**: Login性能测试迭代次数（默认：10）
- **verify_test_iterations**: Token验证测试迭代次数（默认：100）
- **api_test_iterations**: Protected API测试迭代次数（默认：50）
- **performance_report**: 是否生成性能报告（默认：true）
- **output_format**: 输出格式（默认：markdown）

#### Logging配置
- **level**: 日志级别（默认：info）
- **file_path**: 日志文件路径（默认：logs/markbase.log）
- **console_output**: 是否输出到控制台（默认：true）
- **structured_logging**: 是否使用结构化日志（默认：false）

### CLI Config命令

**查看配置：**
```bash
cargo run -- config show                    # 显示所有配置
cargo run -- config show --section server   # 显示server配置
cargo run -- config show --section postgresql
cargo run -- config show --section authentication
```

**编辑配置：**
```bash
cargo run -- config edit --key server.port --value 8080
cargo run -- config edit --key postgresql.password --value new_pass
cargo run -- config edit --key authentication.token_validity_hours --value 48
```

**验证配置：**
```bash
cargo run -- config validate
```

### UI Settings面板

**访问方式：**
1. 打开浏览器访问 http://localhost:11438/
2. 点击底部栏⚙️Settings按钮
3. Settings面板将从顶部滑入

**功能：**
- **查看配置**：显示所有5个配置section（server, postgresql, authentication, test, logging）
- **编辑配置**：点击每个参数旁的Edit按钮，修改值后Save保存
- **验证配置**：点击Validate按钮验证配置有效性
- **Toast提示**：操作成功/失败显示提示信息

**API端点：**
|端点 |方法 |功能 |
|------|------|------|
| `/api/v2/config` | GET | 获取完整配置JSON |
| `/api/v2/config/edit` | POST | 编辑配置参数 |
| `/api/v2/config/validate` | GET | 验证配置有效性 |

**编辑示例：**
```bash
# 使用API修改配置
curl -X POST "http://localhost:11438/api/v2/config/edit?key=server.port&value=8080"
# 返回：{"ok":true}

# 验证配置
curl http://localhost:11438/api/v2/config/validate
# 返回：{"ok":true}
```

### 配置优先级

默认值 → 配置文件 → 环境变量 → CLI参数

**环境变量命名：**
- Server: `MB_HOST`, `MB_PORT`, `MB_LOG_LEVEL`
- PostgreSQL: `PG_HOST`, `PG_PORT`, `PG_USER`, `PG_PASSWORD`
- Authentication: `MB_BCRYPT_COST`, `MB_TOKEN_VALIDITY_HOURS`

---

## FUSE Virtual File System（2026-05-17新增）

### 功能概述

**虚拟文件系统挂载：**
- FUSE-T技术（Kext-less设计）
- Backend选择：NFSv4（稳定）或FSKit（macOS 26+，最快）
- 支持多用户并发挂载（10 users）
- 性能目标：600MB/s sustained write per user

### 设计文档

**架构概览：**
```
MarkBase FUSE System
├── src/fuse/mod.rs          # FUSE核心模組
│   ├── BackendType          # NFSv4/FSKit选择
│   ├── select_backend()     # 自动检测backend
│   └── mount_hello_fs()     # POC placeholder
├── docs/FUSE_DESIGN.md      # 完整设计文档
└ docs/FUSE_POC_TEST.md    # POC测试计划
```

**Backend选择逻辑：**
- macOS 26+：FSKit（native，direct path，minimal overhead）
- macOS <26：NFSv4（stable，TCP/IP overhead ~5-10%）

### CLI命令

**POC测试命令：**
```bash
# 检测backend
cargo run -- fuse detect-backend
# 输出：macOS 26.4.1 → Recommended: fskit

# POC placeholder mount
cargo run -- fuse poc --dir /tmp/fuse_test --backend auto
cargo run -- fuse poc --backend fskit  # 手動指定 FSKit
cargo run -- fuse poc --backend nfs     # 手動指定 NFSv4
```

**未来完整命令（Phase 2+）：**
```bash
# 单user挂载
cargo run -- fuse --mount --user warren --dir /Volumes/MarkBase_warren

# 多user并发挂载
cargo run -- fuse --mount --all --dir /Volumes/

# 卸載
cargo run -- fuse --unmount --dir /Volumes/MarkBase_warren
cargo run -- fuse --unmount --all
```

### POC测试结果（2026-05-17）

**测试环境：**
- 硬體：M4 Mac mini, 16GB RAM, NVMe 2TB
- OS：macOS 26.4.1
- Backend：FSKit（自动检测）

**测试項目（7項全通過）：**
- ✅ Backend detection（macOS 26.4.1 → FSKit）
- ✅ Auto backend selection（FSKit）
- ✅ Manual backend selection（FSKit/NFSv4）
- ✅ Error handling（invalid backend）
- ✅ Compilation check
- ✅ Unit tests（7 passed）
- ✅ CLI commands functional

**Unit Tests结果：**
```
running 7 tests
test fuse::backend::tests::test_backend_support ... ok
test fuse::backend::tests::test_backend_type_name ... ok
test fuse::backend::tests::test_manual_backend_selection ... ok
test fuse::poc_hello::tests::test_hello_fs_creation ... ok
test fuse::backend::tests::test_select_backend_macos_25 ... ok
test fuse::poc_hello::tests::test_mount_placeholder ... ok
test fuse::backend::tests::test_select_backend_macos_26 ... ok
test result: ok. 7 passed; 0 failed; 0 ignored
```

### FUSE-T vs macFUSE比較

|特性 |FUSE-T |macFUSE |
|------|--------|---------|
|Kernel Design |Kext-less（userspace）|Kernel Extension + FSKit |
|Backend Protocol |NFSv4 / SMB3 / FSKit |Direct kernel FUSE API |
|安装难度 |简单（brew install）|需System Settings設定 |
|稳定性 |穩定（userspace server）|可能kernel crash |
|授權 |免費個人，商業需授權 |開源（BSD）|
|macOS支援 |全版本 |macOS 12+ |
|App Store |可嵌入 |需特殊處理 |
|效能（FSKit） |~600-700 MB/s |~650-750 MB/s |

**推薦：FUSE-T**
- 稳定性优先（避免kernel panic）
- 部署友善（无需Security Settings）
- macOS 26支援FSKit backend（与macFUSE相同效能）

### 效能目标

|Metric |Target |Measurement Method |
|--------|--------|-------------------|
|Write throughput |>=600MB/s |AJA System Test 4K ProRes 4444 |
|Read throughput |>=800MB/s |AJA System Test 4K ProRes 422 HQ |
|Mount latency（single） |<100ms |Timing measurement |
|Mount latency（10 users） |<2s |Parallel mount timing |
|Concurrent writes |10 × 600MB/s |AJA concurrent test |
|Uptime stability |24h no crash |Stability test |
|Cache hit rate |>=90% |Cache statistics |

### 实作阶段

**Phase 1：POC验证（已完成 Day 1）**
- ✅ 建立fuse module结构
- ✅ Backend detection implementation
- ✅ CLI commands functional
- ✅ Unit tests pass（7 tests）
- ⏳ FUSE-T安装（需手动sudo）
- ⏳ AJA System Test下载（需手动）

**Phase 2：SQLite-backed FUSE（Day 3-5）**
- ❌ MarkBaseFs implementation
- ❌ FUSE operations（getattr, read, write）
- ❌ warren user test（12659 nodes）
- ❌ LRU caching

**Phase 3：Multi-user Concurrent（Day 6-8）**
- ❌ MountManager implementation
- ❌ 10 user parallel mount
- ❌ AJA concurrent write test
- ❌ 24h stability test

**Phase 4：Performance Optimization（Day 9-12）**
- ❌ Write buffering（64KB chunks）
- ❌ FSKit backend optimization
- ❌ 600MB/s validation
- ❌ Final documentation

### 手动安装步骤

**FUSE-T安装：**
```bash
# 检查下载的PKG
ls -lh ~/Downloads/fuse-t-1.2.6.pkg  # 23MB

# 安装（需要sudo密码）
sudo installer -pkg ~/Downloads/fuse-t-1.2.6.pkg -target /

# 验证安装
ls -la /usr/local/bin/fuse-t
fuse-t --version  # Expected: 1.2.6
```

**AJA System Test安装：**
```bash
# 手动下载（浏览器访问）
https://www.aja.com/en/products/aja-system-test

# 安装DMG
hdiutil attach ~/Downloads/AJA_System_Test.dmg
cp -R /Volumes/AJA\ System\ Test/*.app /Applications/
hdiutil detach /Volumes/AJA\ System\ Test
```

### 相关文档

|文档 |位置 |说明 |
|------|------|------|
|FUSE_DESIGN.md |docs/ |完整设计文档（架构、backend、性能）|
|FUSE_POC_TEST.md |docs/ |POC测试计划（7项测试）|
|FUSE_POC_REPORT.md |docs/ |POC测试报告（结果、下一步）|
|fuse_poc_test.sh |tests/ |自动化测试脚本 |

---

**最后更新：** 2026-05-17 10:20
**版本：** 1.8（FUSE Virtual File System版）
---

## File Scan System（2026-05-17新增）

### 功能概述

**异步导入系统：**
- 快速导入（skip_hash=true）：立即显示文件树
- 后台hash：异步计算SHA256，不影响前端使用

### CLI命令

**scan命令：**
```bash
# 快速导入（默认skip_hash=true）
cargo run -- scan --user warren --dir /Users/accusys/momentry/var/sftpgo/data/warren

# 导入并计算hash（skip_hash=false）
cargo run -- scan --user warren --dir <path> --skip-hash false --threads 4

# 参数说明：
--user <USER>          用户ID
--dir <DIR>            扫描目录
--batch <BATCH>        批量插入大小（默认：100）
--skip-hash <BOOL>     跳过hash计算（默认：true）
--threads <THREADS>    hash计算线程数（默认：4）
````

**hash命令：**
```bash
# 后台计算hash
cargo run -- hash --user warren --threads 4

# 参数说明：
--user <USER>          用户ID
--threads <THREADS>    并行线程数（默认：4）
````

### 效能测试结果（2026-05-17）

**测试配置：**
- 文件总数：11857 files + 801 folders = 12658 nodes
- 目录深度：多层子目录（Accusys/Accusys_FAE/VolPack_ME5012...）
- CPU线程：4 threads (M4 Mac mini)

**第一阶段：快速导入（skip_hash=true）**
- 目录扫描：0.10s
- ID生成：0.57s（主要瓶颈）
- 数据库插入：0.21s
- 总时间：0.89s
- 速度：14243 nodes/sec

**第二阶段：SHA256计算（4 threads）**
- 文件数：11857
- 总时间：417.58s
- 速度：28 files/sec

**效能瓶颈分析：**
1. ID生成（64%）- SHA256计算UUID耗时
2. 数据库插入（24%）- 批量插入优化
3. 目录扫描（11%）- fast, no bottleneck
4. Hash计算 - IO瓶颈（多线程未提速）

### 设计决策

**UUID生成策略：**
- 算法：SHA256(path|filename|mac|mtime).chars().take(32)
- 特性：确定性UUID（同一文件 = 同一UUID）
- 优势：无需外部API，支持增量导入

**路径存储方案：**
- 存储位置：aliases.json（临时方案）
- 格式：`{"path": "/full/path/to/file"}`
- 原因：file_nodes表无path字段
- 改进：未来添加file_locations表填充

**异步hash设计：**
- 导入优先：用户立即查看文件树
- hash后台：不影响前端使用
- 多线程：并行计算（IO瓶颈限制）
- 增量：只计算缺失hash的文件

### 数据库结构（warren.sqlite）

**节点统计：**
- Folders: 801
- Files: 11857
- Total: 12658

**示例节点：**
```
node_id: 8b1ede3cd6970f02fa85b8e34b682caf
label: Test_Plan_ME5.docx
aliases_json: {"path":"/Users/accusys/.../Test_Plan_ME5.docx"}
sha256: 355a063b697a812742fae2a021cdda5c
node_type: file
parent_id: (folder UUID)
````

### 使用流程

**完整导入流程：**
```
1. cargo run -- scan --user warren --dir <path>  # 快速导入（0.89s）
2. cargo run -- hash --user warren --threads 4   # 后台hash（417s）
3. 查看文件树：http://localhost:11438/ → File Tree → Login
````

**增量导入流程：**
```
1. cargo run -- scan --user warren --dir <path>  # 导入新文件
2. cargo run -- hash --user warren               # 计算新hash（只计算缺失的）
````

### 相关文件

|文件 |功能 |
|------|------|
| src/scan.rs | 扫描导入 + hash计算（499行）|
| src/main.rs | CLI命令定义（scan/hash）|
| src/filetree/mod.rs | FileTree::init_user_db |
| data/users/warren.sqlite | warren用户数据库（12658 nodes）|

---

**最后更新：** 2026-05-17 02:15
**版本：** 1.7（File Scan System版）
