Commit Graph

24 Commits

Author SHA1 Message Date
wangjia 3641f1cf16 chore: release server-v1.0.75
Deploy Server / release-deploy-server (push) Successful in 1m7s
出库售价(应收按售价) + 库存选择器分页上限修复 + seed 改为序列号模型

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-22 13:01:25 +08:00
wangjia 20f9e3a410 chore: release server-v1.0.74
Deploy Server / release-deploy-server (push) Successful in 2m4s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 22:17:24 +08:00
wangjia 203cc7ce21 chore: release server-v1.0.71
Deploy Server / release-deploy-server (push) Successful in 56s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 18:14:27 +08:00
wangjia 7b67466a3e chore: release server-v1.0.70
Deploy Server / release-deploy-server (push) Successful in 56s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 17:32:55 +08:00
wangjia c1febfffec feat(backend): 入库每行新建独立产品发独立序列号(product 加生产日期/批次列)
Deploy Server / release-deploy-server (push) Successful in 59s
入库 Create/Update 改为对每条明细新建独立 product(createIndependentProduct,
nextProductCode 自增 + uk_shop_code 唯一约束兜底),回填 product_id;不再按名称复用。
product 表加 production_date/batch_no。向后兼容:保留明细/库存快照列。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 16:30:11 +08:00
wangjia 1a1d9aa15e fix(backend): 商品编码改用最大序号生成不复用软删号 + 加 (shop_id,code) 唯一约束,根治重复编码
Deploy Server / release-deploy-server (push) Successful in 53s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YZ4DskSRKsSiheQonFtQvx
2026-06-21 10:51:34 +08:00
wangjia 15ef71734d chore: release server-v1.0.64
Deploy Server / release-deploy-server (push) Successful in 55s
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 10:13:49 +08:00
wangjia 90d2c8668b feat(backend): 历史进销存导入器 cmd/import-history + 单据明细快照列
一次性 CLI 导入旧系统 data/ 入库·出库 总表/详情表到当前库,历史只读(绝不
回放 inventories/inventory_logs)。明细忠实直存不做 SKU 归一:order/item 表
新增 creator_id(制单人)与 product_code/product_name/series/spec 快照列
(出库另补 batch_no/production_date),导入行 product_id 指向共享占位商品。
order_no 天然主键 (shop_id,order_no) 幂等去重,可重复跑。

testutil sqlite DDL 同步补列以保持 service 测试通过。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-20 07:05:08 +08:00
wangjia 7bbc944ae2 chore: release server-v1.0.62
Deploy Server / release-deploy-server (push) Successful in 51s
服务端安全加固:多维限流(按 IP/按门店)+ 敏感接口独立速率上限抵御 DDoS/刷接口;
登录暴力破解新增按来源 IP 锁定;反代后正确识别真实客户端 IP;
门店 custom_fields 轻量配置(录入默认值)透传保存。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Y2Wdwo7SmgBJU37cBrkhPK
2026-06-19 20:20:44 +08:00
wangjia 23dff69c62 feat(backend): 授权改为时长兑换券体系 + 退役 ed25519/HMAC + 平台生码工具
- 新增 license_codes 码池表 + model.LicenseCode;licenses 加 tier 档位列
- LicenseService.Redeem:单事务 FOR UPDATE 校验码未用 → 时长叠加(可叠加,0=永久)
  → 写 type/tier/max_devices → 绑设备(超限整笔回滚) → 标记已用 → 即时失效 phase 缓存
  路由仍 POST /license/activate,客户端零破坏
- util.GenerateRedeemCode/NormalizeCode:JIUKU-XXXX-XXXX 短码(crypto/rand)
- cmd/gencode:平台批量生成兑换码并落库;删除 cmd/issue、cmd/genkey
- 退役 ed25519 + HMAC:删 util/license_key、GenerateKey、License 全部 config 字段
  及生产启动私钥校验;trial 改直接建行(无需私钥、去 Fatal)
