Files
markbase/AGENTS.md
T

612 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 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**
**版本:1.3CI修復成功版)**