Files
orc-order-v2/docs/superpowers/specs/2026-05-05-logging-tasks-files-design.md
T

9.0 KiB
Raw Blame History

日志系统 + 任务历史 + 文件管理 设计文档

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:writing-plans to create an implementation plan from this spec.

Goal: 为益选 OCR Web 系统添加持久化日志、任务历史和增强文件管理,提升生产环境可观测性和用户体验。

Architecture: 单一 SQLite 数据库 (data/web_data.db) 存储三类数据,FastAPI 中间件自动采集 HTTP 日志,TaskManager 改造为写入 DB,前端新增两个独立页面。

Tech Stack: FastAPI middleware, SQLite (via existing DBPool), Vue 3 + Element Plus, Pinia


1. 数据库设计

数据库文件: data/web_data.db,通过现有 DBPool 管理。

1.1 http_logs

CREATE TABLE IF NOT EXISTS http_logs (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    timestamp TEXT NOT NULL,       -- ISO 8601
    method TEXT NOT NULL,          -- GET/POST/PUT/DELETE
    path TEXT NOT NULL,            -- /api/memory
    status_code INTEGER,           -- 200, 404, 500
    duration_ms REAL,              -- 请求耗时(ms)
    user TEXT,                     -- 当前用户名
    ip TEXT,                       -- 客户端 IP
    detail TEXT                    -- 错误详情/备注
);
CREATE INDEX IF NOT EXISTS idx_http_logs_timestamp ON http_logs(timestamp);
CREATE INDEX IF NOT EXISTS idx_http_logs_status ON http_logs(status_code);

1.2 task_history

CREATE TABLE IF NOT EXISTS task_history (
    id TEXT PRIMARY KEY,           -- 8-char UUID
    name TEXT NOT NULL,            -- pipeline/ocr-batch/excel/merge/sync-push/sync-pull
    status TEXT NOT NULL,          -- pending/running/completed/failed
    progress INTEGER DEFAULT 0,
    message TEXT,
    result_files TEXT,             -- JSON array of filenames
    error TEXT,
    log_lines TEXT,                -- JSON array of log strings
    created_at TEXT NOT NULL,      -- ISO 8601
    updated_at TEXT NOT NULL,      -- ISO 8601
    completed_at TEXT              -- ISO 8601, null if not done
);
CREATE INDEX IF NOT EXISTS idx_task_history_status ON task_history(status);
CREATE INDEX IF NOT EXISTS idx_task_history_created ON task_history(created_at);

1.3 file_metadata

CREATE TABLE IF NOT EXISTS file_metadata (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    filename TEXT NOT NULL,
    directory TEXT NOT NULL,       -- input/output/result
    size INTEGER,
    action TEXT NOT NULL,          -- upload/delete/clear
    user TEXT,
    timestamp TEXT NOT NULL,       -- ISO 8601
    task_id TEXT                   -- 关联的任务 ID (可选)
);
CREATE INDEX IF NOT EXISTS idx_file_metadata_timestamp ON file_metadata(timestamp);

1.4 自动清理

30 天过期清理,在服务器启动时执行,之后每天通过 asyncio 定时任务执行一次:

async def cleanup_old_records():
    cutoff = (datetime.now() - timedelta(days=30)).isoformat()
    await db_pool.execute_write("DELETE FROM http_logs WHERE timestamp < ?", cutoff)
    await db_pool.execute_write("DELETE FROM task_history WHERE created_at < ?", cutoff)
    await db_pool.execute_write("DELETE FROM file_metadata WHERE timestamp < ?", cutoff)

2. 后端架构

2.1 新增文件

文件 职责
web/backend/services/db_schema.py 建表 SQL + init_db() + cleanup_old_records()
web/backend/middleware/logging.py HTTP 请求日志中间件
web/backend/routers/logs.py 日志查询 API
web/backend/routers/tasks.py 任务历史 API

2.2 修改文件

文件 改动
web/backend/main.py lifespan 中调用 init_db(),挂载 logging 中间件,注册 logs/tasks 路由
web/backend/services/task_manager.py update_progress()_finish() 写入 task_history 表
web/backend/routers/files.py upload/delete/clear 操作写入 file_metadata 表

2.3 API 端点

日志 (/api/logs)

  • GET /api/logs — 分页查询
    • 参数: page, page_size, method, status_code, path(搜索), start_date, end_date
    • 返回: { items: [...], total: number }
  • GET /api/logs/stats — 统计概览
    • 返回: { today_count, error_count, avg_duration_ms, error_rate }

任务历史 (/api/tasks)

  • GET /api/tasks — 分页查询
    • 参数: page, page_size, status, name(类型筛选), search
    • 返回: { items: [...], total: number }
  • GET /api/tasks/{task_id} — 任务详情(含完整 log_lines)
  • POST /api/tasks/{task_id}/retry — 重试失败任务
    • 根据 name 字段重新调用对应处理端点