- tier 档位钩子默认 standard,分档消费模式后续设计
- 测试:Redeem 全场景(叠加/过期重置/永久/一码一次/无效/设备上限回滚)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 12:14:27 +08:00
wangjia e41085a878 feat(backend): 会话安全加固 + 授权实时 phase + 首次使用自动试用
会话安全(jti 轮换 / 重用检测 / 改密吊销 / 禁用即时下线 / 清理 / 失败登录落库):
- refresh token 轮换 jti + token-family 重用检测,旧 token 重放即吊销整条会话
- 改密码、停用用户即时吊销其全部活跃会话(revoked_by 审计)
- 中间件 session JOIN user 校验,禁用/删除用户带 token 请求返回 401 USER_DISABLED
- 新增 login_attempts 失败登录落库 + 会话保留期清理 goroutine

授权实时 phase + 心跳回带:
- LicenseGuard 改为按当前 DB 实时计算 phase(30s 每店缓存),续费/过期/被改 ~30s 内对写操作生效,无需重登
- /auth/ping 回带授权概况(ShopInfoView,与 /license/info 同构),客户端一次心跳即刷新横幅/门禁

首次使用自动试用 + code-review 修复:
- 门店首次登录/续期无有效授权时自动签发 30 天 trial(快路径无锁 Count,仅首用走 FOR UPDATE 事务)
- ShopInfo 区分「确无授权」与瞬时 DB 错误,避免误降级
- trial 签发后改为在事务提交后再失效 phase 缓存(修复早于提交的竞态)
- 存量无 sid token 续期纳入显式上限,legacy 会话不再游离于并发配额之外

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 07:34:04 +08:00
wangjia 53fa259284 chore: release server-v1.0.56
Deploy Server / release-deploy-server (push) Successful in 40s
会话/设备管理后端:user_sessions 会话表、JWT 加 sid 校验、按平台类限并发登录、
登录失败锁定、修复禁用账号仍可凭 refresh 续期漏洞、/auth/ping、/auth/logout、
GET /sessions、DELETE /sessions/:id(管理员强制下线)。

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17 23:12:13 +08:00
wangjia c402ea0070 feat(backend): license_devices 表 + 注册自动签发 trial (21B+21C)
21B — DB & model:
- licenses: 扩展 license_key 为 2048 字节(容纳 Ed25519 JWT),
  新增 max_devices INT DEFAULT 3,device_id/activated_at 标为 deprecated
- 新增 license_devices 表(license_id+device_id 唯一索引)
- model/license_device.go:LicenseDevice struct
- main.go AutoMigrate 加入 LicenseDevice
- testutil/setup.go 同步 SQLite DDL

21C — trial at register:
- config: 新增 Ed25519PrivateKey 配置项(LICENSE_ED25519_PRIVATE_KEY 环境变量)
- service/license.go: createTrialLicense(tx, shopID) — 签发 30d trial,
  私钥未配置时静默跳过(开发/测试不影响)
- service/auth.go: Register 事务末尾调用 createTrialLicense

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:42:56 +08:00
wangjia 1ec1d4209a chore: release v1.0.24
Deploy / build-linux-web (push) Successful in 59s
Deploy / build-windows (push) Successful in 1m50s
Deploy / build-macos (push) Successful in 1m22s
Deploy / build-android (push) Successful in 1m26s
Deploy / build-ios (push) Successful in 7s
Deploy / release-deploy (push) Successful in 1m39s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 07:31:55 +08:00
wangjia ba127826b2 feat(backend): 新增商品属性字典表(产地/保质期/储存方式/描述文档)
- model/product_attr.go: 新增 4 张字典表 struct(TenantBase 范式)
- model/product.go: Product 增加 4 个可空外键 + belongs-to 关联
- handler/product_attr.go: 4 组 16 个 CRUD handler(shop_id 隔离)
- handler/product.go: FindOrCreate/Update 支持写入 4 个属性 ID
- handler/public.go: Preload 4 表 + 三级回退介绍 + 默认话术常量
- router/router.go: /product-options/{origins,shelf-lives,storages,description-docs} 路由
- main.go: AutoMigrate 注册 4 个新 model
- testutil/setup.go: SQLite 测试库补齐新列与新表

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-08 06:56:16 +08:00
wangjia eda7d37b64 feat: 新增用户自助注册功能
后端新增 POST /api/v1/public/register 接口,支持门店自助注册并自动生成门店编码(S000001 格式);shops 表加 description 字段。营销站新增 /register/ 注册页,含门店信息和管理员账号表单,注册成功后展示门店编码和登录提示。Flutter 登录页底部加「前往官网注册」跳转链接。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-26 13:56:34 +08:00
wangjia e9a6543a8b feat(search): 库存搜索支持拼音/首字母,按回车触发
- 新增 util.ToPinyin(),使用 go-pinyin 生成全拼和首字母
- Product model 新增 name_pinyin / name_initials 列(AutoMigrate)
- 启动时自动回填存量商品拼音
- Create / Update / FindOrCreate 写入时同步生成拼音
- 库存搜索 SQL 加入拼音/首字母 LIKE 条件
- 前端去掉 300ms 防抖,改为回车/点击搜索按钮触发

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-25 21:27:54 +08:00
wangjia fbb4f90ebd fix(test): shops 测试表补加 logo_url 列
Deploy / deploy (push) Successful in 1m15s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 20:15:39 +08:00
wangjia 86baaf3a1c fix(model): users 唯一索引改为 (shop_id, username) 复合索引
Deploy / deploy (push) Successful in 1m13s
原来 uniqueIndex:uk_shop_username 只在 Username 字段上,导致用户名全局唯一。
S002/S003 的 admin 用户与 S001 冲突,INSERT 被静默跳过,无法登录。

