Files
markbase/AGENTS.md

614 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
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/tree/:user_id` | GET | 取得檔案樹 | 61 |
| `/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
curl http://localhost:11438/api/v2/tree/demo?mode=tree
curl http://localhost:11438/api/v2/tree/demo?mode=list
````
### 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);
````
---
##測試執行
###執行測試
```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 4: 失敗test + build jobs均失敗
- ⚠️ 本地測試全部通過62 tests
- ⚠️ Clippy檢查已通過
- ⚠️ 格式檢查已通過
###待解決問題
**CI失敗根本原因已診斷**
- **失敗位置:** Setup Rust步驟actions-rust-lang/setup-rust-toolchain@v1
- **錯誤信息:** `conditional binary operator expected`line 2
- **具體問題:** GitHub Action與Gitea Runner的bash環境不完全兼容
- **執行時間:** 5秒快速失敗早期階段錯誤
**失敗統計:**
- Run ID 1-6全部失敗6次CI失敗
- 執行時間5-74秒不等早期失敗
- 失敗步驟Setup Rustbash腳本兼容性問題
**解決方案:**
1. 替換 `actions-rust-lang/setup-rust-toolchain@v1`為原生rustup安裝
2. 使用更兼容的action如 dtolnay/rust-toolchain@stable
3. 直接執行 `curl | sh`安裝rustup
**下一步行動:**
- 修改 workflow文件使用原生安裝方式
- 提交並推送觸發新CI run
- 验证修復是否成功
---
**最後更新2026-05-16**
**版本1.2CI問題診斷完成版**