# 小财记账系统重构计划 > **文档状态**:讨论稿 > **创建日期**:2026-07-22 > **目的**:识别当前系统的设计缺陷与脆弱点,规划结构化改进方案,从“能用”走向“好用”。 --- ## 一、当前系统现状概述 经过多轮迭代,系统已具备以下核心功能: - 多用户登录、群聊管理、白名单权限 - 聊天消息发送(文本+图片)、WebSocket实时推送 - AI自动识别采购/付款/发票意图,创建采购记录 - 采购清单(按月汇总)、采购详情(含操作历史、附件) - 删除/清空采购记录(管理员确认流程) - 图片压缩上传、附件关联 - 移动端滑动手势、双击全屏、输入中气泡 - 导出CSV、全局采购汇总 **但所有功能都是“快速响应需求”的结果,缺乏统一设计,代码结构脆弱,修改一处容易引发多处问题。** --- ## 二、当前系统的主要问题与重构方向 ### 2.1 数据库与领域模型 **存在问题**: - `purchases` 表字段通过多次 `ALTER TABLE` 添加,历史数据可能格式不一致(如 `created_at` 有时间和无时间两种格式)。 - 金额计算规则散落在多处代码中,存在“AI返回金额”、“系统自动计算金额”两套逻辑,容易出错。 - 状态机不明确(待处理/已采购/发票已收/已完成),更新时未严格约束状态转换。 - 删除/清空操作依赖业务层手动管理级联,SQLite外键未开启。 **改进方向**: 1. **统一时间格式**:所有 `created_at` 和 `updated_at` 强制使用 `yyyy/MM/dd HH:mm:ss` 格式,在服务端工具函数中生成,不再依赖数据库默认值。 2. **金额计算唯一化**:`amount` 字段仅由系统计算(`quantity * unit_price + freight`),AI 不再提供该字段。删除所有 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 行,难以维护。 - 状态管理混乱:`messageCache`、`rooms`、`pendingFiles` 等全局变量散落,修改时容易出现不一致。 - 消息渲染使用 `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 token(1小时)+ 长期 refresh token(7天)。 2. **上传频率限制**:使用 `express-rate-limit` 限制每用户每天上传次数。 3. **密码哈希**:用户密码存储为 bcrypt 哈希,不再明文比较(需要修改登录逻辑和 `.env` 配置方式)。 --- ### 2.6 运维与部署 **存在问题**: - 数据库迁移依赖手动 `ALTER TABLE` 加 `try/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` 对象)