TraceStudio-dev/docs/web1.1_filemanager/BACKEND_API_REQUIREMENTS.md
2026-01-07 21:31:22 +08:00

11 KiB
Raw Blame History

后端 API 需求文档

📋 概述

本文档描述了前端新增功能所需的后端 API 接口。这些接口用于支持多用户管理、节点数据持久化等功能。


🔌 新增 API 接口

1. 获取用户列表

接口信息

  • 路径: GET /api/users/list
  • 用途: 获取系统中所有用户的列表,用于用户切换下拉框显示
  • 优先级:

请求参数

响应格式

{
  "users": ["guest", "admin", "dev", "test", "user1", "user2"],
  "count": 6
}

响应字段说明

字段 类型 说明
users string[] 用户名列表
count integer 用户总数

实现建议

  1. 扫描 cloud/users/ 目录,返回所有子目录名称
  2. 按字母顺序排序
  3. 可以添加缓存机制TTL 60秒
  4. 排除系统目录(如 .git, __pycache__ 等)

示例代码

from fastapi import APIRouter
from pathlib import Path
from typing import List

router = APIRouter()

@router.get("/api/users/list")
async def list_users():
    """获取所有用户列表"""
    users_dir = Path("cloud/users")
    
    if not users_dir.exists():
        users_dir.mkdir(parents=True, exist_ok=True)
        return {"users": [], "count": 0}
    
    users = []
    for item in users_dir.iterdir():
        if item.is_dir() and not item.name.startswith('.'):
            users.append(item.name)
    
    users.sort()
    return {"users": users, "count": len(users)}

错误处理

  • 如果 cloud/users/ 不存在,自动创建并返回空列表
  • 权限问题返回 403 Forbidden

2. 保存节点数据

接口信息

  • 路径: POST /api/nodes/save
  • 用途: 保存单个节点的配置数据到服务器持久化存储
  • 优先级:

请求参数

Content-Type: application/json

{
  "nodeId": "n_1704614400000_1234",
  "nodeData": {
    "label": "我的CSV加载器",
    "file_path": "users/guest/data/sales.csv",
    "delimiter": ",",
    "meta": { ... },
    "preview": { ... }
  }
}

请求字段说明

字段 类型 必填 说明
nodeId string 节点唯一标识符
nodeData object 节点完整数据对象
nodeData.label string 节点自定义标题
nodeData.* any 其他节点参数

响应格式

成功响应 (200):

{
  "success": true,
  "nodeId": "n_1704614400000_1234",
  "savedAt": "2026-01-07T12:34:56.789Z"
}

失败响应 (400):

{
  "success": false,
  "error": "Invalid nodeId format"
}

实现建议

存储方案 A文件系统
# 存储路径: cloud/nodes/{nodeId}.json
import json
from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from pathlib import Path
from datetime import datetime

class NodeSaveRequest(BaseModel):
    nodeId: str
    nodeData: dict

@router.post("/api/nodes/save")
async def save_node(request: NodeSaveRequest):
    """保存节点数据到文件系统"""
    nodes_dir = Path("cloud/nodes")
    nodes_dir.mkdir(parents=True, exist_ok=True)
    
    # 验证 nodeId 格式
    if not request.nodeId.startswith('n_'):
        raise HTTPException(status_code=400, detail="Invalid nodeId format")
    
    # 添加元数据
    save_data = {
        "nodeId": request.nodeId,
        "nodeData": request.nodeData,
        "savedAt": datetime.utcnow().isoformat() + "Z"
    }
    
    # 保存到文件
    file_path = nodes_dir / f"{request.nodeId}.json"
    with open(file_path, 'w', encoding='utf-8') as f:
        json.dump(save_data, f, indent=2, ensure_ascii=False)
    
    return {
        "success": True,
        "nodeId": request.nodeId,
        "savedAt": save_data["savedAt"]
    }
存储方案 BSQLite 数据库
# 使用 SQLite 存储节点数据
import sqlite3
import json

def init_db():
    conn = sqlite3.connect('cloud/tracestudio.db')
    c = conn.cursor()
    c.execute('''
        CREATE TABLE IF NOT EXISTS nodes (
            node_id TEXT PRIMARY KEY,
            node_data TEXT NOT NULL,
            saved_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
        )
    ''')
    conn.commit()
    conn.close()

@router.post("/api/nodes/save")
async def save_node(request: NodeSaveRequest):
    """保存节点数据到数据库"""
    conn = sqlite3.connect('cloud/tracestudio.db')
    c = conn.cursor()
    
    c.execute('''
        INSERT OR REPLACE INTO nodes (node_id, node_data, saved_at)
        VALUES (?, ?, CURRENT_TIMESTAMP)
    ''', (request.nodeId, json.dumps(request.nodeData)))
    
    conn.commit()
    
    # 获取保存时间
    c.execute('SELECT saved_at FROM nodes WHERE node_id = ?', (request.nodeId,))
    saved_at = c.fetchone()[0]
    conn.close()
    
    return {
        "success": True,
        "nodeId": request.nodeId,
        "savedAt": saved_at
    }

使用场景

  1. 用户在 Inspector 面板编辑节点参数
  2. 点击 "💾 保存" 按钮
  3. 前端调用此 API 保存节点状态
  4. 可用于恢复节点配置、协作编辑等场景

扩展功能(可选)

  • 添加用户权限验证(只能保存自己的节点)
  • 节点版本控制(保存历史记录)
  • 批量保存接口 POST /api/nodes/batch-save

🔄 现有 API 增强建议

文件上传 API 增强

当前: POST /api/files/upload?path=xxx&username=xxx

