Files
cmhub/progress.md
T
2026-07-02 14:47:22 +08:00

40 KiB
Raw Blame History

执行进度记录

本文件是只追加的历史流水,用来记录任务执行过程、验证命令、阻塞点和关键决策。 当前目录、当前命令、下一个可领取任务等可覆盖快照,写入 docs/current-state.md。

职责边界

  • docs/06-tasks.md:任务看板,维护任务状态、依赖和验收要点。
  • progress.md:历史流水,只追加记录每轮执行发生了什么。
  • docs/current-state.md:当前快照,可覆盖更新仓库现实、可运行命令和下一步。

不要在本文重复维护当前目录结构、当前运行命令或下一个任务;这些信息以 docs/current-state.md 为准。

记录格式

每完成或中断一轮任务,在文件末尾追加一条记录:

## 【YYYY-MM-DD】T-【编号】 【任务名】

- 状态:【DONE / BLOCKED / PARTIAL】
- 变更:【修改了哪些文件或模块】
- 验证:【运行的真实命令和结果】
- 阻塞:【如有,写明原因和需要谁决策】
- 决策:【如有,记录本轮确定的关键取舍】
- 下一步:【建议下一个任务 ID 或待确认事项】

执行记录

2026-06-29 文档初始化(非任务)

  • 状态:DONE
  • 变更:基于 D:\github\harness_coding_docs 模板,结合需求讨论生成 cmhub 全套 harness 文档(AGENTS/CLAUDE、docs/00–06、api、routes、current-state、README、progress、init 脚本);通用流程文档(adoption/clean-state/method-map/evaluator/quality)从模板复制。
  • 验证:仅文档,无代码可跑。
  • 决策:技术栈 Django+DRF+django-admin;预付费点数模型(充值按汇率转点存本地,调用扣本地点数,不实时查支付系统);生成接口同步返回;充值由支付系统服务端回调入账(验签+幂等)。
  • 下一步:领取 T-001 初始化 Django + DRF 骨架。支付系统接口文档待提供(T-304 前需要)。

2026-06-29 设计优化:可插拔供应商(别名 + 适配器)(非任务)

  • 状态:DONE
  • 变更:把「两个接口 + 后台配模型」的设计从简化版抬到可治理版,更新到多个文档:
    • 04-architecture.md:AI 调用层改为 Provider 适配器架构;新增 ModelAlias 表与 AiModel 的 capabilities/加密 key;PricingRule 改为按别名定价;CallRecord 增 alias + model_used;计费时序加入别名解析与能力校验;难点表补充抽象泄漏/供应商耦合/配置热生效/审计;项目结构加 apps/ai/providers/。
    • api.md:对外 model 字段明确为能力别名;新增 parameters 透传;响应加 model_used;图片默认返回 URL;AI 模块合约改为别名解析 + Provider 适配器接口。
    • 03-tech-stack.md / 02-requirements.md / 05-coding-rules.md / routes.md / 06-tasks.md:同步别名机制、密钥加密、配置审计、对象存储等决策与任务。
  • 验证:仅文档;自检文档间链接与任务依赖一致(T-302 依赖更新为 T-104)。
  • 决策:① 对外绑能力别名而非具体模型 SKU;② api_type 升级为显式 Provider 适配器层 + capabilities 声明 + parameters 透传;③ 供应商密钥加密存储 + 配置热生效 + 后台变更审计。按账号授权别名、按比例分流/故障转移列入 Backlog(接口预留,MVP 不实现)。
  • 下一步:领取 T-001 初始化 Django + DRF 骨架(Phase 1 任务已重排为 T-101 适配器层 / T-102 别名解析 / T-103 审计 / T-104 跑通)。

2026-07-01 设计决策:桌面端全同步接入 + V2 异步预研(非任务)

  • 状态:DONE
  • 变更:把「桌面端不改、全同步接入 cmhub」的可用性结论与前提写入两个每轮必读文档:
    • 03-tech-stack.md 第二节「同步生成而非任务队列」决策下补:桌面端可不改交互骨架、只换 service 层 URL/密钥即可接入;同步可用的三前提;何时转 V2 异步的触发信号。
    • 04-architecture.md 第五节新增 5.1 同步方案可用性结论:超时链路层层放大对齐(点名 timeout_seconds:0、Gunicorn 30s、Nginx 60s 三个默认值雷,建议统一 300s)、worker 数按峰值总并发预留、适用边界与 V2 触发条件。
  • 验证:仅文档;ai_models.json 现存 timeout_seconds: 0,迁入服务端时须改有限值(关联约束已写入 04 第五节)。
  • 决策:① MVP 桌面端不改、桌面端 → cmhub → 中转站 全同步,多一跳不影响可用性,点数一致性更简单(一次请求闭环:预扣→同步调→成功/失败退点);② 同步可用的硬前提是「超时链路 + worker 容量」配对,否则「小量正常、上量假死」;③ 适用边界为单接入方小并发批量,V2 异步(队列)延后,但适配器接口与 call_record 三态需为异步预留口子。
  • 安全提醒:ai_models.json 内三把 sk- 为明文真实密钥,视为已泄露,迁入时须加密存储(Fernet/KMS)并轮换;密钥不进桌面端。
  • 下一步:不改变任务看板顺序,仍从 T-001 起步;V2 异步化触发条件见 03/04,暂不排期。

