Files
markbase/AGENTS.md
2026-05-18 17:02:30 +08:00

1360 lines
37 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 API18+路由) |
|檔案樹管理 | `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
````
###公開API13個函數
|函數名 |功能 |檔案位置 |
|--------|------|----------|
| 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 API7個路由
|路由 |方法 |功能 |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訪問APIAuthorization: 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. 用戶管理APIcreate_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
**支援格式轉換:**
|工具 |支援格式 |
|------|----------|
| textutilmacOS內建 | 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_aliaszh_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 token24小時有效
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.rsAPI路由 | ❌待補 | 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` APItest_voice |
|文檔轉換 | textutil | convert.rsdoc/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 trait43行
│ ├── 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 11test 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 Actionactions-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个配置sectionserver, 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 System2026-05-17新增
### 功能概述
**虚拟文件系统挂载:**
- FUSE-T技术Kext-less设计
- Backend选择NFSv4稳定或FSKitmacOS 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+FSKitnativedirect pathminimal overhead
- macOS <26NFSv4stableTCP/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
- OSmacOS 26.4.1
- BackendFSKit自动检测
**测试項目7項全通過**
- ✅ Backend detectionmacOS 26.4.1 → FSKit
- ✅ Auto backend selectionFSKit
- ✅ Manual backend selectionFSKit/NFSv4
- ✅ Error handlinginvalid backend
- ✅ Compilation check
- ✅ Unit tests7 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-lessuserspace|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 latencysingle |<100ms |Timing measurement |
|Mount latency10 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 1POC验证已完成 Day 1**
- ✅ 建立fuse module结构
- ✅ Backend detection implementation
- ✅ CLI commands functional
- ✅ Unit tests pass7 tests
- ⏳ FUSE-T安装需手动sudo
- ⏳ AJA System Test下载需手动
**Phase 2SQLite-backed FUSEDay 3-5**
- ❌ MarkBaseFs implementation
- ❌ FUSE operationsgetattr, read, write
- ❌ warren user test12659 nodes
- ❌ LRU caching
**Phase 3Multi-user ConcurrentDay 6-8**
- ❌ MountManager implementation
- ❌ 10 user parallel mount
- ❌ AJA concurrent write test
- ❌ 24h stability test
**Phase 4Performance OptimizationDay 9-12**
- ❌ Write buffering64KB 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.8FUSE Virtual File System版
---
## File Scan System2026-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
# 导入并计算hashskip_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 # 后台hash417s
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.7File Scan System版