建议增强:

  1. 支持批量上传(拖拽多个文件)
  2. 返回上传文件的详细信息(路径、大小、类型)
  3. 添加上传进度支持WebSocket 或 Server-Sent Events
@router.post("/api/files/upload")
async def upload_files(
    files: List[UploadFile],  # 支持多文件
    path: str = "",
    username: str = "guest"
):
    """批量上传文件"""
    results = []
    for file in files:
        # ... 上传逻辑 ...
        results.append({
            "filename": file.filename,
            "path": f"{path}/{file.filename}",
            "size": file.size,
            "status": "success"
        })
    
    return {
        "uploaded": len(results),
        "files": results
    }

📊 优先级排序

优先级 接口 原因
GET /api/users/list 用户切换下拉框依赖此接口无此接口会显示写死的4个用户
POST /api/nodes/save 节点持久化功能,不实现不影响基本使用
文件上传增强 已有基础功能,增强为优化体验

🧪 测试用例

测试用户列表 API

# 测试 1: 获取用户列表
curl http://localhost:8000/api/users/list

# 预期响应:
{
  "users": ["admin", "dev", "guest", "test"],
  "count": 4
}

# 测试 2: 空用户目录
rm -rf cloud/users/*
curl http://localhost:8000/api/users/list

# 预期响应:
{
  "users": [],
  "count": 0
}

测试节点保存 API

# 测试 1: 保存节点
curl -X POST http://localhost:8000/api/nodes/save \
  -H "Content-Type: application/json" \
  -d '{
    "nodeId": "n_1704614400000_1234",
    "nodeData": {
      "label": "测试节点",
      "file_path": "users/guest/data/test.csv"
    }
  }'

# 预期响应:
{
  "success": true,
  "nodeId": "n_1704614400000_1234",
  "savedAt": "2026-01-07T12:34:56.789Z"
}

# 测试 2: 无效节点ID
curl -X POST http://localhost:8000/api/nodes/save \
  -H "Content-Type: application/json" \
  -d '{
    "nodeId": "invalid_id",
    "nodeData": {}
  }'

# 预期响应: 400 Bad Request
{
  "success": false,
  "error": "Invalid nodeId format"
}

🔐 安全注意事项

1. 路径遍历防护

def validate_path(path: str) -> bool:
    """防止 ../ 路径遍历攻击"""
    safe_path = Path(path).resolve()
    base_path = Path("cloud/").resolve()
    return str(safe_path).startswith(str(base_path))

2. 文件大小限制

MAX_FILE_SIZE = 100 * 1024 * 1024  # 100MB
MAX_NODE_DATA_SIZE = 10 * 1024 * 1024  # 10MB

# 在上传和保存时检查大小
if len(json.dumps(request.nodeData)) > MAX_NODE_DATA_SIZE:
    raise HTTPException(413, "Node data too large")

3. 用户权限验证

def check_user_permission(username: str, resource_path: str) -> bool:
    """验证用户只能访问自己的资源"""
    if not resource_path.startswith(f"users/{username}/"):
        raise HTTPException(403, "Permission denied")

📦 数据库 Schema可选

如果使用数据库存储节点数据,建议的表结构:

-- 节点数据表
CREATE TABLE nodes (
    node_id TEXT PRIMARY KEY,
    node_type TEXT NOT NULL,
    node_data TEXT NOT NULL,  -- JSON 格式
    created_by TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    version INTEGER DEFAULT 1
);

-- 创建索引
CREATE INDEX idx_nodes_created_by ON nodes(created_by);
CREATE INDEX idx_nodes_created_at ON nodes(created_at);

-- 节点历史表(可选,用于版本控制)
CREATE TABLE node_history (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    node_id TEXT NOT NULL,
    node_data TEXT NOT NULL,
    version INTEGER NOT NULL,
    saved_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (node_id) REFERENCES nodes(node_id)
);

🚀 实施步骤

阶段 1: 基础功能(立即实施)

  1. 实现 GET /api/users/list 接口
  2. 测试用户列表显示

阶段 2: 节点持久化(后续实施)

  1. 实现 POST /api/nodes/save 接口
  2. 添加节点加载接口 GET /api/nodes/{nodeId}
  3. 添加节点列表接口 GET /api/nodes/list

阶段 3: 增强功能(可选)

  1. ⏸️ 节点版本控制
  2. ⏸️ 多用户协作编辑
  3. ⏸️ 节点模板管理

📝 前端调用示例

获取用户列表

// web/src/components/HeaderBar.tsx
React.useEffect(() => {
  const fetchUsers = async () => {
    try {
      const response = await fetch('/api/users/list')
      if (response.ok) {
        const data = await response.json()
        setUserList(data.users)
      }
    } catch (error) {
      console.warn('获取用户列表失败,使用默认列表')
    }
  }
  fetchUsers()
}, [])

保存节点数据

// web/src/components/Inspector.tsx
const handleSaveNode = async () => {
  try {
    const response = await fetch('/api/nodes/save', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        nodeId: node.id,
        nodeData: node.data
      })
    })
    
    if (response.ok) {
      const result = await response.json()
      alert(`✅ 节点已保存: ${result.savedAt}`)
    } else {
      const error = await response.text()
      alert(`❌ 保存失败: ${error}`)
    }
  } catch (error) {
    alert(`❌ 网络错误: ${error}`)
  }
}

🔄 版本历史

版本 日期 更新内容
v1.0 2026-01-07 初始版本定义用户列表和节点保存API

📧 联系方式

如有疑问或建议,请通过以下方式联系:

  • GitHub Issues: [TraceStudio Issues]
  • 文档维护者: 前端开发团队