2026-07-01 设计决策:版本锁定 + 数据库选型(MySQL 8.4 独立实例)(非任务)

  • 状态:DONE
  • 变更:结合实际部署环境(一台 VPS,实测 15G 内存 / available 7.4G / 无 swap,已装 MySQL 5.7 供其他服务用),定稿版本与数据库选型,更新 03-tech-stack.md(技术栈表语言/框架/数据库三行 + 决策记录三条)、04-architecture.md(数据库条目 + 第五节并发扣点难点补 CHECK 版本注意)、README.md 技术栈行。
  • 验证:仅文档。
  • 决策:
    • ① 框架/语言锁定 Django 5.2 LTS + Python 3.12(requires-python ">=3.12,<3.14");禁用已 EOL 的 Django 4.0/4.1;理由是安全/维护窗口,非性能(性能瓶颈在等上游+worker,见 5.1)。
    • ② 数据库定 MySQL 8.4 LTS,cmhub 专用独立实例。放弃复用 VPS 已有的 MySQL 5.7:5.7 跑不了 Django 5.2(需 ≥8.0.11)、已 EOL、不支持 CHECK 约束;曾评估「坚持 5.7」会连锁把 Django 拖回 4.0(EOL)+Python≤3.10+cmbot 兼容风险,被否。内存宽裕(7.4G),单开独立实例与已有 5.7 隔离、互不影响。
    • ③ 硬性约束:InnoDB + utf8mb4;CHECK 需 MySQL ≥8.0.16 才生效,扣点主防线是 select_for_update / UPDATE ... WHERE balance>=N,不能只靠 CHECK;MySQL 默认隔离级别 REPEATABLE READ,计费按此语义验证;开发亦用 MySQL,不用 SQLite(会忽略 FOR UPDATE,测不出并发扣点)。
  • 待办提醒:T-001 骨架落地时须选 MySQL 驱动(mysqlclient 或 PyMySQL)、DATABASES 配 charset=utf8mb4、连接指向独立实例端口;机器建议补 2–4G swap;03 部署维度仍为「待定」,部署基线待后续定稿。
  • 下一步:不改变任务看板顺序,仍从 T-001 起步(Django+DRF 骨架,按上述版本/数据库落地)。

2026-07-01 定位扩展:新增自助用户端(B2B → B2B+B2C)(非任务)

  • 状态:DONE
  • 变更:按用户新增需求(终端用户自助注册/扫码充值/API Key 管理/查记录),把项目从纯 B2B API 网关扩展为「自助用户端 + 计费 API + 运营后台」三合一,系统性更新文档:
    • 定位/需求:01-vision、00-ai-start-here、02-requirements、project-brief、project-onepager(用户角色加注册用户;MVP 加用户端;移除"自助注册"非目标;注册不送点数)。
    • 架构:04-architecture(系统结构加用户端;数据模型 Account→User+UserWallet+ApiKey;两套认证;4.2 加自助扫码下单时序;难点加 API Key 哈希/注册滥用/Web-API worker 隔离/充错账户;项目结构 apps;架构纪律)。
    • 合约/路由/规则:api.md(认证主体 User、recharge/create 转正扫码、API 只认 Key)、routes.md(用户端页面路由、admin 改 User/Wallet/ApiKey)、03-tech-stack(用户端形态 Django SSR+Bootstrap+allauth、鉴权、部署 worker 隔离)、05-coding-rules(范围、API Key 哈希、API 只认 Key、锁 wallet)。
    • 任务:06-tasks(T-002 首迁移前定自定义 User;T-201 改 User/Wallet/ApiKey;T-203 锁 wallet;T-305 扫码下单;新增 Phase 4 用户端 T-501~504;里程碑加 M4 用户端)。
    • README、current-state 同步。
  • 验证:仅文档。
  • 决策:
    • ① 前端形态选 Django 模板 SSR 单体(+Bootstrap/allauth/crispy),不引前后端分离框架。
    • ② 用户模型:User(auth 登录态) / UserWallet(点数余额,扣点锁 wallet、与 auth 解耦) / ApiKey(User 1:N,sha256 哈希存储、明文只显示一次)。
    • ③ 认证分两套认同一 User:用户端 session+CSRF,对外 API 只挂 API Key(不挂 Session,防绕过计费)。
    • ④ 充值:recharge/create 转正,用户端自助扫码下单 + 回调入账,订单绑定 user 防充错账户,金额 Decimal 向下取整。
    • ⑤ 注册不送免费点数(必须充值才有点数,降低薅羊毛);注册须邮箱验证、生成接口须限流。
    • ⑥ 单体部署按路径把图片 API 与用户端页面分流到不同 worker 池。
  • 待办提醒:支付系统扫码下单 + 回调接口文档仍未提供,是 T-304/T-305 充值的硬阻塞;自定义 User 必须在首次 migrate 前定义(Django 硬约束)。
  • 下一步:任务仍从 T-001 起步;用户端任务见 Phase 4(T-501~504)。

