518 lines
14 KiB
Markdown
518 lines
14 KiB
Markdown
# 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/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)
|
||
|
||
**支援格式轉換:**
|
||
|
||
|工具 |支援格式 |
|
||
|------|----------|
|
||
| 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);
|
||
````
|
||
|
||
---
|
||
|
||
##測試執行
|
||
|
||
###執行測試
|
||
|
||
```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
|
||
````
|
||
|
||
---
|
||
|
||
**最後更新:2026-05-16**
|
||
**版本:1.0(file tree優先版)** |