From 2042c1a3e71ab7f20e368b75548a51aa1cff474a Mon Sep 17 00:00:00 2001 From: QiuSW <105186638@qq.com> Date: Wed, 8 Jul 2026 19:47:49 +0800 Subject: [PATCH] docs: refine image async task plan --- README.md | 2 +- docs/00-ai-start-here.md | 4 ++-- docs/06-tasks.md | 7 ++++++- docs/current-state.md | 10 +++++----- progress.md | 29 +++++++++++++++++++++++++++++ 5 files changed, 43 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 307740e..f163a7f 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ Python 3.12 / Django 5.2 LTS + DRF / django-admin / 用户端 Django 模板 SSR ## 当前状态 -Phase 2 计费核心已完成,Phase 3 对外 API 与充值已完成到 T-306,Phase 4 用户端已完成 T-501~T-505,Phase 5 已完成 T-401 运营后台完善、T-402 MVP 完整验收与 T-403 部署 / 运行文档,Phase 6 已完成 T-601 可用别名发现、T-602/T-603 django-admin 中文化、T-604 中文敏感词本地过滤、T-605 免邮箱验证策略落地、T-606 公开首页 + 客户端下载入口、T-607 桌面端最新版本检查接口、T-608 新用户注册赠送 100 点试用点数与 T-609 桌面端版本强制更新标记。用户可通过公开首页进入注册、登录和下载入口;新用户注册后经计费层自动获得 100 点并写注册赠点流水;登录后可扫码充值并轮询到账,生成 / 删除(吊销)API Key,查看余额、充值总额、分页充值记录、分页点数记录与可用模型;桌面端可匿名请求最新客户端版本 JSON,并读取 `release.force_update` 判断是否必须升级;运营可在 django-admin 检索用户、钱包、API Key、计费规则、汇率、充值订单、点数流水、注册赠点记录、调用记录和客户端发布版本,并通过计费层带原因手工调点;生产部署按 `docs/deployment.md` 执行。生产侧仍需补真实支付回调到账闭环、配置并发布客户端下载包和图片真实耗时验证;邮件服务仅用于后续密码找回/通知等邮件能力,不阻塞注册登录。详见 [`docs/current-state.md`](docs/current-state.md)。 +Phase 2 计费核心已完成,Phase 3 对外 API 与充值已完成到 T-306,Phase 4 用户端已完成 T-501~T-505,Phase 5 已完成 T-401 运营后台完善、T-402 MVP 完整验收与 T-403 部署 / 运行文档,Phase 6 已完成 T-601 可用别名发现、T-602/T-603 django-admin 中文化、T-604 中文敏感词本地过滤、T-605 免邮箱验证策略落地、T-606 公开首页 + 客户端下载入口、T-607 桌面端最新版本检查接口、T-608 新用户注册赠送 100 点试用点数、T-609 桌面端版本强制更新标记、T-610 首页导入模板下载入口与 T-611 用户端品牌名统一为“虾皮圈”。用户可通过公开首页进入注册、登录、下载客户端和下载导入模板;新用户注册后经计费层自动获得 100 点并写注册赠点流水;登录后可扫码充值并轮询到账,生成 / 删除(吊销)API Key,查看余额、充值总额、分页充值记录、分页点数记录与可用模型;桌面端可匿名请求最新客户端版本 JSON,并读取 `release.force_update` 判断是否必须升级;运营可在 django-admin 检索用户、钱包、API Key、计费规则、汇率、充值订单、点数流水、注册赠点记录、调用记录、客户端发布版本和导入模板,并通过计费层带原因手工调点。下一步已拆为 T-612~T-615,优先处理生图同步接口止血、共享生成 core、异步提交轮询和旧同步接口遥测;生产侧仍需补真实支付回调到账闭环。详见 [`docs/current-state.md`](docs/current-state.md)。 > ⚠️ 涉及资金/点数。改动充值、扣费、退款、对账相关代码前,先读 [`docs/05-coding-rules.md`](docs/05-coding-rules.md) 第 8 节与 [`docs/04-architecture.md`](docs/04-architecture.md) 第四节计费时序。 diff --git a/docs/00-ai-start-here.md b/docs/00-ai-start-here.md index cbf281b..4073641 100644 --- a/docs/00-ai-start-here.md +++ b/docs/00-ai-start-here.md @@ -38,7 +38,7 @@ ## 当前阶段 -当前项目处于:**Phase 6 增强任务推进期**。Phase 2 计费核心已完成到 T-204;Phase 3 已完成 T-301 API Key 鉴权、T-302 生成标题 / 图片接口、T-303 余额查询接口、T-304 充值回调、T-305 扫码充值下单 + 轮询与 T-306 对外 API 安全加固;Phase 4 已完成 T-501 注册 / 登录(allauth)、T-502 API Key 自助管理页、T-503 个人中心 / 记录页、T-504 充值页与 T-505 用户端审核优化;Phase 5 已完成 T-401 运营后台完善、T-402 MVP 完整验收与 T-403 部署 / 运行文档;Phase 6 已完成 T-601「可用别名发现」、T-602「django-admin 中文化第 1-3 层」、T-603「django-admin 字段级中文化」、T-604「中文敏感词本地过滤」、T-605「免邮箱验证策略落地」、T-606「公开首页 + 客户端下载入口」、T-607「桌面端最新版本检查接口」、T-608「新用户注册赠送 100 点试用点数」、T-609「桌面端版本检查接口增加强制更新标记」、T-610「首页导入模板下载入口」与 T-611「用户端品牌名统一为虾皮圈」。生产侧仍需补真实支付回调到账闭环、配置并发布客户端下载包和图片生成真实耗时验证;邮件服务仅用于后续密码找回/通知等邮件能力,不阻塞注册登录。 +当前项目处于:**Phase 6 增强任务推进期**。Phase 2 计费核心已完成到 T-204;Phase 3 已完成 T-301 API Key 鉴权、T-302 生成标题 / 图片接口、T-303 余额查询接口、T-304 充值回调、T-305 扫码充值下单 + 轮询与 T-306 对外 API 安全加固;Phase 4 已完成 T-501 注册 / 登录(allauth)、T-502 API Key 自助管理页、T-503 个人中心 / 记录页、T-504 充值页与 T-505 用户端审核优化;Phase 5 已完成 T-401 运营后台完善、T-402 MVP 完整验收与 T-403 部署 / 运行文档;Phase 6 已完成 T-601「可用别名发现」、T-602「django-admin 中文化第 1-3 层」、T-603「django-admin 字段级中文化」、T-604「中文敏感词本地过滤」、T-605「免邮箱验证策略落地」、T-606「公开首页 + 客户端下载入口」、T-607「桌面端最新版本检查接口」、T-608「新用户注册赠送 100 点试用点数」、T-609「桌面端版本检查接口增加强制更新标记」、T-610「首页导入模板下载入口」与 T-611「用户端品牌名统一为虾皮圈」。生图慢 / 504 / 客户端超时已拆为 T-612~T-615:先做同步接口止血和上游硬截止,再抽共享生成 core,随后新增异步提交轮询接口并观察旧同步接口用量。生产侧仍需补真实支付回调到账闭环;邮件服务仅用于后续密码找回/通知等邮件能力,不阻塞注册登录。 优先路径: @@ -48,7 +48,7 @@ 4. Phase 3:对外 API 与充值 —— T-301 Key 鉴权、T-302 生成接口、T-303 余额查询、T-304 充值回调、T-305 扫码下单与轮询、T-306 安全加固已完成。 5. Phase 4:用户端(Django 模板 SSR)—— T-501 注册登录、T-502 API Key 管理、T-503 个人中心 / 记录页、T-504 充值页与 T-505 用户端审核优化已完成。 6. Phase 5:后台与发布 —— T-401 运营后台完善、T-402 完整验收 MVP、T-403 部署 / 运行文档已完成;计划内 MVP 任务已收尾。 -7. Phase 6:增强(MVP 后)—— T-601 可用别名发现已完成,实现 `/api/v1/models` 与 portal 只读「可用模型」页;T-602 已完成 django-admin 分组/表名中文化;T-603 已完成字段级中文标签代码与 no-op 迁移并人工确认 admin 字段中文化;T-604 已完成中文敏感词本地过滤;T-605 已完成免邮箱验证策略落地;T-606 已完成公开首页 + 客户端下载入口;T-607 已完成桌面端最新版本检查接口;T-608 已完成新用户注册赠送 100 点试用点数;T-609 已完成桌面端版本检查接口增加强制更新标记;T-610 已完成首页导入模板下载入口;T-611 已完成用户端品牌名统一为虾皮圈。 +7. Phase 6:增强(MVP 后)—— T-601 可用别名发现已完成,实现 `/api/v1/models` 与 portal 只读「可用模型」页;T-602 已完成 django-admin 分组/表名中文化;T-603 已完成字段级中文标签代码与 no-op 迁移并人工确认 admin 字段中文化;T-604 已完成中文敏感词本地过滤;T-605 已完成免邮箱验证策略落地;T-606 已完成公开首页 + 客户端下载入口;T-607 已完成桌面端最新版本检查接口;T-608 已完成新用户注册赠送 100 点试用点数;T-609 已完成桌面端版本检查接口增加强制更新标记;T-610 已完成首页导入模板下载入口;T-611 已完成用户端品牌名统一为虾皮圈;T-612~T-615 已立项为生图链路治理任务,当前下一个可领取任务为 T-612。 ## 领取任务规则 diff --git a/docs/06-tasks.md b/docs/06-tasks.md index c38f99d..1cd1e40 100644 --- a/docs/06-tasks.md +++ b/docs/06-tasks.md @@ -90,6 +90,10 @@ | T-609 | 桌面端版本检查接口增加强制更新标记 | T-607 | 在 `GET /api/v1/client/releases/latest?platform=windows` 的当前版本响应中,为 `release` 对象新增布尔字段 `force_update`,用于桌面端判断是否必须升级。**接口兼容**:只新增字段,不删除既有 `version` / `download_url` / `sha256` / `release_notes` / `published_at` 字段;无当前版本或无下载地址时仍返回 `release:null`,不返回 `force_update`。**数据来源**:在 `DownloadRelease` 增加 `force_update` 布尔字段,默认 `false`;django-admin 可编辑并在列表展示。**示例**:`{platform:"windows", release:{version:"0.1.1", download_url:"...0.1.1.zip", release_notes:"优化了ai模块的生图的功能", force_update:true}}`。**安全**:接口仍公开匿名只读,不读取用户、不扣点、不暴露后台 ID、本地文件路径或内部状态。**文档**:同步 `api.md`、`routes.md`、`04-architecture.md`、`current-state.md`、版本接口对接文档口径。**测试**:覆盖 `force_update=true` / 默认 `false`、无 current release 不返回该字段、响应字段白名单更新、admin 字段可见;`makemigrations` / `migrate` / `check` / 目标测试通过并在 `../progress.md` 留证据 | DONE | | T-610 | 首页导入模板下载入口 | T-606 | 在公开首页“下载客户端”按钮右侧新增“下载导入模板”链接,让用户下载桌面端导入商品数据使用的 Excel 模板。**产品口径**:模板下载是公开资源,匿名可见;不需要登录、不需要 API Key、不扣点、不占用生成接口限流。**后台配置**:新增独立 `ImportTemplate`(不要复用 `DownloadRelease`,两者生命周期不同),字段建议包含 `name`、`file`(FileField,`MEDIA_ROOT/import_templates/`)、`external_url`(可选,有则优先,后续切 CDN/对象存储)、`sha256`(可选)、`is_current`、`notes`、`created_at`、`updated_at`;admin 可上传/更新模板并标记当前模板;每次保存 current 时把其他 current 置为 false,避免使用 MySQL 不支持的条件唯一约束。**首页行为**:`HomeView` 同时读取 Windows 当前 `DownloadRelease` 和当前 `ImportTemplate`;有当前模板且有可下载地址时,在“下载客户端”右侧展示“下载导入模板”链接;无模板时不显示该链接或显示不可用提示,不能影响客户端下载入口和首页 200。**托管策略**:本地上传模板复用生产 Nginx `/media/` 静态托管,不经 Django/Gunicorn 传大文件;`external_url` 优先于 `file.url`,响应/页面不得暴露本地 `MEDIA_ROOT` 或服务器文件路径。**UI**:保持 T-606 下载区现有布局,桌面端按钮为主按钮,导入模板为次级链接/按钮;移动端需换行不重叠。**文档**:同步 `02-requirements.md`、`04-architecture.md`、`routes.md`、`api.md`、`current-state.md`。**测试**:覆盖首页有模板时展示链接且 href 为绝对/可访问 media URL,`external_url` 优先,本地路径不泄露,无模板时首页正常且不显示错误;admin 字段可见;`makemigrations` / `migrate` / `check` / 目标测试通过并在 `../progress.md` 留证据 | DONE | | T-611 | 用户端品牌名统一为“虾皮圈” | T-606 | 把用户端页面上对外展示的项目/产品名从 `cmhub` 统一改为“虾皮圈”。**范围**:只改终端用户可见的 portal 页面文案和浏览器标题,包括公开首页、顶部导航品牌、注册/登录/登出页、控制台、充值、API Key、可用模型、充值记录、点数记录等模板中作为品牌/产品名出现的 `cmhub`;用户端文案里的“cmhub API Key”应改为“虾皮圈 API Key”。**不改**:仓库名、Python 包名、Django app 名、数据库表名、环境变量、API 路径、域名、对外接口字段、后台内部模型名和技术文档里指代服务代号的 `cmhub`。**文档**:同步 `02-requirements.md`、`00-ai-start-here.md`、`current-state.md` 与 `../progress.md`。**测试**:更新 portal 相关断言,覆盖首页展示“虾皮圈”且不再展示旧标题 `cmhub AI 电商生成台`;关键用户端页面渲染不含作为品牌展示的 `cmhub`;`check`、`makemigrations --check --dry-run`、目标 portal 测试通过并在 `../progress.md` 留证据 | DONE | +| T-612 | 生图同步接口止血(上游硬截止 + 长请求池校准) | T-403 | **先行止血,不改成功响应契约**,保护存量老客户端的旧同步路。**真实现状**:线上已按路径分流到独立 Gunicorn 长请求池,当前是 `gthread` 而非 sync worker;P0 风险是同步生图长请求仍会占用生成池线程,上游慢 / 卡死时导致生成池排队、客户端写入或读取超时,并可能拖慢同池生文接口。**硬截止优先**:新增可配置上游生图硬截止(建议 `AI_IMAGE_UPSTREAM_DEADLINE_SECONDS`,默认 180s 左右,生产按真实 smoke 校准),Provider 实际读取超时取 `min(AiModel.timeout_seconds 或分辨率默认值, AI_IMAGE_UPSTREAM_DEADLINE_SECONDS)`;撞截止必须走现有失败退点路径,保证不超扣、不扣成负数。**Worker 策略**:默认继续使用已验证的 `gthread` 长请求池并校准 `workers/threads/timeout`;只有在本地和生产预演证明 `requests`、PyMySQL、Django cache、支付 SDK 在 monkey-patch 下无问题时,才允许把 `gevent` 作为替代方案写入部署文档,不能把 gevent 当成默认第一步。**接口兼容**:`POST /api/v1/generate/image` 的成功响应字段保持不变;失败响应外层结构保持 `{error:{code,message}}`,如新增 `upstream_timeout` 错误码必须同步 `api.md` 并保持旧客户端可按失败处理。**文档**:同步 `deployment.md`(硬截止、`AiModel.timeout_seconds`、Gunicorn `--timeout`、Nginx `proxy_read_timeout`、客户端 read timeout 的外层 >= 内层关系)、`04-architecture.md` 和 `env.md`。**验收**:模拟上游超时能退点并返回结构化错误;压测下卡死上游不会拖垮 `/balance`、`/models`,生文排队受控;线上配置仍保留 web 池和 generate 池分离;`check`/目标测试/`init` 通过并在 `../progress.md` 留证据 | TODO | +| T-613 | 抽生成核心 service(计费+审核+上游共享 core) | T-612, T-302, T-604 | 为异步化铺路,**重构现有 `apps/api/generation.py`,不是另写第二套生成逻辑**。把「别名解析+能力校验 → 审核(T-604) → 图片输入处理 → 计费计算 → 预扣(precharge) → 调上游 → 保存结果 → 成功确认/失败退点」整理为不依赖 DRF `Request` / `Response` 的核心 service,并为 T-614 拆出可复用的阶段:同步旧接口可一口气执行完整 pipeline,异步 worker 可复用“已预扣 call_record 的执行与确认 / 退点”阶段,**严禁复制第二套扣点/退点逻辑**。**HTTP 解耦**:核心 service 不直接构造 DRF `Response`,错误用领域异常表达;图片保存不能强依赖 `request.build_absolute_uri()`,需通过 URL 构建器或公开基础 URL 生成结果 URL。**兼容约束**:旧 `POST /api/v1/generate/title|image` 的字段、HTTP 状态码和错误语义保持不变;不要求 JSON 字段顺序逐字节一致。**验收**:T-302/T-604 既有断言不降低标准即通过;覆盖旧同步接口成功、上游失败退点、敏感词拦截不扣点、图片 URL 保存;`check`/目标测试/`init` 通过并在 `../progress.md` 留证据 | TODO | +| T-614 | 生图异步任务化接口(提交+轮询,新增不动旧接口) | T-613, T-203, T-301 | 新增任务化接口与旧同步接口**共存**(expand-contract 并行变更),新版桌面端走新路、老版本零感知。跨仓契约参考 cmshopee 侧设计(Obsidian「生图接口异步任务化-提交轮询方案」评审修订 v2),**落地口径以本任务 + `api.md` 为准**。**新增路由**:`POST /api/v1/generate/image/tasks`(提交后返回 `202` + `task_id`)、`GET /api/v1/generate/image/tasks/{task_id}`(轮询取状态和结果);本期不暴露 cancel 路由,若后续要做取消单独拆任务且只允许取消 `queued`。**任务模型**:新增 `ImageGenerationTask`,公开 `task_id` 用 UUID,不暴露自增 ID;字段至少包含 `user`、`api_key`、`call_record`、`status(queued/running/succeeded/failed/expired)`、`idempotency_key`、`request_hash`、必要的请求快照 / 输入引用、`result_url`、`error_code`、`error_message`、`started_at`、`finished_at`、`expires_at`、`locked_at`、`lease_expires_at`、`heartbeat_at`、`worker_id`、`attempt_count`。不得把 provider raw、密钥或超大 base64 原文长期存 DB;`image_base64` 应先解码后落临时文件 / 存储引用,`image_url` submit 阶段至少做协议与公网地址校验,实际下载可在 worker 内执行,失败走退点。**提交段**:审核(T-604)同步执行,命中 BLOCK 直接 `400 content_blocked`,不建 task、不扣点、不调上游;submit 时预扣(沿用现有 `precharge`),余额不足 `402`,堵住「余额只够 1 张却提交 100 个 task」;建任务后立即返回 `202`。**幂等**:支持 `Idempotency-Key`,按 `api_key + operation + key` 去重;同 key 同 payload 返回同一 `task_id` 且不重复预扣,同 key 不同 payload 返回 `409 idempotency_conflict`。**后台 worker**:优先用 DB 任务表 + management command worker + systemd 托管,MySQL 8.4 可用 `select_for_update(skip_locked)` 抢任务;暂不引入 Celery/Redis,`django-q`/`huey` 只有在 DB worker 不够时再单独评估。worker 必须复用 T-613 共享 core 和已预扣的 `CallRecord`,成功保留扣点并返回 cmhub 托管 URL,失败/撞硬截止必须退点。**结果 URL**:异步 worker 没有 request,必须新增 `PUBLIC_BASE_URL` 或 `MEDIA_PUBLIC_BASE_URL` 等配置来生成绝对 URL;不得透传上游临时链接。**查询段**:只读、短超时,必须校验 `task.user == api_key.user`(防 IDOR,跨用户返回 404 或 403);`succeeded` 幂等重取返回同一 URL;过期任务 / 图片 GC 口径写入文档。**保留窗口**:task_id 持久化的目的是扛客户端重启,窗口须覆盖桌面端现实停机(如关一晚),**任务元数据保留 ≥24h、结果图保留更久(如 24–72h,可配,别硬编码 6h)**,避免「点已扣、图被 GC」。**租约与僵任务回收(reaper,必做)**:worker 抢任务时写 `worker_id`、`locked_at`、`lease_expires_at`,运行中周期性更新 `heartbeat_at`;如果 worker 用 `select_for_update(skip_locked)` 抢任务后崩溃,行锁随连接释放但 `status` 会永远停在 `running`——**点数已预扣却永不退、客户端轮询到自己超时**。reaper 按 `lease_expires_at` / `heartbeat_at`(兜底 `started_at`)识别僵任务,默认把超时 `running` 判 `failed` + **退点(幂等)**,不默认重排队;只有能证明任务尚未调上游(如明确 `stage=not_started`)时才允许后续任务设计重排队。**worker 至少一次执行,账务和结果 exactly-once**:worker 可能重复执行同一任务,但「上游调用确认 / 退点 / 写结果」这些终态动作必须幂等;重复执行不得重复扣/退,不得覆盖已 `succeeded` 结果,也不得把 reaper 已判 `failed` 且已退点的任务改回 `succeeded`。**配置**:新增或同步 `IMAGE_TASK_RETENTION_HOURS`、`GENERATED_IMAGE_RETENTION_HOURS`、`IMAGE_TASK_REAPER_INTERVAL_SECONDS`、`IMAGE_TASK_LEASE_SECONDS` 等环境变量口径。**文档**:同步 `api.md`(新契约、状态机、错误码、幂等)、`routes.md`、`04-architecture.md`(异步计费时序)、`deployment.md`(worker 进程托管)、`env.md`。**验收**:审核命中不建 task/不扣点/不调上游;预扣余额不足 402;同 Idempotency-Key 去重且 payload 冲突 409;worker 成功后重复 GET 同一 URL;跨用户 GET 被拒;失败/超时退点不超扣;**模拟 worker 崩溃留下 `running` 僵任务 → reaper 判失败并退点、不超扣、客户端下次 GET 得到 `failed`**;**worker 重复执行同一任务幂等(不重复扣/退、不覆盖已 `succeeded` 结果)**;**reaper 已把任务判 `failed` 并退点后,迟到 worker 返回成功也不能改回 `succeeded`、不能覆盖结果、不能再次改账**;旧生文与旧同步生图不回归;`check`/目标测试/`init` 通过并在 `../progress.md` 留证据 | TODO | +| T-615 | 旧同步生图接口用量遥测 + 弃用口径 | T-614 | 给旧同步接口装可观测、定弃用退出条件,避免永久双维护。**最小遥测**:旧 `POST /api/v1/generate/image` 和新 `/tasks` 路径都写结构化日志 / 计数,至少含 route_type(sync/async)、api_key 前缀或 ID、user_id、client version(若请求头提供,如 `X-Client-Version`)、alias、status、latency_ms、error_code;日志不得包含 API Key 明文、prompt 全文、图片 base64 或 provider raw。**查看方式**:先用日志查询即可;若要 admin 报表需单独评估数据量和索引。**弃用口径**:在 `deployment.md`/`04-architecture.md` 记录迁移计划:新版桌面端默认走异步接口 → 观察旧路调用量和错误率 → 旧路调用归零或低于阈值一段时间 → 宣布 deprecate → 另立任务下线;旧同步接口下线前必须保留成功响应兼容。**验收**:能按 client version / api_key 看到旧路与新路用量;弃用条件成文;不泄露敏感数据;`check`/目标测试/`init` 通过并在 `../progress.md` 留证据 | TODO | ## 里程碑 @@ -103,10 +107,11 @@ - M8:客户端版本强制更新标记(T-609)。 - M9:首页导入模板下载入口(T-610)。 - M10:用户端品牌名统一为“虾皮圈”(T-611)。 +- M11:生图异步任务化(先止血、后共享 core、再新老接口共存并观察旧路用量,T-612~T-615)。 ## 待办池(Backlog) -- 异步生成(任务队列 + 轮询/回调)。 +- ~~异步生成(任务队列 + 轮询/回调)~~ → 已立项 **T-612~T-615**(生图异步任务化:先硬截止 + 长请求池校准止血,再抽共享 core,最后新增 `/tasks` 提交+轮询接口与旧同步接口共存、旧路遥测后弃用)。 - 按账号授权可用别名(`account_alias_permission`),防止调用未授权/昂贵模型。 - 别名按比例分流到多个模型(灰度 / A/B / 故障转移);供应商 A 故障自动切 B。 - 复杂活动赠点、邀请奖励、历史用户批量补发(需单独审批、风控、批处理与流水留痕)。 diff --git a/docs/current-state.md b/docs/current-state.md index 3362a0f..db5104f 100644 --- a/docs/current-state.md +++ b/docs/current-state.md @@ -56,9 +56,9 @@ - 已完成:T-001 初始化 Django + DRF 项目骨架;T-002 建立 apps 目录、自定义 User 与配置;T-003 接通 django-admin 与最小测试;T-004 Phase 0 骨架审核修补;T-101 Provider 适配器层 + 移植 cmbot 调用;T-102 AiModel + ModelAlias 模型 + 别名解析;T-103 配置变更审计;T-104 跑通一次录制标题生成;T-105 Phase 1 AI 层审核修补;T-201 User / UserWallet / ApiKey / PointsLedger / CallRecord 模型;T-202 PricingRule / ExchangeRate 模型 + 计费计算;T-203 并发安全扣点 / 退点;T-204 Phase 2 计费核心审核加固;T-301 API Key 鉴权;T-302 生成标题 / 图片接口;T-303 余额查询接口;T-304 充值回调;T-305 扫码充值下单 + 轮询;T-306 Phase 3 对外 API 安全加固;T-501 注册 / 登录(allauth);T-502 API Key 自助管理页;T-503 个人中心 / 记录页;T-504 充值页(扫码 + 轮询到账);T-505 Phase 4 用户端审核优化;T-401 运营后台完善;T-402 完整验收 MVP;T-403 部署 / 运行文档;T-601 可用别名发现;T-602 django-admin 中文化(第 1-3 层);T-603 django-admin 中文化(第 4 层·字段级);T-604 中文敏感词本地过滤;T-605 免邮箱验证策略落地;T-606 公开首页 + 客户端下载入口;T-607 桌面端最新版本检查接口;T-608 新用户注册赠送 100 点试用点数;T-609 桌面端版本检查接口增加强制更新标记;T-610 首页导入模板下载入口;T-611 用户端品牌名统一为虾皮圈。 - 正在进行:无。 -- 待开始:当前无编号 TODO;之后可继续处理真实支付回调到账闭环、配置并发布客户端下载包、真实图片耗时验证,或从 Backlog 拆新任务。 -- 当前 blocker:支付商户真实密钥/证书与生产 SDK 依赖仍待提供;微信回调到账闭环仍需真实支付验收;真实 AI 标题生成已在线上跑通,图片生成真实耗时仍需补测。 -- 下一个可领取任务:当前无编号 TODO;需先从 Backlog 或业务优先级拆出下一项任务。 +- 待开始:T-612 生图同步接口止血(上游硬截止 + 长请求池校准)、T-613 抽生成核心 service、T-614 生图异步任务化接口、T-615 旧同步生图接口用量遥测 + 弃用口径。 +- 当前 blocker:支付商户真实密钥/证书与生产 SDK 依赖仍待提供;微信回调到账闭环仍需真实支付验收;真实 AI 标题生成已在线上跑通,图片生成慢 / 504 / 客户端超时风险已拆为 T-612~T-615 分阶段处理。 +- 下一个可领取任务:T-612 生图同步接口止血(上游硬截止 + 长请求池校准)。 ## 当前可运行内容 @@ -123,8 +123,8 @@ gunicorn config.wsgi:application --bind 127.0.0.1:8002 --workers 1 --worker-clas 1. 读仓库级 `AGENTS.md` / `CLAUDE.md`。 2. 读 `docs/00-ai-start-here.md`。 3. 读 `docs/05-coding-rules.md`(尤其第 8 节资金安全)。 -4. 在 `docs/06-tasks.md` 领取第一个 `TODO` 且依赖均 `DONE` 的任务;当前无编号 TODO。 -5. 下一步按业务优先级拆真实支付回调到账闭环、客户端下载包发布、真实图片耗时验证,或从 Backlog 创建新任务。 +4. 在 `docs/06-tasks.md` 领取第一个 `TODO` 且依赖均 `DONE` 的任务;当前为 T-612。 +5. 下一步优先处理 T-612,给旧同步生图接口加上游硬截止并校准长请求池;真实支付回调到账闭环和客户端下载包发布继续作为后续业务事项排期。 ## 维护规则 diff --git a/progress.md b/progress.md index cf80789..8d3af55 100644 --- a/progress.md +++ b/progress.md @@ -1619,3 +1619,32 @@ - `git diff --check`:通过,仅 Windows CRLF 提示。 - `py -3.12 manage.py test apps.portal.tests.PortalAccountFlowTests.test_homepage_is_public_and_shows_anonymous_onboarding_without_release apps.portal.tests.PortalAccountFlowTests.test_homepage_shows_current_download_release apps.portal.tests.PortalAccountFlowTests.test_portal_pages_use_shopee_circle_branding --keepdb --noinput --verbosity 2`:通过,3 tests OK。 - 下一步:如需线上生效,部署最新代码到 185.216.248.75 并重启服务;无数据库迁移需要执行。 + +## 2026-07-08 生图异步任务化任务口径修正(非任务) + +- 状态:DONE。 +- 背景:Claude Code 新增了 T-612~T-615 草案,用于处理生图慢、504 gateway timeout、客户端请求超时和旧同步接口迁移问题。复核线上实际运行后确认当前 `cmhub-generate` 已是 `gthread --workers 2 --threads 16 --timeout 900`,并非 sync worker,因此原草案中“sync worker 池饥饿 → 默认切 gevent”的口径需要修正。 +- 文档变更: + - `docs/06-tasks.md`:T-612 改为“上游硬截止 + 长请求池校准”,明确先保留已验证的 `gthread` 长请求池,gevent 仅作为兼容性验证后的替代方案;T-613 明确重构现有 `apps/api/generation.py`,不得复制第二套扣点 / 退点逻辑;T-614 补充 `ImageGenerationTask`、UUID `task_id`、`Idempotency-Key` 去重与 payload 冲突、DB worker + systemd、公开 URL 配置、IDOR 防护和本期不暴露 cancel;T-615 补充旧同步 / 新异步路径结构化遥测与弃用条件。 + - `docs/current-state.md`:把“当前无编号 TODO”更新为 T-612~T-615 待开始,下一步为 T-612。 + - `README.md`、`docs/00-ai-start-here.md`:同步 Phase 6 当前状态和下一步任务。 +- 验证: + - `git diff --check -- README.md docs/00-ai-start-here.md docs/06-tasks.md docs/current-state.md`:通过,仅 Windows CRLF 提示。 + - `Select-String` 确认 `docs/06-tasks.md` 中 T-612~T-615、M11 和 Backlog 已更新,`docs/current-state.md` 的下一个可领取任务为 T-612。 + - `rg -n "sync worker|先 gevent|当前无编号 TODO|图片真实耗时验证" README.md docs/00-ai-start-here.md docs/06-tasks.md docs/current-state.md`:仅保留 T-612 中“当前是 `gthread` 而非 sync worker”的事实说明,未再出现“当前无编号 TODO”等旧口径。 +- 阻塞:无。 +- 决策:T-612 先做硬截止和现有 gthread 长请求池校准,不把 gevent 作为默认第一步;T-614 第一版用 DB 任务表 + management command worker + systemd,不引入 Celery / Redis;异步 worker 必须复用共享 core 和已预扣 `CallRecord`,不得复制资金逻辑。 +- 下一步:领取 T-612,先更新 `deployment.md` / `04-architecture.md` / `env.md`,再落代码实现上游硬截止与退点测试。 + +## 2026-07-08 T-614 验收条件加固(非任务) + +- 状态:DONE。 +- 背景:复核 Claude Code 对 T-614 的新增验收条件后,确认“结果保留窗口”“僵任务回收 reaper”“worker 重复执行幂等”方向合理,但需要把重排队、租约和迟到 worker 的口径写得更严格。 +- 变更:更新 `docs/06-tasks.md` 中 T-614: + - `ImageGenerationTask` 字段补充 `locked_at`、`lease_expires_at`、`heartbeat_at`、`worker_id`、`attempt_count`。 + - reaper 改为按 `lease_expires_at` / `heartbeat_at` 识别僵任务,默认 `running -> failed + 退点`,不默认重排队;只有能证明尚未调上游时才允许后续任务设计重排队。 + - worker 语义改为“允许至少一次执行,但账务和结果终态必须 exactly-once”,不得重复扣 / 退,不得覆盖已成功结果,也不得把已被 reaper 判失败并退点的任务改回成功。 + - 环境变量口径补充 `IMAGE_TASK_RETENTION_HOURS`、`GENERATED_IMAGE_RETENTION_HOURS`、`IMAGE_TASK_REAPER_INTERVAL_SECONDS`、`IMAGE_TASK_LEASE_SECONDS`。 + - 验收补充迟到 worker 场景:reaper 已判失败并退点后,迟到 worker 返回成功也不能改回 `succeeded`、不能覆盖结果、不能再次改账。 +- 验证:仅文档更新;提交前用 `git diff --check`、`Select-String` 复核。 +- 下一步:提交本轮文档;后续领取 T-612。