2026-07-01 补全支付协议(参考同系统 PHP 实现,解除充值 blocker)(非任务)

  • 状态:DONE
  • 变更:从 Obsidian 笔记(虎观虾皮一键采购 扫码支付购买流程-技术文档 + 扫码支付迁移到Django-实施指南)提取同一支付系统的扫码支付协议,补进当前 Django 仓库文档:
    • api.md:充值段重写为微信 V3 native + 支付宝当面付双回调(/recharge/callback/wechat、/alipay)+ create(pay_method、code_url/qr_code)+ status 轮询;金额单位、验签、幂等、应答格式明确。
    • 04-architecture.md 4.2:补通道协议、库、金额单位、回调应答、@csrf_exempt、主动查单兜底。
    • 03-tech-stack.md:充值对接行加库 wechatpayv3/python-alipay-sdk。
    • routes.md:拆微信/支付宝回调端点 + status。
    • 06-tasks.md:T-304 拆双回调+主动查单,T-305 加 weixin/alipay+轮询。
    • 05-coding-rules.md:回调 @csrf_exempt + 主动查单兜底。
    • current-state.md:blocker 降级。
  • 验证:仅文档。
  • 决策:
    • ① 路线确认:继续当前 Django 仓库,Obsidian 的 Go(Gin+GoAdmin) cmhub 方案仅作支付逻辑参考(用户拍板)。
    • ② 支付通道:微信 V3 native(wechatpayv3,金额分,回调 SDK 验签解密、TRANSACTION.SUCCESS、应答 {code:SUCCESS});支付宝当面付 trade.precreate(python-alipay-sdk,金额元,verify、TRADE_SUCCESS/FINISHED、应答 success)。
    • ③ 二维码不含业务数据,靠 out_trade_no(=order_no) 在回调关联;回调 @csrf_exempt;幂等 select_for_update+status!=pending;须主动查单兜底。
    • ④ 只取支付层,不引入 Obsidian 源里的套餐/会员有效期/邀请返佣业务(那是虎观助手专有);充值入账走本项目 UserWallet+points_ledger+ExchangeRate。
  • 待办提醒:blocker 从「协议缺失」降级为「仅缺商户密钥/证书真实值」,不阻塞开发,可先 mock。原 PHP 遗留坑(测试后门号、H5 金额写死、支付宝 debug 沙箱、明文密钥)不迁入。
  • 下一步:任务仍从 T-001 起步;充值见 T-304/T-305(可 mock 先行)。

2026-07-01 吸收 AI 模型调用机制(来自 Go 方案 §16.6)(非任务)

  • 状态:DONE
  • 变更:从 Obsidian Golang-Gin-GoAdmin-技术方案 §16.6 提取三个上游模型的真实调用机制(业务规则/上游契约,非技术栈),补进 04-architecture.md(3.1 + AI 层职责)、api.md(待确认 + image 改图必传)、03-tech-stack.md、06-tasks.md(T-101 验收)。
  • 验证:仅文档。
  • 决策:
    • ① GPT-5.5(chat)标准 chat/completions;Nano Banana 2(api_type=auto)走 chat/completions 多模态返图、需自定义解析、可文/图生图;GPT Image 2(images_edits)走 images/edits 改图、原图必传。
    • ② 两个图片模型非标准 images/generations,每模型独立 url+key;图片返回结构(URL/base64/位置)首次对接抓真实响应再定解析。
    • ③ 只吸收 AI 模型机制,不吸收 Go 方案的会员套餐/续期/折扣/邀请返佣/多端 JWT(属虎观采购业务或 Go 栈,非 cmhub 定位);鉴权继续用 API Key(比桌面端 JWT 更安全,不在桌面端存密码)。
  • 下一步:T-101/T-102 实现适配器时按此机制,首次对接 api.vectorengine.ai 抓真实响应确认图片返回结构。

2026-07-01 文档优化:定位一致性 + 充值 schema + 调用状态 + 环境配置(非任务)

  • 状态:DONE
  • 变更:按全栈落地前优先级修正文档:
    • docs/README.md / project-brief.md / project-onepager.md:定位同步为「自助用户端 + 计费型 AI 能力网关 + 运营后台」三合一,并加入 env.md 导航。
    • docs/04-architecture.md / docs/api.md / docs/06-tasks.md:充值订单改为下单时锁定 exchange_rate 与 points_granted,回调入账使用订单值并校验金额;call_record.status 明确为 pending -> success / failed,失败退点通过 points_ledger(refund, ref_call_id) 关联。
    • docs/env.md:新增环境变量与配置清单,覆盖 Django、MySQL、AI 密钥加密、微信/支付宝、对象存储与上线检查。
    • docs/03-tech-stack.md / docs/current-state.md / docs/00-ai-start-here.md / docs/02-requirements.md / 汇报文档:同步环境配置入口、当前快照与支付 blocker 降级口径。
  • 验证:文档修改;用 rg 定位相关段落,未运行代码测试(仓库当前尚无代码)。
  • 阻塞:无。
  • 决策:充值汇率采用「下单锁定」而非「回调时读取当前汇率」,便于页面展示预计到账点数,也避免用户扫码后后台改价导致入账变化;调用记录不增加 refunded 状态,账务冲正由点数流水表达。
  • 下一步:仍从 T-001 初始化 Django + DRF 骨架开始。

2026-07-01 文档优化:里程碑口径同步(非任务)

  • 状态:DONE
  • 变更:同步汇报文档里程碑到 06-tasks.md 的 M1-M5 口径:project-brief.md 增加 M4 用户端可用、M5 验收上线;project-onepager.md 进度行同步 M4/M5。
  • 验证:文档修改;用 rg 定位里程碑旧口径。
  • 阻塞:无。
  • 决策:以 06-tasks.md 的里程碑为权威,汇报文档只做同口径摘要。
  • 下一步:仍从 T-001 初始化 Django + DRF 骨架开始。

2026-07-01 文档优化:Phase 顺序口径同步(非任务)

  • 状态:DONE
  • 变更:更新 docs/00-ai-start-here.md 的优先路径,Phase 3/4/5 与 docs/06-tasks.md 对齐:Phase 3 为对外 API 与充值,Phase 4 为用户端,Phase 5 为后台与发布。
  • 验证:文档修改;用 rg 对照 00-ai-start-here.md 与 06-tasks.md 的 Phase 标题。
  • 阻塞:无。
  • 决策:任务阶段顺序以 06-tasks.md 为权威,入口文档只做一致的导航摘要。
  • 下一步:仍从 T-001 初始化 Django + DRF 骨架开始。

