From a63ee263cadcd40a50cbf2959ad346871ca4607a Mon Sep 17 00:00:00 2001 From: wangjia <809946525@qq.com> Date: Tue, 16 Jun 2026 22:38:30 +0800 Subject: [PATCH] =?UTF-8?q?chore:=20=E6=B8=85=E7=A9=BA=E9=A1=B9=E7=9B=AE?= =?UTF-8?q?=20todo=EF=BC=88=E6=8C=89=E7=94=A8=E6=88=B7=E8=A6=81=E6=B1=82?= =?UTF-8?q?=EF=BC=8C=E5=8E=86=E5=8F=B2=E4=BF=9D=E7=95=99=E5=9C=A8=20git=20?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E4=B8=AD=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- todo/todo.html | 1505 +----------------------------------------------- todo/todo.json | 873 +--------------------------- 2 files changed, 15 insertions(+), 2363 deletions(-) diff --git a/todo/todo.html b/todo/todo.html index d886036..1987ef3 100644 --- a/todo/todo.html +++ b/todo/todo.html @@ -223,11 +223,11 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }

酒库管理系统 — 项目 TODO

生成于 2026-06-16 · 真相源 todo/todo.json
-
51全部
-
1待开始
+
0全部
+
0待开始
0开发中
-
36待验收
-
14已验收
+
0待验收
+
0已验收
@@ -257,11 +257,7 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; } -
-
- 平台 / 标签 - -
+
@@ -269,39 +265,12 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
- 📋 待开始 1 + 📋 待开始 0 ▴ 收起
    - -
  • -
    - iOS 上线 TestFlight 正式分发 -
    - 待开始 - 重要 - 一级 - - -
    -
    - -
    路线已定:CI 构建签名 IPA → 上传 TestFlight。前置(用户侧):Apple Developer Program($99/年)+App Store Connect 建 App(com.yanmei.jiu)+三件套凭证(.p12/.mobileprovision/.p8)+7个 Forgejo secrets+TestFlight 公开链接填 version.yaml。代码缺口(我方):compile-ios.sh 需在 flutter build ipa 前向 Release.xcconfig 注入 manual 签名(CODE_SIGN_STYLE/DEVELOPMENT_TEAM/PROVISIONING_PROFILE_SPECIFIER/CODE_SIGN_IDENTITY),否则 archive 阶段因 Automatic 无 team 必失败。详见计划 luminous-hugging-platypus.md。暂不调度。
    - - -
  • +

    暂无条目

