# 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/.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//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; fn filter_options(&self) -> Vec; } ``` ### 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/.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