2026-07-01 T-001 初始化 Django + DRF 项目骨架

  • 状态:DONE
  • 变更:
    • 新增 manage.py、config/ Django 工程骨架。
    • 新增 requirements.txt,锁定 Django 5.2 系列与 DRF 3.16 系列。
    • config/settings.py 加入 rest_framework,SECRET_KEY / DEBUG / ALLOWED_HOSTS 支持环境变量,默认仅用于本地开发。
    • init.ps1 / init.sh 替换为真实命令;按用户要求使用系统 Python 3.12,不使用虚拟环境。Windows 用 py -3.12,Unix/WSL 用 python3.12。
    • 同步 docs/00-ai-start-here.md、docs/03-tech-stack.md、docs/current-state.md、docs/06-tasks.md、README.md。
  • 验证:
    • py -3.12 -m pip install -r requirements.txt:Django 5.2.15 / DRF 3.16.1 已安装。
    • py -3.12 manage.py check:通过,0 issues。
    • py -3.12 manage.py test:通过,当前 0 tests。
    • ./init.ps1:通过,完成依赖检查、manage.py check,打印启动命令。
    • C:\Python312\python.exe manage.py runserver 127.0.0.1:8765 --noreload:端口 smoke 通过(TCP 8765 可连接),随后已停止进程。
    • bash -n init.sh:当前机器无可用 bash/WSL,无法本机验证 Unix 脚本。
  • 阻塞:无。
  • 决策:T-001 不接入 MySQL、不创建自定义 User、不创建 apps 目录;这些按任务边界留给 T-002。T-001 阶段暂保留 Django 默认 SQLite 配置用于框架启动检查,T-002 必须在首次迁移前改为自定义 User + MySQL 8.4 配置。
  • 下一步:领取 T-002 建立 apps 目录、自定义 User 与配置。

2026-07-02 T-002 建立 apps 目录、自定义 User 与配置

  • 状态:DONE
  • 变更:
    • 创建 apps/ 包与 apps/users|portal|billing|ai|api 五个 Django app。
    • apps/users.models.User 继承 AbstractUser,新增 payment_user_id、status、created_at,邮箱改为必填,db_table="user";settings.AUTH_USER_MODEL="users.User" 已设置。
    • settings.py 增加根目录 .env 读取,数据库从 SQLite 切换到 MySQL,配置 utf8mb4 与严格 SQL 模式。
    • 采用 PyMySQL 作为 MySQL 驱动,更新 requirements.txt 与 config/__init__.py。
    • 生成 apps/users/migrations/0001_initial.py。
  • 验证:
    • py -3.12 -m pip install -r requirements.txt:通过,安装 PyMySQL 1.1.3。
    • py -3.12 manage.py check:通过,0 issues。
    • py -3.12 manage.py makemigrations users:通过,生成 0001_initial.py。
    • py -3.12 manage.py migrate:首次失败,MySQL 返回 ALTER command denied to user 'test'@'61.141.174.182' for table 'django_content_type';用户在宝塔/MySQL 授权后,清理失败迁移留下的空表并重新执行,最终通过。
    • SHOW GRANTS FOR CURRENT_USER():授权后显示 GRANT ALL PRIVILEGES ON cmhub.* TO test@%。
    • py -3.12 manage.py check:通过,0 issues。
    • py -3.12 manage.py test:通过,当前 0 tests。
    • MySQL 验证:存在自定义 user 表,含 payment_user_id / status / created_at;未创建默认 auth_user 表;django_migrations 共 19 条。
  • 阻塞:已解除。曾因 MySQL 用户缺少 ALTER/INDEX/DROP 等迁移权限受阻。
  • 决策:使用 PyMySQL 作为 MySQL 驱动;T-002 只落 apps、自定义 User、settings 与 MySQL 初始迁移,不提前实现 UserWallet/ApiKey 等 T-201 内容。
  • 下一步:领取 T-003 接通 django-admin 与最小测试。

2026-07-02 T-003 接通 django-admin 与最小测试

  • 状态:PARTIAL
  • 变更:
    • apps/users/admin.py:用 DjangoUserAdmin 注册自定义 User,后台列表展示 username/email/status/is_staff/is_active/created_at,支持按 status 过滤、按 username/email/payment_user_id 搜索,created_at 只读。
    • apps/users/tests.py:新增最小 admin smoke test,覆盖自定义 User 已注册到 admin、superuser 可登录 /admin/。
    • config/settings.py:本地默认 ALLOWED_HOSTS 增加 testserver,匹配 Django test client。
    • docs/06-tasks.md / docs/current-state.md:记录 T-003 当前权限阻塞。
  • 验证:
    • py -3.12 manage.py check:通过,0 issues。
    • 手工创建临时 superuser 并用 Django test client 登录 /admin/:登录成功,GET /admin/ 返回 200;临时用户已清理。
    • py -3.12 manage.py test:未通过,Django 在创建 test_cmhub 测试库时报 (1044, "Access denied for user 'test'@'%' to database 'test_cmhub'")。
    • 进一步验证 CREATE DATABASE IF NOT EXISTS test_cmhub ... 同样返回 1044;当前授权仅覆盖 cmhub.*。
  • 阻塞:需要给 MySQL 用户增加测试库权限,建议优先只授权测试库范围:
    • GRANT ALL PRIVILEGES ON test_cmhub.* TO 'test'@'%';
    • FLUSH PRIVILEGES;
  • 决策:不把 Django 测试改跑到业务库 cmhub,避免测试清表/迁移影响真实开发数据;T-003 在标准 manage.py test 通过前不标 DONE。
  • 下一步:完成 MySQL 授权后重跑 py -3.12 manage.py test,再跑 py -3.12 manage.py check / ./init.ps1,通过后把 T-003 标记 DONE。

