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:
Warren
2026-05-16 15:37:37 +08:00
commit e3d6b60825
50 changed files with 7758 additions and 0 deletions

413
docs/filetree.md Normal file
View 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 API13 Functions
### CRUD Operationsmod.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 Creationnode.rs
|Function |Location |Description |
|----------|----------|-------------|
| new_folder | 27 |建立資料夾節點 |
| new_file_node | 300 |建立檔案節點 |
### Utilities
|Function |Location |Description |
|----------|----------|-------------|
| add_location | 346 |新增檔案位置 |
| get_file_info | 359 |取得檔案資訊 |
---
## REST API7 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
### Definitionmode.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 Conversionconvert.rs
### Supported Formats
|Tool |Formats |
|------|---------|
| textutilmacOS | 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 Tests7 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根資料夾
├── Movies9個檔案
│ ├── view7.mp4
│ ├── Charade_YouTube_24fps.mp4
│ └── ...
├── Marketing26個檔案
│ ├── Screenshot *.png
│ ├── diagram-*.svg
│ └── ...
├── Cartoons5個檔案
│ ├── animal11.jpg
│ ├── animal10.jpg
│ └── ...
└── Other4個檔案
├── people.jpg
└── ...
```
---
## Architecture Diagram
```
┌─────────────────────────────────────┐
│ server.rs │
│ REST API HandlersAxum
└─────────────────────────────────────┘
┌─────────────────────────────────────┐
│ 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 operationsAxum 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 binsoft delete
- Batch import/export
### Performance Optimization
- Database connection pooling
- Caching layerRedis
- Async SQLite drivertokio-rusqlite
### Testing Coverage
- convert.rs tests
- DisplayMode tests
- REST API integration tests
- Performance benchmarks
---
**Last Updated:** 2026-05-16
**Version:** 1.0