Files
ai-xiaocai/docs/v2.md
2026-07-22 17:13:35 +08:00

9.2 KiB
Raw Blame History

小财记账系统重构计划

文档状态:讨论稿
创建日期2026-07-22
目的:识别当前系统的设计缺陷与脆弱点,规划结构化改进方案,从“能用”走向“好用”。


一、当前系统现状概述

经过多轮迭代,系统已具备以下核心功能:

  • 多用户登录、群聊管理、白名单权限
  • 聊天消息发送(文本+图片、WebSocket实时推送
  • AI自动识别采购/付款/发票意图,创建采购记录
  • 采购清单(按月汇总)、采购详情(含操作历史、附件)
  • 删除/清空采购记录(管理员确认流程)
  • 图片压缩上传、附件关联
  • 移动端滑动手势、双击全屏、输入中气泡
  • 导出CSV、全局采购汇总

但所有功能都是“快速响应需求”的结果,缺乏统一设计,代码结构脆弱,修改一处容易引发多处问题。


二、当前系统的主要问题与重构方向

2.1 数据库与领域模型

存在问题

  • purchases 表字段通过多次 ALTER TABLE 添加,历史数据可能格式不一致(如 created_at 有时间和无时间两种格式)。
  • 金额计算规则散落在多处代码中存在“AI返回金额”、“系统自动计算金额”两套逻辑容易出错。
  • 状态机不明确(待处理/已采购/发票已收/已完成),更新时未严格约束状态转换。
  • 删除/清空操作依赖业务层手动管理级联SQLite外键未开启。

改进方向

  1. 统一时间格式:所有 created_atupdated_at 强制使用 yyyy/MM/dd HH:mm:ss 格式,在服务端工具函数中生成,不再依赖数据库默认值。
  2. 金额计算唯一化amount 字段仅由系统计算(quantity * unit_price + freightAI 不再提供该字段。删除所有 AI 返回 amount 的处理逻辑。
  3. 定义采购状态机待采购 → 已采购 → 发票已收 → 已完成,更新状态时检查合法性。
  4. 开启外键约束:在 db.js 中启用 PRAGMA foreign_keys = ON;,确保级联删除安全。

2.2 AI 交互层

存在问题

  • Prompt 分散在 analyzeWithDeepSeek 函数中,规则越来越多,难以维护。
  • AI 返回的 JSON 格式不稳定,有时带 reply 有时不带,有时 action 与字段不匹配。
  • 上下文管理简陋:对话历史只保留最近 40 条无摘要压缩token 使用效率低。
  • 附件补充、删除确认、权限判断等场景AI 表现不稳定,经常误判意图。

改进方向

  1. Prompt 模板化:将 system prompt 拆分为多个模块(角色定义、意图分类、采购规则、删除规则、附件规则、权限规则),动态拼接。
  2. JSON Schema 校验:定义每种 action 对应的必选/可选字段,服务端在解析 AI 返回后立即校验,不符合的驳回或修正。
  3. 上下文管理升级
    • 近期消息30 条)保持完整 messages 数组。
    • 超过 30 条时,调用 AI 生成结构化摘要(当前采购清单),作为 system 消息注入。
  4. 附件与更新逻辑分离
    • 附件请求仅返回 purchase_item,不包含金额/数量字段,后端强制匹配已有记录并插入附件。
    • 更新请求必须明确给出变化字段,后端对比后仅更新真正变化的列。

2.3 后端架构

存在问题

  • 所有业务逻辑AI 调用、数据库操作、权限判断)混在 server.js 单文件中,超过 600 行,难以维护。
  • 错误处理不统一:有的地方静默失败,有的地方只打印日志,用户得不到反馈。
  • 权限检查仅通过中间件 adminOnly,但删除/清空的权限还依赖 AI 判断,存在双重标准。

改进方向

  1. 模块化拆分
    • routes/Express 路由auth, rooms, messages, purchases, upload
    • ai/Prompt 模板、AI 调用、结果解析与校验
    • db/:数据库操作封装(含迁移逻辑)
    • ws/WebSocket 管理(连接、房间、广播)
  2. 统一错误处理中间件:自定义错误类,全局捕获并返回标准 JSON 格式。
  3. 权限统一:删除/清空操作仅在后端检查管理员权限AI 不再参与权限判断(只负责识别意图)。

2.4 前端架构

存在问题

  • 单文件 HTML 包含所有 CSS/JS超过 800 行,难以维护。
  • 状态管理混乱:messageCacheroomspendingFiles 等全局变量散落,修改时容易出现不一致。
  • 消息渲染使用 innerHTML 直接拼接,存在 XSS 风险(虽然做了部分转义,但 Markdown 渲染绕过)。
  • 图片加载、滚动位置控制不稳定,经常出现自动跳转。