将 User 的 TenantBase 改为直接定义 ShopID,使其参与复合唯一索引。
需要 Reset DB 使新索引生效。

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 14:50:34 +08:00
wangjia 9f94cc97b7 fix(test): 修复测试数据库 schema 和 Flutter 测试与屏幕重构的兼容性
- backend/testutil/setup.go: SQLite shops 表补充 business_hours 列
- stock_in_screen_test: 入库管理双 Tab 重构后,draft/pending 测试改为先切换到「入库审核」Tab
- stock_out_insufficient_stock_flow_test: Inventory 构造参数 productUnit→unit,补充必填 id
- inventory_repository_test: mock 数据改为平铺字段格式,补充必填 id
- docs: 新增 NAS + Gitea 部署文档(Runner 设置、Shadowrocket 中继说明)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 10:48:21 +08:00
wangjia 1b4ca0c675 fix(test): 修复测试文件类型错误和测试数据库 schema 过期问题
- 修正 stock_in/out 测试中 WarehouseID/ProductID 指针误用(StockOrder 用 uint64,Inventory 用 *uint64)
- 更新 testutil/setup.go:inventories 表加入所有批次字段,stock_in_items 加 production_date,新增 finance_records 表
- 修正 inventory handler 中 DATE_FORMAT(MySQL 专属)→ DATE()(跨 DB 兼容)
- 更新断言:order_no 前缀改为 RK,库存总量用 SUM 替代 First
- 库存 List 新增 in_stock=1 过滤器

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 14:16:10 +08:00
wangjia f5c41e04f3 fix: 修复测试 schema 缺失字段,标记过时测试为 skip
- testutil/setup.go 补充 products.public_id、description,partners.status
- 过时 products/stock 流程测试标记 skip(provider 已不挂载)
- deploy.sh 补充 PUBLIC_URL dart-define

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-30 00:46:25 +08:00
wangjia 31ea370cea fix(backend): JWT config mapstructure tag 修复 + 模型从 hotel 重构为 shop
- 修复 JWTConfig 缺少 mapstructure tag 导致 access_expire_min 解析为 0,
  token 签发即过期,所有 API 请求返回 401
- 全部 config struct 补齐 mapstructure tag(secret/dsn/hmac_secret 等)
- 模型层从 hotel/HotelID 统一重命名为 shop/ShopID
- 删除旧 migrations(001-004),新增 001_init 综合迁移文件
- 更新 schema.sql、testutil、handler/service/model 相关引用

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 22:20:12 +08:00
wangjia 7a09d1537c test: 后端自动化测试套件
Service 单元测试(SQLite in-memory):
- auth: 登录成功/失败/禁用账号,token 刷新
- stock: 入库审核、出库审核(含库存不足)、单号生成
- license: 激活、设备绑定验证、过期检测

Handler 集成测试(httptest + SQLite):
- auth: 登录 API 成功/401 场景
- product: CRUD 完整流程 + hotel_id 隔离验证
- stock_in: 创建→提交→审核完整流程
- stock_out: 完整流程 + 库存不足 400
- inventory: 库存查询/过滤/盘点创建
- warehouse: CRUD

覆盖率:service 90.4%,handler 56.1%
共 50 个测试用例,全部 PASS

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-04 07:24:14 +08:00