2026-07-02 T-003 接通 django-admin 与最小测试(完成验收)

  • 状态:DONE
  • 变更:
    • requirements.txt:新增 cryptography>=42,<47,用于支持 PyMySQL 连接 MySQL 8 默认 caching_sha2_password 认证。
    • docs/06-tasks.md:T-003 从 BLOCKED 改为 DONE。
    • docs/current-state.md / docs/03-tech-stack.md:同步当前依赖、验证结果与下一步任务。
  • 验证:
    • py -3.12 -m pip install -r requirements.txt:通过,安装 cryptography 46.0.7。
    • py -3.12 manage.py test:通过,2 tests OK,测试库 test_cmhub 创建与销毁正常。
    • py -3.12 manage.py check:通过,0 issues。
    • ./init.ps1:通过,依赖同步与基础检查正常。
  • 阻塞:无。
  • 决策:保留独立 test_cmhub 测试库路径,标准测试不使用业务库 cmhub。
  • 下一步:领取 T-101 Provider 适配器层 + 移植 cmbot 调用。

2026-07-02 Phase 0 骨架审核(Claude Code review,非任务)

  • 状态:DONE(审核完成)
  • 变更:新增 docs/phase-0-review.md;06-tasks.md 新增 T-004 修补任务;docs/README.md 导航登记;current-state.md 下一步改 T-004。
  • 审核结论:T-001~003 验收全部达标,质量高于骨架平均水准。自定义 User 先于首次迁移、AUTH_USER_MODEL 已设、PyMySQL install_as_MySQLdb() 胶水到位、密钥全走 env 且 .env/ai_models.json 未被 git 跟踪、独立 test_cmhub 测试库——关键硬约束全对。
  • 发现(详见 phase-0-review.md):
    • P1(建议现在改):User.email 未 unique;requires-python 未落地、init 脚本无解释器版本断言。
    • P2(规范性):INSTALLED_APPS 顺序(本地 app 排在 contrib 前,模板查找隐患);缺 .env.example。
    • P3(后续任务处理):REST_FRAMEWORK 认证配置(T-301)、sql_mode 完整性、生产 SECRET_KEY 保护(T-403)。
  • 未本地复跑:审核机无 python3.12,结论基于静态审查 + codex 验证记录(记录真实,含 MySQL 授权 / caching_sha2 修复过程)。
  • 下一步:codex 领 T-004,按 phase-0-review.md 修 P1/P2,全绿留证后再进 T-101。

2026-07-02 T-004 Phase 0 骨架审核修补

  • 状态:DONE
  • 变更:
    • 文档先行:更新 README.md、docs/00-ai-start-here.md、docs/03-tech-stack.md、docs/04-architecture.md、docs/api.md、docs/current-state.md、docs/env.md、docs/06-tasks.md,把 T-004、邮箱唯一约束、Python 版本断言、.env.example 和下一步 T-101 口径同步。
    • apps/users.models.User.email 增加 unique=True,并生成/应用 apps/users/migrations/0002_alter_user_email.py。
    • config/settings.py 调整 INSTALLED_APPS 顺序为 django.contrib.* → rest_framework → 本地 apps。
    • init.ps1 / init.sh 在安装依赖前校验 Python 版本必须满足 >=3.12,<3.14。
    • 新增 .env.example(仅占位符,无真实密钥)与 pyproject.toml(落地 requires-python)。
  • 验证:
    • 重复邮箱预检:业务库非空 email 无重复。
    • py -3.12 manage.py makemigrations users:生成 0002_alter_user_email.py。
    • py -3.12 manage.py migrate:通过,应用 users.0002_alter_user_email。
    • 数据库索引验证:user.email 存在唯一索引 user_email_54dc62b2_uniq。
    • py -3.12 manage.py check:通过,0 issues。
    • py -3.12 manage.py test:通过,2 tests OK。
    • ./init.ps1:通过,输出 Python 3.12.3 版本断言、依赖同步与基础检查。
    • py -3.12 manage.py makemigrations --check:通过,No changes detected。
    • git diff --check:通过,仅有 CRLF 提示。
    • bash -n init.sh:当前 Windows 未安装 WSL/bash,无法本机验证 Unix 脚本语法。
  • 阻塞:无。
  • 决策:保留 requirements.txt 作为运行依赖来源,pyproject.toml 只承载 Python 版本元数据;.env.example 使用占位符,不提交 .env。
  • 下一步:领取 T-101 Provider 适配器层 + 移植 cmbot 调用。