改进方向

  1. 文件拆分CSS 独立文件、JS 按功能模块拆分(登录、聊天、清单、管理),使用 ES modules 或构建工具(如 esbuild打包。
  2. 虚拟 DOM 或模板引擎:考虑引入轻量框架(如 Preact 或 lit-html避免手动拼接 HTML同时解决 XSS 问题。
  3. 状态管理:将所有全局状态集中到一个 store 对象,通过事件或 Proxy 驱动 UI 更新。
  4. 消息渲染优化:图片加载完成后才调整滚动位置,防止跳动;使用懒加载。

2.5 安全性

存在问题

  • JWT secret 使用随机字符串,但未设置过期刷新机制,长期有效。
  • 文件上传仅限制格式和大小,未限制上传频率,有被滥用的风险。
  • 用户密码在环境变量中明文存储,传输时未加密(仅 HTTPS 保护)。

改进方向

  1. JWT 刷新:增加 refresh token 机制,短期 access token1小时+ 长期 refresh token7天
  2. 上传频率限制:使用 express-rate-limit 限制每用户每天上传次数。
  3. 密码哈希:用户密码存储为 bcrypt 哈希,不再明文比较(需要修改登录逻辑和 .env 配置方式)。

2.6 运维与部署

存在问题

  • 数据库迁移依赖手动 ALTER TABLEtry/catch,日志不完善,问题难排查。
  • 图片存储使用本地磁盘,容器重建后丢失(除非挂载卷)。
  • 无备份机制,数据风险高。

改进方向

  1. 自动化迁移:使用 better-sqlite3 的迁移工具或自定义版本管理系统,记录已执行迁移。
  2. 对象存储:支持 S3 兼容存储(如 MinIO、阿里云 OSS作为图片存储后端本地仅做缓存。
  3. 定时备份:通过 cronjob 定期导出 SQLite 数据库和上传目录。

三、优先重构顺序建议

优先级 模块 原因
P0 AI交互层Prompt模板化、JSON Schema校验、附件逻辑分离 直接影响用户体验,当前最不稳定
P0 金额计算唯一化、时间格式统一 数据一致性基础,错误频发
P1 后端模块化拆分 为后续开发铺路,当前单文件难以维护
P1 权限模型统一 安全风险目前依赖AI判断不可靠
P2 前端状态管理与文件拆分 改善开发体验和运行稳定性
P3 安全增强JWT、密码哈希、上传限制 系统公开使用后必须处理
P3 运维自动化(备份、存储迁移) 数据安全,长期运行保障

修改记录

server/
├── server.js              # 入口40行原 588行
├── db.js                  # 数据库(新增 foreign_keys = ON
├── utils.js               # timestamp / normalizeTime
├── handlers.js            # AI 结果处理 + 共享状态
├── ai/
│   ├── prompt.js          # Prompt 模板化
│   ├── validator.js       # JSON Schema 校验
│   └── client.js          # DeepSeek API 客户端
├── middleware/
│   └── auth.js            # JWT + adminOnly
├── routes/
│   ├── auth.js            # 登录 / 用户信息
│   ├── rooms.js           # 群聊 CRUD
│   ├── messages.js        # 消息 + AI 分析
│   └── purchases.js       # 采购 CRUD / 汇总 / 导出
├── ws/
│   └── index.js           # WebSocket 连接管理 + 广播
└── public/
    ├── index.html         # 纯结构(引用 CSS/JS
    ├── css/
    │   └── style.css      # 独立样式
    └── js/
        ├── store.js       # 全局状态
        ├── chat.js        # 消息渲染 + 图片处理
        ├── ws.js          # WebSocket + 聊天列表 + 发送
        ├── purchases.js   # 采购面板 + 详情 + 群聊管理 + 手势
        └── auth.js        # 登录 / 初始化

P0 完成项

  • Prompt 模板化(ai/prompt.js
  • JSON Schema 校验(ai/validator.js
  • AI 客户端封装(ai/client.js
  • 金额计算唯一化(handlers.js 中 amount 仅由系统计算)
  • 时间格式统一(utils.js normalizeTime

P1 完成项

  • 后端模块化拆分routes / ai / ws / middleware
  • 权限模型统一middleware/auth.js
  • 外键约束开启(db.js PRAGMA foreign_keys = ON

P2 完成项

  • CSS 独立文件(public/css/style.css
  • JS 模块化拆分store / chat / ws / purchases / auth
  • 状态集中管理(Store 对象)