feat: MarkBase initial version
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%
This commit is contained in:
413
docs/filetree.md
Normal file
413
docs/filetree.md
Normal file
@@ -0,0 +1,413 @@
|
||||
# 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
|
||||
|
||||
```sql
|
||||
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
|
||||
|
||||
```bash
|
||||
#取得檔案樹(樹狀顯示)
|
||||
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)
|
||||
|
||||
```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>;
|
||||
}
|
||||
```
|
||||
|
||||
### Implementations
|
||||
|
||||
|Mode |File |Purpose |
|
||||
|------|------|---------|
|
||||
| Tree | modes/tree.rs |層級樹狀結構顯示 |
|
||||
| List | modes/list.rs |簡潔列表顯示 |
|
||||
| GridSm | modes/grid_sm.rs |緊湊格狀顯示 |
|
||||
| GridLg | modes/grid_lg.rs |寬鬆格狀顯示 |
|
||||
|
||||
### Usage
|
||||
|
||||
```rust
|
||||
//取得顯示模式
|
||||
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`
|
||||
|
||||
```bash
|
||||
#清理暫存資料庫
|
||||
rm data/users/test_*.sqlite
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Development Examples
|
||||
|
||||
### Create Folder
|
||||
|
||||
```rust
|
||||
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
|
||||
|
||||
```rust
|
||||
//建立檔案節點
|
||||
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
|
||||
|
||||
```rust
|
||||
//載入檔案樹
|
||||
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
|
||||
|
||||
```rust
|
||||
//更新多語言別名
|
||||
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
|
||||
Reference in New Issue
Block a user