2026-07-02 T-101 Provider 适配器层 + 移植 cmbot 调用

  • 状态:DONE
  • 变更:
    • 新增 apps/ai/providers/:ResolvedModel、Provider 协议、结果对象、错误类型、注册表、chat/gemini/images/images_edits 适配器。
    • 从 D:\chengma\cmbot\src\services\ai_text_service.py / ai_image_service.py 移植纯 HTTP 与响应解析逻辑:URL 归一化、api_type=auto 识别、分辨率超时、chat/gemini payload、images/edits multipart、标题清洗、图片 data URL/base64/URL 解析。
    • 服务端接口改为 bytes 输入,不依赖桌面端本地路径、GUI、线程或 Qt;HTTP session 可注入,便于测试。
    • requirements.txt 新增 requests>=2.32,<3。
    • apps/ai/tests.py 新增 5 条 mock 单测,覆盖 provider 选择、chat 文本请求构造和标题解析、chat 多模态返图解析、images/edits multipart 请求构造和 base64 图片解析、能力不支持错误。
    • 同步 docs/api.md、docs/03-tech-stack.md、docs/current-state.md、docs/06-tasks.md、README.md、docs/00-ai-start-here.md。
  • 验证:
    • 脱敏读取 D:\chengma\cmbot\config\ai_models.json:顶层为 models 列表,共 3 个模型;仅打印非密钥字段,未暴露真实 key。
    • py -3.12 -m pip install -r requirements.txt:通过,安装 requests 2.34.2 及依赖。
    • py -3.12 manage.py test apps.ai:通过,5 tests OK。
    • py -3.12 manage.py test:通过,7 tests OK。
    • py -3.12 manage.py check:通过,0 issues。
    • py -3.12 manage.py makemigrations --check:通过,No changes detected。
    • py -3.12 -m compileall apps:通过。
    • ./init.ps1:通过,依赖同步含 requests,基础检查正常。
  • 阻塞:无。
  • 决策:T-101 不创建 AiModel/ModelAlias 数据表、不做别名解析数据库读取、不接计费;先用 ResolvedModel dataclass 承接后续 T-102 的数据库模型。
  • 下一步:领取 T-102 AiModel + ModelAlias 模型 + 别名解析。

2026-07-02 T-102 AiModel + ModelAlias 模型 + 别名解析

  • 状态:DONE
  • 变更:
    • 新增 AiModel / ModelAlias 数据模型与 apps/ai/migrations/0001_initial.py:AiModel 保存上游 url/model/api_type/capabilities/timeout/extra_body/is_active 与 Fernet 密文 api_key_encrypted;ModelAlias 用 operation_type + alias 映射到具体模型,支持默认别名与启停。
    • 新增 apps/ai/security.py:AI_KEY_ENCRYPTION_KEY 驱动 Fernet 加解密,密文带 fernet: 前缀;拒绝明文 fallback。
    • 新增 apps/ai/aliases.py:resolve_alias(operation_type, alias=None) 每次查当前 active 配置,标题要求 text 能力,图片要求 image 能力,返回 provider 可用的 ResolvedModel。
    • 新增 apps/ai/importers.py 与 import_ai_models 管理命令:支持导入 cmbot 形状的 ai_models.json,导入时加密 key、推断 capabilities,可选创建 title-standard / image-standard 默认别名。
    • 完善 apps/ai/admin.py:admin 提供写入型 api_key 字段,密钥脱敏显示且不回显;缺少 Fernet 主密钥时以表单错误提示;api_key_encrypted 不暴露。
    • 扩展 apps/ai/tests.py:覆盖密钥加密/解密、别名解析、能力不匹配、inactive alias、配置导入、admin 脱敏与缺主密钥错误;同步更新 README、入口文档、技术栈、架构、API、环境配置、任务看板和当前状态。
  • 验证:
    • py -3.12 manage.py migrate:通过,ai.0001_initial 已应用;py -3.12 manage.py showmigrations ai 显示 [X] 0001_initial。
    • py -3.12 manage.py test apps.ai --noinput:通过,16 tests OK。
    • py -3.12 manage.py test --noinput:通过,18 tests OK。
    • py -3.12 manage.py check:通过,0 issues。
    • py -3.12 manage.py makemigrations --check:通过,No changes detected。
    • py -3.12 -m compileall apps / py -3.12 -m compileall apps\ai:通过。
    • ./init.ps1:通过,依赖同步与基础检查正常。
    • 验证期间远程 MySQL 43.128.3.240:3306 多次短暂超时,Test-NetConnection 43.128.3.240 -Port 3306 恢复后重试通过;失败点均为建库/事务前连接超时,不是断言失败。
  • 阻塞:无。
  • 决策:
    • 供应商密钥存储采用 cryptography Fernet 应用层加密,主密钥只走 AI_KEY_ENCRYPTION_KEY;不实现明文兼容。
    • T-102 不自动导入真实 D:\chengma\cmbot\config\ai_models.json,避免真实上游 key 被误暴露;后续由管理员在确认环境密钥后手动执行导入命令。
    • 默认别名唯一性先由 model validation、admin 与导入器保证;MySQL partial unique 约束留待审计/后台完善阶段评估。
  • 下一步:领取 T-103 配置变更审计。

