From 666bf5693395745769b9227f13013169924b45b7 Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Wed, 10 Jun 2026 23:53:32 +0800 Subject: [PATCH] chore: release v1.0.31 Co-Authored-By: Claude Sonnet 4.6 --- CHANGELOG.md | 5 + todo/todo.html | 342 ++++++++++++++++++++++++++++++++++++++++++++++++- todo/todo.json | 186 ++++++++++++++++++++++++++- 3 files changed, 528 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f79b71d..60b6fee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.0.31] - 2026-06-10 + +### 修复 +- 修复 Windows 客户端构建失败:授权到期横幅与弹窗方法位置错误导致编译报错 + ## [1.0.30] - 2026-06-10 ### 新功能 diff --git a/todo/todo.html b/todo/todo.html index ed751fd..6af8e5d 100644 --- a/todo/todo.html +++ b/todo/todo.html @@ -223,8 +223,8 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }

酒库管理系统 — 项目 TODO

生成于 2026-06-10 · 真相源 todo/todo.json
-
24全部
-
2待开始
+
36全部
+
14待开始
0开发中
8待验收
14已验收
@@ -269,7 +269,7 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
- 📋 待开始 2 + 📋 待开始 14 ▴ 收起
@@ -303,6 +303,258 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
+
  • +
    + 修复库存扣减 TOCTOU 竞态:SUM 预检纳入事务且在 FOR UPDATE 加锁后执行 +
    + 待开始 + 高优 · 紧急 + 二级 + + +
    +
    + +
    stock.go ApproveStockOut 中库存总量 SUM 在 FOR UPDATE 加锁前执行,存在 check-then-act 窗口,高并发下可超扣。需将预检 SUM 也放入事务并在加锁后执行
    + + +
  • + +
  • +
    + 统一 handler Update 改用白名单字段更新,防止 GORM Save() 跨租户覆盖 +
    + 待开始 + 高优 · 紧急 + 二级 + + +
    +
    + +
    partner.go/product_attr.go/warehouse.go 等多处用 db.Save(&object) 更新全字段,若中间件被绕过会造成 shop_id 被覆盖。改为 db.Model(&x).Where("id=? AND shop_id=?").Updates(fields) 白名单模式
    + + +
  • + +
  • +
    + 添加库存与财务流水定期对账检查,防止事务中断导致不平账 +
    + 待开始 + 高优 · 紧急 + 二级 + + +
    +
    + +
    出库审批若 DB 断连,Rollback 后库存正确但财务记录可能未落地。需添加对账脚本:SUM(InventoryLog.quantity by direction) == SUM(Inventories.quantity),及告警机制
    + + +
  • + +
  • +
    + 迁移 License 激活逻辑到 license_devices 表,废弃 licenses.device_id 字段 +
    + 待开始 + 重要 + 二级 + + +
    +
    + +
    licenses.device_id 已标记 deprecated 但激活/解绑逻辑仍在使用它,license_devices 表未被完整采用。需将 Activate/Deactivate 逻辑迁移至 license_devices,并写数据迁移脚本
    + + +
  • + +
  • +
    + 将 checkInventory 业务逻辑从 StockOutHandler 移到 Service 层 +
    + 待开始 + 重要 + 二级 + + +
    +
    + +
    checkInventory 实现在 handler/stock_out.go 中而非 service 层,导致单元测试困难、逻辑无法复用。应移至 StockService 或 InventoryService
    + + +
  • + +
  • +
    + 统一后端 API 错误响应格式为 {code, message},创建 util/response.go +
    + 待开始 + 重要 + 二级 + + +
    +
    + +
    各 handler 返回格式不一致:有的 {error: err.Error()},有的 {error: 硬编码字符串},有的直接 struct。前端解析困难。需定义 ErrorResponse struct 和 RespondError/RespondSuccess 辅助函数统一调用
    + + +
  • + +
  • +
    + 生产环境 CORS 强制校验:非 debug 模式禁止 Origin=* +
    + 待开始 + 重要 + 三级 + + +
    +
    + +
    config.go 默认 CORSOrigin="*",注释提示生产需改但无代码强制。应在 main.go 中添加:server.mode!=debug 且 CORSOrigin=="*" 时 log.Fatal 拒绝启动
    + + +
  • + +
  • +
    + License 私钥未配置时改为 Fatal 而非静默跳过 +
    + 待开始 + 重要 + 三级 + + +
    +
    + +
    license.go 中私钥未配置只打 log 并跳过,导致授权功能失效但程序正常运行。应改为 log.Fatal,确保运维人员知晓配置缺失
    + + +
  • + +
  • +
    + 统一各 handler 的 pageSize 上限校验,创建 util.ValidatePageSize() +
    + 待开始 + 重要 + 三级 + + +
    +
    + +
    inventory.go 限制 pageSize 最大 500,其他 handler 无此限制,前端可传 pageSize=10000 打满 DB。创建 util.ValidatePageSize(n) 统一处理
    + + +
  • +
  • 🕐 2026-06-08 +
  • +
    + + +
  • +
    + 将拼音回填从启动逻辑改为一次性迁移脚本 +
    + 待开始 + 一般 / 优化 + 三级 + + +
    +
    + +
    main.go 每次启动执行 backfillPinyin 全表扫描,数据量大后拖慢启动。改为 go run ./cmd/migrate-pinyin 一次性迁移,后续新数据靠写入时自动生成
    + + +
  • + +
  • +
    + DB 连接池参数(MaxIdleConns/MaxOpenConns)改为可配置项 +
    + 待开始 + 一般 / 优化 + 三级 + + +
    +
    + +
    main.go 中硬编码 MaxIdleConns=10, MaxOpenConns=100,无法运维调优。改为读取 config(viper),并在文档中说明推荐值
    + + +
  • + +
  • +
    + 明确 Inventories 反范式字段语义:是当前值还是入库快照 +
    + 待开始 + 一般 / 优化 + 二级 + + +
    +
    + +
    inventories 表存了 product_name/warehouse_name/supplier_name 等,既可能是冗余(与 products JOIN 重复),也可能是历史快照(入库时锁定)。需明确语义并在 model 注释中说明;若是快照,应只在写入时固定,不随主表变化
    + +
  • diff --git a/todo/todo.json b/todo/todo.json index d31ffd6..e80689e 100644 --- a/todo/todo.json +++ b/todo/todo.json @@ -1,9 +1,9 @@ { "meta": { "title": "酒库管理系统 — 项目 TODO", - "updated_at": "2026-06-10T14:56:28.055Z" + "updated_at": "2026-06-10T15:32:03.641Z" }, - "seq": 28, + "seq": 40, "items": [ { "id": 1, @@ -467,6 +467,188 @@ "done": false, "completed_at": null, "version": null + }, + { + "id": 29, + "title": "修复库存扣减 TOCTOU 竞态:SUM 预检纳入事务且在 FOR UPDATE 加锁后执行", + "desc": "stock.go ApproveStockOut 中库存总量 SUM 在 FOR UPDATE 加锁前执行,存在 check-then-act 窗口,高并发下可超扣。需将预检 SUM 也放入事务并在加锁后执行", + "level": "high", + "tier": 2, + "tags": [ + "后端" + ], + "status": "open", + "created_at": "2026-06-10T15:31:13.249Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 30, + "title": "统一 handler Update 改用白名单字段更新,防止 GORM Save() 跨租户覆盖", + "desc": "partner.go/product_attr.go/warehouse.go 等多处用 db.Save(&object) 更新全字段,若中间件被绕过会造成 shop_id 被覆盖。改为 db.Model(&x).Where(\"id=? AND shop_id=?\").Updates(fields) 白名单模式", + "level": "high", + "tier": 2, + "tags": [ + "后端" + ], + "status": "open", + "created_at": "2026-06-10T15:31:15.102Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 31, + "title": "添加库存与财务流水定期对账检查,防止事务中断导致不平账", + "desc": "出库审批若 DB 断连,Rollback 后库存正确但财务记录可能未落地。需添加对账脚本:SUM(InventoryLog.quantity by direction) == SUM(Inventories.quantity),及告警机制", + "level": "high", + "tier": 2, + "tags": [ + "后端" + ], + "status": "open", + "created_at": "2026-06-10T15:31:16.854Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 32, + "title": "迁移 License 激活逻辑到 license_devices 表,废弃 licenses.device_id 字段", + "desc": "licenses.device_id 已标记 deprecated 但激活/解绑逻辑仍在使用它,license_devices 表未被完整采用。需将 Activate/Deactivate 逻辑迁移至 license_devices,并写数据迁移脚本", + "level": "mid", + "tier": 2, + "tags": [ + "后端", + "数据库" + ], + "status": "open", + "created_at": "2026-06-10T15:31:25.715Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 33, + "title": "将 checkInventory 业务逻辑从 StockOutHandler 移到 Service 层", + "desc": "checkInventory 实现在 handler/stock_out.go 中而非 service 层,导致单元测试困难、逻辑无法复用。应移至 StockService 或 InventoryService", + "level": "mid", + "tier": 2, + "tags": [ + "后端" + ], + "status": "open", + "created_at": "2026-06-10T15:31:28.106Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 34, + "title": "统一后端 API 错误响应格式为 {code, message},创建 util/response.go", + "desc": "各 handler 返回格式不一致:有的 {error: err.Error()},有的 {error: 硬编码字符串},有的直接 struct。前端解析困难。需定义 ErrorResponse struct 和 RespondError/RespondSuccess 辅助函数统一调用", + "level": "mid", + "tier": 2, + "tags": [ + "后端" + ], + "status": "open", + "created_at": "2026-06-10T15:31:33.596Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 35, + "title": "生产环境 CORS 强制校验:非 debug 模式禁止 Origin=*", + "desc": "config.go 默认 CORSOrigin=\"*\",注释提示生产需改但无代码强制。应在 main.go 中添加:server.mode!=debug 且 CORSOrigin==\"*\" 时 log.Fatal 拒绝启动", + "level": "mid", + "tier": 3, + "tags": [ + "后端" + ], + "status": "open", + "created_at": "2026-06-10T15:31:44.159Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 36, + "title": "License 私钥未配置时改为 Fatal 而非静默跳过", + "desc": "license.go 中私钥未配置只打 log 并跳过,导致授权功能失效但程序正常运行。应改为 log.Fatal,确保运维人员知晓配置缺失", + "level": "mid", + "tier": 3, + "tags": [ + "后端" + ], + "status": "open", + "created_at": "2026-06-10T15:31:46.792Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 37, + "title": "统一各 handler 的 pageSize 上限校验,创建 util.ValidatePageSize()", + "desc": "inventory.go 限制 pageSize 最大 500,其他 handler 无此限制,前端可传 pageSize=10000 打满 DB。创建 util.ValidatePageSize(n) 统一处理", + "level": "mid", + "tier": 3, + "tags": [ + "后端" + ], + "status": "open", + "created_at": "2026-06-10T15:31:49.032Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 38, + "title": "将拼音回填从启动逻辑改为一次性迁移脚本", + "desc": "main.go 每次启动执行 backfillPinyin 全表扫描,数据量大后拖慢启动。改为 go run ./cmd/migrate-pinyin 一次性迁移,后续新数据靠写入时自动生成", + "level": "low", + "tier": 3, + "tags": [ + "后端" + ], + "status": "open", + "created_at": "2026-06-10T15:31:57.979Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 39, + "title": "DB 连接池参数(MaxIdleConns/MaxOpenConns)改为可配置项", + "desc": "main.go 中硬编码 MaxIdleConns=10, MaxOpenConns=100,无法运维调优。改为读取 config(viper),并在文档中说明推荐值", + "level": "low", + "tier": 3, + "tags": [ + "后端" + ], + "status": "open", + "created_at": "2026-06-10T15:32:00.233Z", + "done": false, + "completed_at": null, + "version": null + }, + { + "id": 40, + "title": "明确 Inventories 反范式字段语义:是当前值还是入库快照", + "desc": "inventories 表存了 product_name/warehouse_name/supplier_name 等,既可能是冗余(与 products JOIN 重复),也可能是历史快照(入库时锁定)。需明确语义并在 model 注释中说明;若是快照,应只在写入时固定,不随主表变化", + "level": "low", + "tier": 2, + "tags": [ + "后端", + "数据库" + ], + "status": "open", + "created_at": "2026-06-10T15:32:03.641Z", + "done": false, + "completed_at": null, + "version": null } ] }