文件历史 (/api/files)

  • GET /api/files/history — 文件操作记录
    • 参数: page, page_size, directory, action
    • 返回: { items: [...], total: number }
  • GET /api/files/stats — 存储统计
    • 返回: { directories: [{ name, file_count, total_size }] }

2.4 中间件设计

async def logging_middleware(request: Request, call_next):
    # 跳过静态资源和 WebSocket
    if request.url.path.startswith("/assets") or request.url.path.startswith("/ws"):
        return await call_next(request)

    start = time.time()
    response = await call_next(request)
    duration_ms = (time.time() - start) * 1000

    # 异步写入日志(不阻塞响应)
    asyncio.create_task(write_log(
        method=request.method,
        path=request.url.path,
        status_code=response.status_code,
        duration_ms=duration_ms,
        user=get_current_user_from_request(request),
        ip=request.client.host,
    ))
    return response

2.5 TaskManager 改造

现有 TaskManager.update_progress()_finish() 方法中增加 DB 写入:

async def update_progress(self, task_id: str, progress: int, message: str):
    task = self._tasks[task_id]
    task.progress = progress
    task.message = message
    task.log_lines.append(message)
    # 新增:写入 DB
    await self._db.execute_write(
        "UPDATE task_history SET progress=?, message=?, log_lines=?, updated_at=? WHERE id=?",
        progress, message, json.dumps(task.log_lines), datetime.now().isoformat(), task_id
    )
    await self._broadcast(task)

3. 前端设计

3.1 新增页面

侧边栏导航新增 2 项:

页面 路由 图标 标签
任务历史 /tasks Timer -
日志中心 /logs Notebook -

3.2 任务历史页面 (Tasks.vue)

布局:

  • 顶部统计卡片行(4 卡片):总任务数 / 成功 / 失败 / 运行中
  • 筛选栏:状态下拉(全部/成功/失败/运行中)+ 类型下拉(全部/pipeline/ocr/excel/merge+ 搜索框
  • 表格列:任务ID、类型、状态(彩色标签)、进度条、耗时、创建时间、操作
  • 操作:查看详情(弹窗显示完整日志流)、重试(仅失败任务)

详情弹窗:

  • 任务基本信息(类型/状态/耗时/结果文件)
  • 终端风格日志流(复用 Dashboard 的 log-box 样式)
  • 结果文件列表(可下载)

3.3 日志中心页面 (Logs.vue)

布局:

  • 顶部统计卡片行(4 卡片):今日请求 / 错误数 / 平均耗时 / 错误率
  • 筛选栏:时间范围选择器(今天/7天/30天)+ 方法筛选(GET/POST/PUT/DELETE+ 状态码筛选(2xx/4xx/5xx+ 路径搜索
  • 表格列:时间、方法(彩色标签)、路径、状态码(颜色区分)、耗时、用户
  • 点击行展开详情面板(IP 地址、错误信息)

3.4 Dashboard 增强

  • stats-row 第三列从硬编码 "记忆库 5591" 改为动态存储统计(磁盘用量)
  • 文件列表区新增「操作历史」按钮,弹窗显示该目录的 file_metadata 记录

3.5 新增文件

文件 职责
web/frontend/src/views/Tasks.vue 任务历史页面
web/frontend/src/views/Logs.vue 日志中心页面
web/frontend/src/stores/tasks.ts 任务历史状态管理(可选,可用 api 直接调用)

3.6 修改文件

文件 改动
web/frontend/src/views/Layout.vue navItems 新增 2 项
web/frontend/src/router/index.ts 新增 2 个路由
web/frontend/src/views/Dashboard.vue stats-row 动态化 + 文件历史弹窗

4. 安全与性能

  • 日志查询 API 仅限认证用户
  • HTTP 日志不记录请求体(避免泄露敏感数据)
  • 中间件使用 asyncio.create_task() 异步写入,不阻塞响应
  • 日志表索引:timestampstatus_codepath
  • 任务表索引:statuscreated_at
  • 自动清理 30 天前的记录,防止数据库无限增长
  • 分页查询默认 page_size=50,最大 200

5. 实施顺序

  1. Phase 1: 数据库 + 后端

    • db_schema.py(建表 + 清理)
    • logging 中间件
    • task_manager 改造
    • files.py 改造
    • logs.py + tasks.py 路由
  2. Phase 2: 前端页面

    • Tasks.vue
    • Logs.vue
    • Layout.vue 路由注册
    • Dashboard.vue 增强
  3. Phase 3: 集成测试

    • npm run build
    • 端到端验证:操作 → 日志记录 → 任务历史 → 文件历史