2026-07-02 T-103 配置变更审计

  • 状态:DONE
  • 变更:
    • 新增 AiConfigAuditLog 审计模型与 apps/ai/migrations/0002_aiconfigauditlog.py,字段包括 actor、action、target_type、target_id、target_repr、changed_fields、changes、created_at。
    • 新增 apps/ai/audit.py:对 AiModel / ModelAlias 做变更快照与字段 diff,api_key_encrypted 对外记录为 api_key,只保留 empty / set 状态,不记录明文或 Fernet 密文。
    • 更新 apps/ai/admin.py:AiModelAdmin / ModelAliasAdmin 的保存和删除 hook 自动写审计日志;新增 AiConfigAuditLogAdmin,仅允许只读查看,不允许新增、修改、删除审计日志。
    • 扩展 apps/ai/tests.py:新增 5 条审计测试,覆盖 AiModel 创建、密钥更新、ModelAlias 映射变更、删除审计、审计 admin 只读。
    • 同步更新 README.md、docs/00-ai-start-here.md、docs/03-tech-stack.md、docs/04-architecture.md、docs/06-tasks.md、docs/api.md、docs/routes.md、docs/current-state.md、汇报文档。
  • 验证:
    • ./init.ps1:通过,依赖同步与基础检查正常。
    • py -3.12 manage.py migrate:通过,应用 ai.0002_aiconfigauditlog。
    • py -3.12 manage.py showmigrations ai:通过,0001_initial / 0002_aiconfigauditlog 均为 [X]。
    • py -3.12 manage.py test apps.ai.tests.AiConfigAuditAdminTests --noinput:通过,5 tests OK。
    • py -3.12 manage.py test apps.ai --noinput:通过,21 tests OK。
    • py -3.12 manage.py test --noinput --keepdb:通过,23 tests OK。
    • py -3.12 manage.py check:通过,0 issues。
    • py -3.12 manage.py makemigrations --check:通过,No changes detected。
    • py -3.12 -m compileall apps:通过。
    • git diff --check:通过,仅有 CRLF 提示。
    • 标准 py -3.12 manage.py test --noinput 多次在远程 MySQL 43.128.3.240:3306 创建/销毁测试库或测试中途重连时超时;失败点为 MySQL 连接/建库,不是断言失败。为降低远程建库压力,使用 --keepdb 完整测试已通过。
  • 阻塞:无代码阻塞;远程 MySQL 偶发连接超时会影响标准测试建库稳定性。
  • 决策:T-103 使用自建 AiConfigAuditLog 专表,不只依赖 django-admin LogEntry;密钥审计只记录状态变化,不记录明文或密文。
  • 下一步:领取 T-104 跑通一次真实/录制的标题或图片生成。

2026-07-02 T-104 跑通一次真实/录制的标题或图片生成

  • 状态:DONE
  • 变更:
    • 新增 smoke_ai_generation 管理命令:支持 title --recorded,在事务内临时创建 fake AiModel / ModelAlias,通过 resolve_alias() 解析别名,再用录制的 chat/completions 响应走 ChatCompletionsProvider.generate_text(),最后回滚临时配置,不写真实 key、不污染业务库。
    • 扩展 apps/ai/tests.py:新增录制 smoke 命令测试,确认输出不包含 placeholder key / Bearer,且临时 AiModel / ModelAlias 不持久化。
    • 同步更新 README.md、docs/00-ai-start-here.md、docs/03-tech-stack.md、docs/06-tasks.md、docs/current-state.md、汇报文档。
  • 验证:
    • ./init.ps1:通过,依赖同步与基础检查正常。
    • py -3.12 manage.py showmigrations ai:通过,0001_initial / 0002_aiconfigauditlog 均为 [X]。
    • py -3.12 manage.py shell -c "...AI_KEY_ENCRYPTION_KEY...":当前环境未配置 AI_KEY_ENCRYPTION_KEY。
    • py -3.12 manage.py shell -c "...AiModel/ModelAlias count...":业务库 AiModel count=0、ModelAlias count=0。
    • py -3.12 manage.py smoke_ai_generation title --recorded --prompt "为测试商品生成3个中文标题" --resolution 1K:通过;alias=t-104-recorded-title-c054d919,model_used=recorded-title-model,elapsed_ms=149,title_count=3。
    • smoke 后再次查询业务库:AiModel count=0、ModelAlias count=0,确认临时配置已回滚。
    • py -3.12 manage.py test apps.ai.tests.AiGenerationSmokeCommandTests --noinput --keepdb:通过,1 test OK。
    • py -3.12 manage.py check:通过,0 issues。
    • py -3.12 manage.py makemigrations --check:通过,No changes detected。
    • py -3.12 -m compileall apps:通过。
    • py -3.12 manage.py test apps.ai --noinput --keepdb:多次在远程 MySQL 43.128.3.240:3306 连接/测试库初始化阶段超时;失败点为数据库连接,不是断言失败。
  • 阻塞:真实上游 smoke 未执行,因为当前环境未配置 AI_KEY_ENCRYPTION_KEY,且业务库没有 AiModel/ModelAlias。配置 Fernet 主密钥并导入模型后,可去掉 --recorded 用同一命令跑真实标题 smoke。
  • 决策:T-104 采用“录制标题生成”作为验收路径,验证别名解析、Provider 选择、响应解析和同步耗时记录;真实图片同步耗时仍需在后续配置真实模型后补测。
  • 下一步:领取 T-201 User / UserWallet / ApiKey / PointsLedger / CallRecord 模型。

