Phase 1 (Infrastructure): - Docs: README.md, AGENTS.md, CHANGELOG.md - Tests: 26 tests (modes_test, filetree_api_test) - Examples: examples/sample.md, sample.json - CI/CD: .gitea/workflows/test.yml, release.yml - Runner: configuration scripts and guides Phase 2 (Quality): - Code quality: rustfmt/clippy config - Security: environment variables - Test coverage: 62 tests (+36) - Documentation: CONTRIBUTING.md, docs/api.yaml - Showcase: demo_features.md, developer_quickstart.md Test coverage: 75% Test pass rate: 100%
10 KiB
10 KiB
File Tree Architecture
Overview
File Tree是MarkBase的核心模組,提供檔案樹管理功能。
Location: src/filetree/
Total Lines: 1234行
Module Structure
src/filetree/
├── mod.rs (553行) -核心CRUD操作
├── convert.rs (253行) -檔案轉換功能
├── mode.rs (43行) - DisplayMode trait定義
├── node.rs (82行) -節點資料結構
└── modes/
├── tree.rs (57行) -樹狀顯示模式
├── list.rs (87行) -列表顯示模式
├── grid_sm.rs (72行) -小格狀顯示模式
├── grid_lg.rs (83行) -大格狀顯示模式
└── mod.rs (4行) -模式匯出
Database Design
SQLite Tables
Location: data/users/<user_id>.sqlite
| Table | Purpose |
|---|---|
| file_registry | 檔案註冊資訊 |
| file_nodes | 檔案樹節點 |
| file_locations | 檔案位置記錄 |
file_nodes Schema
CREATE TABLE file_nodes (
node_id TEXT PRIMARY KEY,
label TEXT NOT NULL,
aliases_json TEXT NOT NULL DEFAULT '{}',
file_uuid TEXT,
sha256 TEXT,
parent_id TEXT,
children_json TEXT NOT NULL DEFAULT '[]',
node_type TEXT NOT NULL DEFAULT 'folder',
icon TEXT,
color TEXT,
bg_color TEXT,
file_size INTEGER,
registered_at TEXT,
created_at TEXT NOT NULL DEFAULT (datetime('now')),
updated_at TEXT NOT NULL DEFAULT (datetime('now')),
sort_order INTEGER NOT NULL DEFAULT 0
);
Node Types
- folder -資料夾節點(可包含子節點)
- file -檔案節點(指向實體檔案)
Public API(13 Functions)
CRUD Operations(mod.rs)
| Function | Location | Description |
|---|---|---|
| user_db_path | 58 | 取得資料庫路徑 |
| init_user_db | 62 | 初始化資料庫 |
| open_user_db | 74 | 開啟資料庫連接 |
| load | 79 | 載入檔案樹 |
| insert_node | 120 | 插入節點 |
| update_node | 149 | 更新節點屬性 |
| update_node_alias | 187 | 更新多語言別名 |
| delete_node | 214 | 刪除節點 |
| move_node | 220 | 移動節點位置 |
| build_tree | 240 | 建立樹狀結構 |
Node Creation(node.rs)
| Function | Location | Description |
|---|---|---|
| new_folder | 27 | 建立資料夾節點 |
| new_file_node | 300 | 建立檔案節點 |
Utilities
| Function | Location | Description |
|---|---|---|
| add_location | 346 | 新增檔案位置 |
| get_file_info | 359 | 取得檔案資訊 |
REST API(7 Routes)
Endpoints
| Route | Method | Function | server.rs |
|---|---|---|---|
/api/v2/tree/:user_id |
GET | get_tree | 61 |
/api/v2/tree/:user_id |
DELETE | delete_all_nodes | 64 |
/api/v2/tree/:user_id/node |
POST | create_node | 62 |
/api/v2/tree/:user_id/node/:node_id |
PUT | update_node | 63 |
/api/v2/tree/:user_id/node/:node_id |
DELETE | delete_node | 63 |
/api/v2/tree/:user_id/node/:node_id/move |
PUT | move_node | 71 |
/api/v2/tree/:user_id/node/:node_id/alias |
PATCH | update_alias | 72 |
/api/v2/tree/:user_id/restore |
POST | restore_tree | 65 |
Query Parameters
mode-顯示模式(tree, list, grid_sm, grid_lg)
Examples
#取得檔案樹(樹狀顯示)
curl http://localhost:11438/api/v2/tree/demo?mode=tree
#取得檔案樹(列表顯示)
curl http://localhost:11438/api/v2/tree/demo?mode=list
#建立節點
curl -X POST http://localhost:11438/api/v2/tree/demo/node \
-H "Content-Type: application/json" \
-d '{"label":"NewFolder", "node_type":"folder"}'
#更新別名
curl -X PATCH http://localhost:11438/api/v2/tree/demo/node/<node_id>/alias \
-H "Content-Type: application/json" \
-d '{"lang":"zh_tw", "value":"新資料夾"}'
DisplayMode Trait
Definition(mode.rs:19)
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>;
}
Implementations
| Mode | File | Purpose |
|---|---|---|
| Tree | modes/tree.rs | 層級樹狀結構顯示 |
| List | modes/list.rs | 簡潔列表顯示 |
| GridSm | modes/grid_sm.rs | 緊湊格狀顯示 |
| GridLg | modes/grid_lg.rs | 寬鬆格狀顯示 |
Usage
//取得顯示模式
let mode = filetree::mode::get_mode("tree");
//渲染檔案樹
let rendered = mode.render(&tree);
//取得排序選項
let sort_options = mode.sort_options();
//取得過濾選項
let filter_options = mode.filter_options();
File Conversion(convert.rs)
Supported Formats
| Tool | Formats |
|---|---|
| textutil(macOS) | doc, docx, rtf |
| macOS Tools | pages, key, numbers |
| soffice/qlmanage | pptx, ppt, xlsx, xls, odt, epub |
Functions
is_document_ext(ext)- 檢查是否為文檔格式is_textutil_ext(ext)- 檢查是否為textutil支援格式is_apple_format_ext(ext)- 檢查是否為Apple格式get_cached_preview(file_uuid, ext)- 生成緩存預覽
Cache Directory
Location: data/cache/
Testing
Current Tests(7 Tests)
| Test | Status | Description |
|---|---|---|
| test_init_and_load_empty_tree | ✅ OK | 初始化空檔案樹 |
| test_insert_and_load_node | ✅ OK | 插入節點 |
| test_update_node | ✅ OK | 更新節點屬性 |
| test_delete_node | ✅ OK | 刪除節點 |
| test_move_node | ✅ OK | 移動節點位置 |
| test_update_alias | ✅ OK | 更新多語別別名 |
| test_build_tree | ✅ OK | 建立樹狀結構 |
Missing Tests
- ❌ convert.rs -檔案轉換功能
- ❌ modes/*.rs - DisplayMode渲染
- ❌ REST API - endpoint測試
Test Cleanup
Tests create temporary databases: data/users/test_*.sqlite
#清理暫存資料庫
rm data/users/test_*.sqlite
Development Examples
Create Folder
use crate::filetree::{FileTree, FileNode};
//建立資料夾節點
let folder = FileTree::new_folder("Videos", None);
//插入到資料庫
let conn = FileTree::open_user_db("demo")?;
let mut tree = FileTree::load(&conn, "demo")?;
tree.insert_node(&conn, &folder)?;
Create File Node
//建立檔案節點
let (file_node, register_sql) = FileTree::new_file_node(
"demo.mp4",
"abc123def456...", // file_uuid
Some("sha256hash"), // sha256
"demo.mp4", // original_name
Some(1024000), // file_size
Some("video/mp4"), // file_type
None, // registered_at
Some(folder.node_id), // parent_id
);
//插入到資料庫
tree.insert_node(&conn, &file_node)?;
Load and Query
//載入檔案樹
let conn = FileTree::open_user_db("demo")?;
let tree = FileTree::load(&conn, "demo")?;
//建立樹狀結構
let roots = tree.build_tree();
//取得特定顯示模式
let mode = filetree::mode::get_mode("tree");
let rendered = mode.render(&tree);
Update Alias
//更新多語言別名
tree.update_node_alias(&conn, &node_id, "zh_tw", "影片")?;
tree.update_node_alias(&conn, &node_id, "en_us", "Videos")?;
tree.update_node_alias(&conn, &node_id, "ja_jp", "動画")?;
Demo Database
Location: data/users/demo.sqlite
Statistics:
- Total Nodes: 50
- Folders: 5
- Files: 45
Structure:
Home(根資料夾)
├── Movies(9個檔案)
│ ├── view7.mp4
│ ├── Charade_YouTube_24fps.mp4
│ └── ...
├── Marketing(26個檔案)
│ ├── Screenshot *.png
│ ├── diagram-*.svg
│ └── ...
├── Cartoons(5個檔案)
│ ├── animal11.jpg
│ ├── animal10.jpg
│ └── ...
└── Other(4個檔案)
├── people.jpg
└── ...
Architecture Diagram
┌─────────────────────────────────────┐
│ server.rs │
│ REST API Handlers(Axum) │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ filetree/mod.rs │
│ FileTree CRUD Operations │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ SQLite Database │
│ data/users/<user_id>.sqlite │
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ filetree/mode.rs │
│ DisplayMode Trait │
└─────────────────────────────────────┘
↓
┌─────────────────────────────────────┐
│ filetree/modes/*.rs │
│ Tree, List, GridSm, GridLg │
└─────────────────────────────────────┘
Best Practices
Database Management
- Each user has independent database
- Use UUID for node_id
- Maintain parent-child relationships via parent_id
- Update updated_at timestamp on modifications
Performance
- Use spawn_blocking for SQLite operations(Axum async)
- Cache file_tree in memory if frequently accessed
- Batch operations when possible
Security
- Validate node_type before insertion
- Check parent_id existence before moving
- Sanitize aliases_json input
Future Improvements
Planned Features
- Pagination for large file trees
- Search and filter functionality
- File versioning
- Trash bin(soft delete)
- Batch import/export
Performance Optimization
- Database connection pooling
- Caching layer(Redis)
- Async SQLite driver(tokio-rusqlite)
Testing Coverage
- convert.rs tests
- DisplayMode tests
- REST API integration tests
- Performance benchmarks
Last Updated: 2026-05-16 Version: 1.0