@@ -318,1475 +287,23 @@ ul.todo-list { list-style: none; margin: 0; padding: 0; }
- 🔍 待验收 36 + 🔍 待验收 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),及告警机制
    - - -
  • - -
  • -
    - CheckInventoryAvailability Scan错误未检查导致所有商品误报库存不足 -
    - 待验收 - 高优 · 紧急 - 三级 - - -
    -
    - -
    service/stock.go:312 DB查询失败时sums为空,所有商品have=0,合法出库审核被全部拒绝
    - - -
  • - -
  • -
    - 修复 act_runner→Forgejo 任务状态上报丢失导致构建成功却标失败 -
    - 待验收 - 高优 · 紧急 - 二级 - - -
    -
    - -
    v1.0.27~v1.0.32 连续 6 个版本 CI 全部'失败',但日志显示所有 job 实际构建成功(🏁 Job succeeded),是 act_runner 最终状态上报丢失(Failed to write EOT),被 Forgejo 僵尸任务清理标为 failure。生产环境因此停留在 v1.0.26(6/8)。需排查 relay/GOAWAY race 或升级 act_runner/Forgejo。
    - - -
  • - -
  • -
    - 商品详情页重设计:展示所有字段,内容为公开页超集 -
    - 待验收 - 重要 - - - -
    -
    - -
    当前 product_detail_screen.dart 显示内容过于简单。需先做页面设计(UI 方案),内容要求是公开扫码页的超集:包含商品基本信息、参数(产地/保质期/储存方式)、价格、描述文档、图片、库存批次、入库记录等管理侧专属字段。另:商品公开链接展示为可点击超链接(点击可跳转公开扫码页)。
    - - -
  • - -
  • -
    - 桌面客户端单实例限制,禁止同时运行多个进程 -
    - 待验收 - 重要 - - - -
    -
    - -
    Windows 和 macOS 客户端启动时检测是否已有实例运行;若有,则激活已有窗口并退出新进程。Flutter desktop 可通过 window_single_instance 或 dart:io 锁文件实现。
    - - -
  • - -
  • -
    - 迁移 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) 统一处理
    - - -
  • - -
  • -
    - finance ListRecords 和 inventory Logs handler 缺 pageSize 上限 -
    - 待验收 - 重要 - 三级 - - -
    -
    - -
    finance.go:36 和 inventory.go:130 漏加 ValidatePageSize,#37 未覆盖这两个 handler,可被任意用户触发全表扫描
    - - -
  • - -
  • -
    - ReconcileInventory 两条 Scan 错误未检查导致对账误判 -
    - 待验收 - 重要 - 三级 - - -
    -
    - -
    admin.go:122-123 invQuery/logQuery Scan错误被丢弃;invQuery失败→差异消失显示全部正常;logQuery失败→所有库存飘红为差异
    - - -
  • - -
  • -
    - license Info 端点 device_count 统计错误且 ListDevices 错误被吞 -
    - 待验收 - 重要 - 三级 - - -
    -
    - -
    handler/license.go:67-70 两个bug:1.devs,_ 错误被_吞掉DB故障时deviceCount=0;2.ListDevices(shopID)包含该店所有license设备而非当前license
    - - -
  • - -
  • -
    - License model 的 license_key 索引超 InnoDB 3072 字节限制需改用前缀索引 -
    - 待验收 - 重要 - 三级 - - -
    -
    - -
    license.go 的 LicenseKey 是 size:2048+uniqueIndex,utf8mb4 下 8192 字节超 MySQL InnoDB 索引上限,全新环境 AutoMigrate 必失败(线上已手动建 license_key(768) 前缀索引绕过)。需在 model 层固化:缩短列或 GORM 指定索引前缀长度,并同步 schema.sql。
    - - -
  • - -
  • -
    - 网络请求加重试(3次间隔递增)+离线提示带可感知的重试按钮 -
    - 待验收 - 重要 - - - -
    -
    - - - - -
  • - -
  • -
    - iOS 顶栏被状态栏遮挡,菜单按钮点不到(SafeArea) -
    - 待验收 - 重要 - - - -
    -
    - - - - -
  • - -
  • -
    - 左侧抽屉+系统设置页加退出登录按钮 -
    - 待验收 - 重要 - - - -
    -
    - - - - -
  • - -
  • -
    - 酒行信息显示微信号 -
    - 待验收 - 重要 - - - -
    -
    - - - - -
  • - -
  • -
    - 备案号为占位假值 -
    - 待验收 - 一般 / 优化 - - - -
    -
    - -
    现为沪ICP备2026000000号(全0),上线前必须替换真实备案号。
    - - -
  • - -
  • -
    - 授权信息功能方案设计 -
    - 待验收 - 一般 / 优化 - - 8/8 子任务 - -
    -
    - -
    完整方案设计,涵盖:界面设计与交互、前端实现方案、后端接口与数据模型、安全策略(防盗用、防滥用、授权校验)等。需产出设计文档后再进入开发阶段。
    -
    -
    - 子任务 - 8 / 8 完成 -
    -
    -
    • - - 21A - 后端:Ed25519 签发验签工具 + GenerateKey 修复 -
      二级待验收
      -
    • -
    • - - 21B - 数据库:license_devices 表 + licenses 表改造 -
      二级待验收依赖:21A
      -
    • -
    • - - 21C - 后端:注册自动签发 30 天 trial license -
      二级待验收依赖:21A
      -
    • -
    • - - 21D - 后端:LicenseGuard 中间件 + JWT claim 扩展 -
      二级待验收依赖:21B21C
      -
    • -
    • - - 21E - 前端:license model/repository/device_id 采集 -
      二级待验收依赖:21A
      -
    • -
    • - - 21F - 前端:激活与设备管理 UI(授权 Tab 重构) -
      二级待验收依赖:21D21E
      -
    • -
    • - - 21G - 前端:gating 横幅 + 到期弹窗(app_shell 注入) -
      二级待验收依赖:21D21E
      -
    • -
    • - - 21H - 端到端验证:phase 切换 + 签名拒绝 + 多设备上限 -
      二级待验收依赖:21D21F21G
      -
    -
    - -
  • - -
  • -
    - 关于我们页文档/更新日志链接更新,Web 新增版本历史页 -
    - 待验收 - 一般 / 优化 - - - -
    -
    - -
    1. 客户端「关于我们」页面的「打开文档」「更新日志」链接指向需更新为正确地址。2. Web 营销站新增版本更新页面(/changelog 或 /download/),从 CHANGELOG.md 自动渲染,展示所有历史版本更新记录。
    - - -
  • - -
  • -
    - 注册/联系入口「发邮件」升级为「加客服微信」并优化文案 -
    - 待验收 - 一般 / 优化 - - - -
    -
    - -
    当前注册成功页和网站联系支持入口引导用户「发邮件」,体验较弱。升级为扫码加客服微信,同时梳理相关文案措辞,使表达更专业、有亲和力。
    - - -
  • - -
  • -
    - 服务条款与隐私政策页面 -
    - 待验收 - 一般 / 优化 - - - -
    -
    - -
    在营销网站(jiu.51yanmei.com)补充服务条款(Terms of Service)和隐私政策(Privacy Policy)页面,注册页底部添加链接。最低优先级,待其他功能稳定后处理。
    - - -
  • - -
  • -
    - 移动端左侧抽屉菜单支持手势侧滑唤出 -
    - 待验收 - 一般 / 优化 - - - -
    -
    - -
    窄屏(手机)模式下,导航 Drawer 当前需点击汉堡按钮打开,需支持从屏幕左边缘向右滑动手势唤出菜单,符合移动端操作习惯。涉及 app_shell.dart 的 Drawer 配置。
    - - -
  • - -
  • -
    - 入库单详情商品明细改为卡片式竖排布局 -
    - 待验收 - 一般 / 优化 - - - -
    -
    - -
    当前入库单详情的商品明细以横向表格展示,字段多时在窄屏上挤压严重。改为每件商品独占一个卡片区块,字段竖向排列(商品名、规格、数量、单价、产地、保质期等各占一行),信息层次清晰,移动端阅读体验更好。宽屏可保持表格,窄屏自动切换为卡片流(复用 MobileListCard 模式)。
    - - -
  • - -
  • -
    - 将拼音回填从启动逻辑改为一次性迁移脚本 -
    - 待验收 - 一般 / 优化 - 三级 - - -
    -
    - -
    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 注释中说明;若是快照,应只在写入时固定,不随主表变化
    - - -
  • - -
  • -
    - license Activate 幂等路径 Update 错误未检查 -
    - 待验收 - 一般 / 优化 - 三级 - - -
    -
    - -
    service/license.go:70 s.db.Model(&existing).Update()失败时仍返回nil error,设备名未更新但调用方不知道
    - - -
  • - -
  • -
    - license Verify 加载 license 缺 shop_id 过滤(防御纵深) -
    - 待验收 - 一般 / 优化 - 三级 - - -
    -
    - -
    service/license.go:102 WHERE id=? AND is_active=1 应加 AND shop_id=? 防御数据异常时跨租户泄露
    - - -
  • - -
  • -
    - util/response.go 的 RespondError 等辅助函数从未被调用(#34 实际未完成) -
    - 待验收 - 一般 / 优化 - 二级 - - -
    -
    - -
    #34 只创建了util/response.go,没有将任何handler迁移过去,实际错误格式仍不统一,需完成迁移
    - - -
  • - -
  • -
    - 清理 ErrDeviceMismatch 死代码(多设备迁移后残留) -
    - 待验收 - 一般 / 优化 - 三级 - - -
    -
    - -
    service/license.go:24 ErrDeviceMismatch定义后从未返回,多设备迁移(#32)后已无单设备约束
    - - -
  • +

    暂无条目

- ✅ 已验收 14 + ✅ 已验收 0 ▾ 展开
diff --git a/todo/todo.json b/todo/todo.json index cde838f..0b66fd2 100644 --- a/todo/todo.json +++ b/todo/todo.json @@ -1,873 +1,8 @@ { "meta": { "title": "酒库管理系统 — 项目 TODO", - "updated_at": "2026-06-16T14:26:17.800Z" + "updated_at": "2026-06-16T14:38:14.559Z" }, - "seq": 55, - "items": [ - { - "id": 1, - "title": "两套 CSS / 设计令牌并存", - "desc": "主站 njk 用 color.css+style.css,功能页用 colors_and_type.css,导航/页脚各写一份,维护分裂。建议合并到一套,功能页走 base.njk 模板。", - "level": "mid", - "tags": [ - "前端", - "Web" - ], - "created_at": "2026-06-07T17:30:32.138Z", - "done": true, - "completed_at": "2026-06-07T17:48:38.554Z", - "version": "v1.0.23", - "status": "accepted" - }, - { - "id": 2, - "title": "备案号为占位假值", - "desc": "现为沪ICP备2026000000号(全0),上线前必须替换真实备案号。", - "level": "low", - "tags": [ - "Web" - ], - "created_at": "2026-06-07T17:30:32.188Z", - "done": false, - "completed_at": null, - "version": null, - "status": "done" - }, - { - "id": 3, - "title": "注册接口同源依赖问题", - "desc": "用 window.location.origin+'/api/v1/public/register',要求同源部署;分离部署时指错。需确认部署形态。", - "level": "low", - "tags": [ - "前端", - "Web" - ], - "created_at": "2026-06-07T17:30:32.237Z", - "done": true, - "completed_at": "2026-06-08T14:33:22.523Z", - "version": "v1.0.25", - "status": "accepted" - }, - { - "id": 4, - "title": "scan.html / features 走 passthrough 不享模板", - "desc": "features/scan.html 直接复制,不经 njk 模板,页脚/备案/CSS 都得手动同步。建议长期改造为模板化。", - "level": "low", - "tags": [ - "前端", - "Web" - ], - "created_at": "2026-06-07T17:30:32.287Z", - "done": true, - "completed_at": "2026-06-07T18:07:13.211Z", - "version": "v1.0.23", - "status": "accepted" - }, - { - "id": 5, - "title": "页脚双份维护", - "desc": "njk 站点用 footer.njk 读变量,功能页把页脚硬编码各写一份,改一处不同步。根因同「两套模板」。", - "level": "low", - "tags": [ - "前端", - "Web" - ], - "created_at": "2026-06-07T17:30:32.334Z", - "done": true, - "completed_at": "2026-06-08T14:33:22.584Z", - "version": "v1.0.25", - "status": "accepted" - }, - { - "id": 6, - "title": "注册成功提示路径需核对", - "desc": "提示「忘记门店编码可在「系统设置→关于」查看」,需与实际客户端菜单路径一致。", - "level": "low", - "tags": [ - "前端", - "Web" - ], - "created_at": "2026-06-07T17:30:32.381Z", - "done": true, - "completed_at": "2026-06-08T14:33:22.648Z", - "version": "v1.0.25", - "status": "accepted" - }, - { - "id": 8, - "title": "补全「查看本店其他商品」功能", - "desc": "PublicProductScreen _ShopCard 底部按钮 onPressed: () {} 为空,需实现跳转至该门店商品列表页。client/lib/screens/public/public_product_screen.dart:1240", - "level": "mid", - "tags": [ - "前端", - "iOS", - "Android" - ], - "created_at": "2026-06-07T18:08:24.432Z", - "done": true, - "completed_at": "2026-06-07T23:18:23.239Z", - "version": "v1.0.23", - "status": "accepted" - }, - { - "id": 9, - "title": "设计并实现添加门店微信功能", - "desc": "PublicProductScreen _ShopCard「添加门店微信」按钮 onPressed: () {} 为空。需设计方案:门店维护微信号字段 or 二维码图片,扫码页展示。涉及后端 shop model 扩展 + 前端展示。client/lib/screens/public/public_product_screen.dart:1255", - "level": "mid", - "tags": [ - "前端", - "iOS", - "Android" - ], - "created_at": "2026-06-07T18:08:32.748Z", - "done": true, - "completed_at": "2026-06-07T23:28:52.932Z", - "version": "v1.0.23", - "status": "accepted" - }, - { - "id": 10, - "title": "公开商品 API 补充 sale_price 并在页面展示价格", - "desc": "product model 有 sale_price 字段但 public.go GetProduct 未返回。需:1) 后端 batchData/productData 加 sale_price;2) Flutter _TitleBlock 或单独区块展示建议零售价。client: public_product_screen.dart, backend: handler/public.go", - "level": "mid", - "tags": [ - "前端", - "后端", - "iOS", - "Android" - ], - "created_at": "2026-06-07T18:12:21.217Z", - "done": true, - "completed_at": "2026-06-07T23:28:53.001Z", - "version": "v1.0.23", - "status": "accepted" - }, - { - "id": 13, - "title": "公开商品 API 补充 batch.quantity 和 product code/barcode", - "desc": "Flutter _AuthenticityCard 读取 batch['quantity'] 但后端 public.go batchData 未返回 quantity。另 product code/barcode 未暴露,参数卡无法显示商品编码。handler/public.go GetProduct", - "level": "low", - "tags": [ - "后端", - "iOS", - "Android" - ], - "created_at": "2026-06-07T18:12:43.136Z", - "done": true, - "completed_at": "2026-06-08T14:40:04.464Z", - "version": "v1.0.25", - "status": "accepted" - }, - { - "id": 14, - "title": "Footer「商品报错」「意见反馈」补充实际功能", - "desc": "public_product_screen.dart _Footer 底部两个链接无 url/action,点击静默。需设计方案:跳转反馈表单、弹出联系方式、或发邮件。line:1353-1355", - "level": "low", - "tags": [ - "前端", - "iOS", - "Android" - ], - "created_at": "2026-06-07T18:12:50.299Z", - "done": true, - "completed_at": "2026-06-08T00:06:15.299Z", - "version": "v1.0.24", - "status": "accepted" - }, - { - "id": 15, - "title": "4 张商品属性字典表 + 后端 CRUD", - "desc": "新增 product_origin_options/product_shelf_life_options/product_storage_options/product_description_docs 4 张字典表(TenantBase+shop_id 隔离);Product 增加 4 个可空外键;AutoMigrate 注册;handler/product_attr.go CRUD(16 个方法);router.go 追加 4 组路由在 /product-options/ 下", - "level": "mid", - "tags": [ - "后端", - "数据库" - ], - "created_at": "2026-06-07T22:51:51.881Z", - "done": true, - "completed_at": "2026-06-07T22:56:24.807Z", - "version": "v1.0.23", - "status": "accepted" - }, - { - "id": 16, - "title": "public.go 返回产地/保质期/储存/介绍,公开页去硬编码", - "desc": "public.go GetProduct Preload 4 张新表 + 三级回退(描述文档→旧Description→通用中性兜底)+ 默认值常量(保质期/储存方式);Flutter public_product_screen.dart _ParamsCard/_DescriptionSection 改读真实数据,移除茅台 mock", - "level": "mid", - "tags": [ - "后端", - "前端", - "iOS", - "Android" - ], - "created_at": "2026-06-07T22:51:59.988Z", - "done": true, - "completed_at": "2026-06-07T22:58:32.882Z", - "version": "v1.0.23", - "status": "accepted" - }, - { - "id": 17, - "title": "入库表单关联 4 个商品属性字典", - "desc": "stock_in_form_screen.dart 生产日期字段附近增加产地/保质期/储存方式/描述文档 4 个下拉选择(数据来自字典 List 接口);FindOrCreate/Update 接受并写入 4 个 id;前端新增对应 API client 方法", - "level": "mid", - "tags": [ - "前端", - "iOS", - "Android" - ], - "created_at": "2026-06-07T22:52:07.331Z", - "done": true, - "completed_at": "2026-06-07T23:03:13.631Z", - "version": "v1.0.23", - "status": "accepted" - }, - { - "id": 18, - "title": "基础数据管理 UI 增加 4 个字典维护 Tab", - "desc": "products_screen.dart 基础数据管理页增加产地/保质期/储存方式/描述文档 4 个维护 Tab,复用现有 option 维护组件(增删改查);描述文档 Tab 含 title+content 多行输入", - "level": "low", - "tags": [ - "前端", - "iOS", - "Android" - ], - "created_at": "2026-06-07T22:52:13.283Z", - "done": true, - "completed_at": "2026-06-08T00:06:15.371Z", - "version": "v1.0.24", - "status": "accepted" - }, - { - "id": 19, - "title": "入库单新建表单增加产地/保质期/储存方式,选填项默认折叠", - "desc": "新建入库单的商品行增加产地、保质期、储存方式三个字典下拉选项(已有字典数据)。必填项(商品名、数量等)正常显示;选填项默认隐藏,点击展开按钮后在下一行展示。", - "level": "high", - "tags": [ - "前端", - "iOS", - "Android" - ], - "created_at": "2026-06-08T14:56:32.850Z", - "done": false, - "completed_at": null, - "version": null, - "status": "done", - "reject_reason": null, - "rejected_at": null - }, - { - "id": 20, - "title": "商品详情页重设计:展示所有字段,内容为公开页超集", - "desc": "当前 product_detail_screen.dart 显示内容过于简单。需先做页面设计(UI 方案),内容要求是公开扫码页的超集:包含商品基本信息、参数(产地/保质期/储存方式)、价格、描述文档、图片、库存批次、入库记录等管理侧专属字段。另:商品公开链接展示为可点击超链接(点击可跳转公开扫码页)。", - "level": "mid", - "tags": [ - "前端", - "iOS", - "Android" - ], - "created_at": "2026-06-08T14:59:08.342Z", - "done": false, - "completed_at": null, - "version": null, - "status": "done" - }, - { - "id": 21, - "title": "授权信息功能方案设计", - "desc": "完整方案设计,涵盖:界面设计与交互、前端实现方案、后端接口与数据模型、安全策略(防盗用、防滥用、授权校验)等。需产出设计文档后再进入开发阶段。", - "level": "low", - "tags": [ - "前端", - "后端", - "安全", - "文档" - ], - "created_at": "2026-06-08T15:02:58.896Z", - "done": false, - "completed_at": null, - "version": null, - "status": "done", - "subtasks": [ - { - "sid": "21A", - "title": "后端:Ed25519 签发验签工具 + GenerateKey 修复", - "tier": 2, - "deps": [], - "status": "done", - "created_at": "2026-06-09T16:14:58.628Z" - }, - { - "sid": "21B", - "title": "数据库:license_devices 表 + licenses 表改造", - "tier": 2, - "deps": [ - "21A" - ], - "status": "done", - "created_at": "2026-06-09T16:15:09.490Z" - }, - { - "sid": "21C", - "title": "后端:注册自动签发 30 天 trial license", - "tier": 2, - "deps": [ - "21A" - ], - "status": "done", - "created_at": "2026-06-09T16:15:09.541Z" - }, - { - "sid": "21D", - "title": "后端:LicenseGuard 中间件 + JWT claim 扩展", - "tier": 2, - "deps": [ - "21B", - "21C" - ], - "status": "done", - "created_at": "2026-06-09T16:15:09.590Z" - }, - { - "sid": "21E", - "title": "前端:license model/repository/device_id 采集", - "tier": 2, - "deps": [ - "21A" - ], - "status": "done", - "created_at": "2026-06-09T16:15:09.639Z" - }, - { - "sid": "21F", - "title": "前端:激活与设备管理 UI(授权 Tab 重构)", - "tier": 2, - "deps": [ - "21D", - "21E" - ], - "status": "done", - "created_at": "2026-06-09T16:15:09.689Z" - }, - { - "sid": "21G", - "title": "前端:gating 横幅 + 到期弹窗(app_shell 注入)", - "tier": 2, - "deps": [ - "21D", - "21E" - ], - "status": "done", - "created_at": "2026-06-09T16:15:09.739Z" - }, - { - "sid": "21H", - "title": "端到端验证:phase 切换 + 签名拒绝 + 多设备上限", - "tier": 2, - "deps": [ - "21D", - "21F", - "21G" - ], - "status": "done", - "created_at": "2026-06-09T16:15:09.789Z" - } - ] - }, - { - "id": 22, - "title": "关于我们页文档/更新日志链接更新,Web 新增版本历史页", - "desc": "1. 客户端「关于我们」页面的「打开文档」「更新日志」链接指向需更新为正确地址。2. Web 营销站新增版本更新页面(/changelog 或 /download/),从 CHANGELOG.md 自动渲染,展示所有历史版本更新记录。", - "level": "low", - "tags": [ - "前端", - "Web", - "文档" - ], - "created_at": "2026-06-08T15:05:00.447Z", - "done": false, - "completed_at": null, - "version": null, - "status": "done" - }, - { - "id": 23, - "title": "注册/联系入口「发邮件」升级为「加客服微信」并优化文案", - "desc": "当前注册成功页和网站联系支持入口引导用户「发邮件」,体验较弱。升级为扫码加客服微信,同时梳理相关文案措辞,使表达更专业、有亲和力。", - "level": "low", - "tags": [ - "前端", - "Web" - ], - "created_at": "2026-06-08T15:06:00.175Z", - "done": false, - "completed_at": null, - "version": null, - "status": "done" - }, - { - "id": 24, - "title": "服务条款与隐私政策页面", - "desc": "在营销网站(jiu.51yanmei.com)补充服务条款(Terms of Service)和隐私政策(Privacy Policy)页面,注册页底部添加链接。最低优先级,待其他功能稳定后处理。", - "level": "low", - "tags": [ - "Web", - "文档" - ], - "created_at": "2026-06-08T15:06:26.383Z", - "done": false, - "completed_at": null, - "version": null, - "status": "done" - }, - { - "id": 25, - "title": "移动端左侧抽屉菜单支持手势侧滑唤出", - "desc": "窄屏(手机)模式下,导航 Drawer 当前需点击汉堡按钮打开,需支持从屏幕左边缘向右滑动手势唤出菜单,符合移动端操作习惯。涉及 app_shell.dart 的 Drawer 配置。", - "level": "low", - "tags": [ - "前端", - "iOS", - "Android" - ], - "created_at": "2026-06-08T15:09:27.652Z", - "done": false, - "completed_at": null, - "version": null, - "status": "done" - }, - { - "id": 26, - "title": "入库单详情商品明细改为卡片式竖排布局", - "desc": "当前入库单详情的商品明细以横向表格展示,字段多时在窄屏上挤压严重。改为每件商品独占一个卡片区块,字段竖向排列(商品名、规格、数量、单价、产地、保质期等各占一行),信息层次清晰,移动端阅读体验更好。宽屏可保持表格,窄屏自动切换为卡片流(复用 MobileListCard 模式)。", - "level": "low", - "tags": [ - "前端", - "iOS", - "Android" - ], - "created_at": "2026-06-08T15:11:09.971Z", - "done": false, - "completed_at": null, - "version": null, - "status": "done" - }, - { - "id": 27, - "title": "桌面客户端单实例限制,禁止同时运行多个进程", - "desc": "Windows 和 macOS 客户端启动时检测是否已有实例运行;若有,则激活已有窗口并退出新进程。Flutter desktop 可通过 window_single_instance 或 dart:io 锁文件实现。", - "level": "mid", - "tags": [ - "Windows", - "mac" - ], - "status": "done", - "created_at": "2026-06-08T15:58:11.759Z", - "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": "done", - "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": "done", - "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": "done", - "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": "done", - "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": "done", - "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": "done", - "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": "done", - "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": "done", - "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": "done", - "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": "done", - "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": "done", - "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": "done", - "created_at": "2026-06-10T15:32:03.641Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 41, - "title": "CheckInventoryAvailability Scan错误未检查导致所有商品误报库存不足", - "desc": "service/stock.go:312 DB查询失败时sums为空,所有商品have=0,合法出库审核被全部拒绝", - "level": "high", - "tier": 3, - "tags": [ - "后端" - ], - "status": "done", - "created_at": "2026-06-10T23:59:34.919Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 42, - "title": "finance ListRecords 和 inventory Logs handler 缺 pageSize 上限", - "desc": "finance.go:36 和 inventory.go:130 漏加 ValidatePageSize,#37 未覆盖这两个 handler,可被任意用户触发全表扫描", - "level": "mid", - "tier": 3, - "tags": [ - "后端" - ], - "status": "done", - "created_at": "2026-06-10T23:59:46.152Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 43, - "title": "ReconcileInventory 两条 Scan 错误未检查导致对账误判", - "desc": "admin.go:122-123 invQuery/logQuery Scan错误被丢弃;invQuery失败→差异消失显示全部正常;logQuery失败→所有库存飘红为差异", - "level": "mid", - "tier": 3, - "tags": [ - "后端" - ], - "status": "done", - "created_at": "2026-06-10T23:59:46.205Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 44, - "title": "license Info 端点 device_count 统计错误且 ListDevices 错误被吞", - "desc": "handler/license.go:67-70 两个bug:1.devs,_ 错误被_吞掉DB故障时deviceCount=0;2.ListDevices(shopID)包含该店所有license设备而非当前license", - "level": "mid", - "tier": 3, - "tags": [ - "后端" - ], - "status": "done", - "created_at": "2026-06-10T23:59:46.257Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 45, - "title": "license Activate 幂等路径 Update 错误未检查", - "desc": "service/license.go:70 s.db.Model(&existing).Update()失败时仍返回nil error,设备名未更新但调用方不知道", - "level": "low", - "tier": 3, - "tags": [ - "后端" - ], - "status": "done", - "created_at": "2026-06-10T23:59:59.016Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 46, - "title": "license Verify 加载 license 缺 shop_id 过滤(防御纵深)", - "desc": "service/license.go:102 WHERE id=? AND is_active=1 应加 AND shop_id=? 防御数据异常时跨租户泄露", - "level": "low", - "tier": 3, - "tags": [ - "后端" - ], - "status": "done", - "created_at": "2026-06-10T23:59:59.066Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 47, - "title": "util/response.go 的 RespondError 等辅助函数从未被调用(#34 实际未完成)", - "desc": "#34 只创建了util/response.go,没有将任何handler迁移过去,实际错误格式仍不统一,需完成迁移", - "level": "low", - "tier": 2, - "tags": [ - "后端" - ], - "status": "done", - "created_at": "2026-06-10T23:59:59.118Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 48, - "title": "清理 ErrDeviceMismatch 死代码(多设备迁移后残留)", - "desc": "service/license.go:24 ErrDeviceMismatch定义后从未返回,多设备迁移(#32)后已无单设备约束", - "level": "low", - "tier": 3, - "tags": [ - "后端" - ], - "status": "done", - "created_at": "2026-06-10T23:59:59.168Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 49, - "title": "修复 act_runner→Forgejo 任务状态上报丢失导致构建成功却标失败", - "desc": "v1.0.27~v1.0.32 连续 6 个版本 CI 全部'失败',但日志显示所有 job 实际构建成功(🏁 Job succeeded),是 act_runner 最终状态上报丢失(Failed to write EOT),被 Forgejo 僵尸任务清理标为 failure。生产环境因此停留在 v1.0.26(6/8)。需排查 relay/GOAWAY race 或升级 act_runner/Forgejo。", - "level": "high", - "tier": 2, - "tags": [ - "CI/CD" - ], - "status": "done", - "created_at": "2026-06-11T13:55:07.388Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 50, - "title": "License model 的 license_key 索引超 InnoDB 3072 字节限制需改用前缀索引", - "desc": "license.go 的 LicenseKey 是 size:2048+uniqueIndex,utf8mb4 下 8192 字节超 MySQL InnoDB 索引上限,全新环境 AutoMigrate 必失败(线上已手动建 license_key(768) 前缀索引绕过)。需在 model 层固化:缩短列或 GORM 指定索引前缀长度,并同步 schema.sql。", - "level": "mid", - "tier": 3, - "tags": [ - "后端", - "数据库" - ], - "status": "done", - "created_at": "2026-06-11T15:52:40.353Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 51, - "title": "iOS 上线 TestFlight 正式分发", - "desc": "路线已定:CI 构建签名 IPA → 上传 TestFlight。前置(用户侧):Apple Developer Program($99/年)+App Store Connect 建 App(com.yanmei.jiu)+三件套凭证(.p12/.mobileprovision/.p8)+7个 Forgejo secrets+TestFlight 公开链接填 version.yaml。代码缺口(我方):compile-ios.sh 需在 flutter build ipa 前向 Release.xcconfig 注入 manual 签名(CODE_SIGN_STYLE/DEVELOPMENT_TEAM/PROVISIONING_PROFILE_SPECIFIER/CODE_SIGN_IDENTITY),否则 archive 阶段因 Automatic 无 team 必失败。详见计划 luminous-hugging-platypus.md。暂不调度。", - "level": "mid", - "tier": 1, - "tags": [ - "iOS", - "CI/CD" - ], - "status": "open", - "created_at": "2026-06-13T15:22:29.363Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 52, - "title": "网络请求加重试(3次间隔递增)+离线提示带可感知的重试按钮", - "desc": null, - "level": "mid", - "tier": null, - "tags": [], - "status": "done", - "created_at": "2026-06-16T06:39:13.652Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 53, - "title": "iOS 顶栏被状态栏遮挡,菜单按钮点不到(SafeArea)", - "desc": null, - "level": "mid", - "tier": null, - "tags": [], - "status": "done", - "created_at": "2026-06-16T14:19:56.340Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 54, - "title": "左侧抽屉+系统设置页加退出登录按钮", - "desc": null, - "level": "mid", - "tier": null, - "tags": [], - "status": "done", - "created_at": "2026-06-16T14:26:00.681Z", - "done": false, - "completed_at": null, - "version": null - }, - { - "id": 55, - "title": "酒行信息显示微信号", - "desc": null, - "level": "mid", - "tier": null, - "tags": [], - "status": "done", - "created_at": "2026-06-16T14:26:00.735Z", - "done": false, - "completed_at": null, - "version": null - } - ] -} + "seq": 0, + "items": [] +} \ No newline at end of file