2026-07-02 Phase 1 审核(Claude Code review,非任务)

  • 状态:DONE(审核完成)
  • 变更:新增 docs/phase-1-review.md;06-tasks.md 新增 T-105 修补任务、T-104 状态标注「图片同步风险未退」;docs/README.md 导航登记;current-state.md 阶段/下一步改 T-105。
  • 审核结论:T-101~104 验收达标,代码质量高。三模型机制忠实落地(chat / auto→chat 多模态返图 nano-banana2 / images_edits 改图 gpt-image-2);timeout_seconds=0→按分辨率有限超时 修对了桌面端「0=无限」的坑;Fernet 加密 + 拒绝明文 fallback + 缺主密钥 fail-closed + admin 写入型脱敏字段 + 审计只记 empty/set,密钥零泄露闭环;审计 admin 真只读、delete_queryset 也留痕;smoke 用 override_settings+atomic+rollback 不落库、不打印 Bearer/key。
  • 发现(详见 phase-1-review.md):
    • P1-1(进 T-302 前必修,资金安全):apps/ai/providers/openai_compatible.py:apply_extra_body 无差别 payload.update(parameters),调用方透传可覆盖 model/n/size/resolution 等核心/计费字段,击穿「按别名计费」契约。须白名单化、核心字段服务端固定不可覆盖。
    • P1-2(最高风险未退):T-104 只跑了 recorded 标题(elapsed_ms=149 无网络意义),Phase 1 存在的唯一理由「图片同步在 Gunicorn/nginx 下不超时」未验证。结论应改为「管路已验、图片同步风险未退」,并在依赖同步部署前(最迟 T-403)跑一次真实图片生成记录真实耗时。
    • P2:.env.example 的 AI_DEFAULT_CONNECT/READ_TIMEOUT_SECONDS 代码未读取(死配置,接上或删除);resolution_to_size 未大小写归一("1k" 漏命中);导入器默认别名 image-standard 与文档示例 image-hd 口径不一致。
    • P3(登记):Provider.capabilities() 无调用点(半冗余);图生图 vs 改图都归 operation_type=IMAGE,T-302 需把「缺原图」翻成 400 而非 500;CallRecord 写入禁 dump result.raw(含 base64 大图/敏感);provider 密钥无轮换(单 Fernet key)。
  • 未本地复跑:审核机无 python3.12,结论基于静态审查(providers/models/security/aliases/audit/importers/admin/tests/迁移/settings)+ codex 验证记录(7→18→23 tests 递增、含真实 MySQL 建库超时的诚实记录,可信度高)。T-104 的 149ms 不作为图片同步可行性证据。
  • 下一步:codex 领 T-105,按 phase-1-review.md 修 P1/P2;P1-1 须先于 T-302,全绿留证。

2026-07-02 T-105 Phase 1 AI 层审核修补

  • 状态:DONE
  • 变更:
    • apps/ai/providers/openai_compatible.py:parameters / extra_body 改为白名单安全透传,model、messages、n、size、stream 等核心/计费字段不可被覆盖;generationConfig 仅允许安全子字段合并。
    • apps/ai/providers/utils.py:resolution_to_size() 增加大小写归一,"1k" / "512px" 可正确映射。
    • apps/ai/importers.py 与 import_ai_models 帮助文案:默认图片别名从 image-standard 对齐为 image-hd。
    • smoke_ai_generation 支持 image --recorded,录制图片路径走别名解析 + Provider 解析 + 事务回滚,不打印 key/Bearer、不持久化临时配置;保留真实 image smoke 入口和 --image-file。
    • 扩展 apps/ai/tests.py:覆盖 provider 参数越权拦截、分辨率归一、默认别名、录制 image smoke。
    • .env.example / docs/env.md 删除未被代码读取的 AI_DEFAULT_CONNECT_TIMEOUT_SECONDS / AI_DEFAULT_READ_TIMEOUT_SECONDS,改为说明超时来自 AiModel 字段与 Provider 分辨率默认值。
    • 同步更新 docs/06-tasks.md、docs/api.md、docs/04-architecture.md、docs/03-tech-stack.md、README.md、docs/00-ai-start-here.md、docs/current-state.md:T-105 完成,P1/P2 已修;P3 已挂到 T-201/T-302/T-403 或 Backlog。
  • 验证:
    • py -3.12 -m py_compile apps\ai\providers\openai_compatible.py apps\ai\providers\utils.py apps\ai\importers.py apps\ai\management\commands\smoke_ai_generation.py apps\ai\tests.py:通过。
    • py -3.12 manage.py test apps.ai.tests.ProviderUtilsTests apps.ai.tests.ChatCompletionsProviderTests apps.ai.tests.ImagesEditsProviderTests apps.ai.tests.AiModelsImportTests apps.ai.tests.AiGenerationSmokeCommandTests --noinput --keepdb:通过,10 tests OK。
    • py -3.12 manage.py smoke_ai_generation image --recorded --prompt "生成测试图片" --resolution 1k:通过;alias=t-105-recorded-image-27c25b3a,model_used=recorded-image-model,elapsed_ms=71,image_bytes=20。
    • py -3.12 manage.py smoke_ai_generation title --recorded --prompt "为测试商品生成3个中文标题" --resolution 1K:通过;alias=t-104-recorded-title-ceec8dab,model_used=recorded-title-model,elapsed_ms=92,title_count=3。
    • py -3.12 manage.py check:通过,0 issues。
    • py -3.12 manage.py makemigrations --check:通过,No changes detected。
    • py -3.12 -m compileall apps:通过。
    • git diff --check:通过,仅 Windows CRLF 提示。
    • ./init.ps1:通过,依赖同步与基础检查正常。
    • py -3.12 manage.py test apps.ai --noinput --keepdb:两次未作为绿灯;一次在连接远程 MySQL 测试库前超时,一次跑到 23 tests 后于 AiModelAdminTests.setUpClass 事务连接阶段超时。失败点均为远程 MySQL 43.128.3.240:3306 连接/重连,不是断言失败。
  • 阻塞:无代码阻塞。真实图片同步耗时仍未验证,已登记到 T-302/T-403;需要真实 AI_KEY_ENCRYPTION_KEY、AiModel/ModelAlias 与上游 key 后执行。
  • 决策:对外 parameters 不是任意直通上游,而是 provider 白名单安全参数;服务端固定字段优先,计费仍以能力别名/分辨率为准。未生效的全局 AI timeout 环境变量删除,避免运维误以为可通过 env 调整。
  • 下一步:领取 T-201 User / UserWallet / ApiKey / PointsLedger / CallRecord 模型。