fix: reduce signup bonus to ten points
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
|
||||
`cmhub` 是「**自助用户端 + 计费 API + 运营后台**」三合一服务:终端用户在用户端自助注册、扫码充值、管理 API Key,用 API Key 调用「生成标题」「生成图片」「多图理解」等 HTTP 接口,按**点数计费**;运营用 django-admin 管理用户、点数与记录。
|
||||
|
||||
第一版 MVP 做:**用户自助注册登录 → 注册成功赠送 100 点试用点数 → 扫码充值转点数 → 自助生成/删除 API Key → 带 Key 调用按规则算点数 → 点数足够则调上游生成并扣点 / 不足则报错 → 写调用与消费记录 → django-admin 运营后台**。注册赠点也是账本资产,必须经计费层入账并写点数流水。
|
||||
第一版 MVP 做:**用户自助注册登录 → 注册成功赠送 10 点试用点数 → 扫码充值转点数 → 自助生成/删除 API Key → 带 Key 调用按规则算点数 → 点数足够则调上游生成并扣点 / 不足则报错 → 写调用与消费记录 → django-admin 运营后台**。注册赠点也是账本资产,必须经计费层入账并写点数流水。
|
||||
|
||||
## 必读顺序
|
||||
|
||||
@@ -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「用户端品牌名统一为虾皮圈」、T-612「生图同步接口止血」、T-613「抽生成核心 service」、T-614「生图异步任务化接口」与 T-615「旧同步生图接口遥测 / 弃用口径」。生图慢 / 504 / 客户端超时已拆为 T-612~T-615 并完成:T-612 已做同步接口上游硬截止止血,T-613 已抽共享生成 core,T-614 已新增异步提交 / 轮询接口与 DB worker,T-615 已给旧同步 / 新异步提交路径接入结构化日志并形成旧同步接口退出条件。生产侧仍需补真实支付回调到账闭环;邮件服务仅用于后续密码找回/通知等邮件能力,不阻塞注册登录。
|
||||
当前项目处于:**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「新用户注册赠送试用点数(当前 10 点)」、T-609「桌面端版本检查接口增加强制更新标记」、T-610「首页导入模板下载入口」、T-611「用户端品牌名统一为虾皮圈」、T-612「生图同步接口止血」、T-613「抽生成核心 service」、T-614「生图异步任务化接口」与 T-615「旧同步生图接口遥测 / 弃用口径」。生图慢 / 504 / 客户端超时已拆为 T-612~T-615 并完成:T-612 已做同步接口上游硬截止止血,T-613 已抽共享生成 core,T-614 已新增异步提交 / 轮询接口与 DB worker,T-615 已给旧同步 / 新异步提交路径接入结构化日志并形成旧同步接口退出条件。生产侧仍需补真实支付回调到账闭环;邮件服务仅用于后续密码找回/通知等邮件能力,不阻塞注册登录。
|
||||
|
||||
T-616~T-620 也已完成:生图失败自动重试、客户端版本文件校验元数据、多图理解 `vision` 操作与同步接口,以及单图 / 多图图生图均已落地。T-620 保持旧单图字段兼容,并固定第一张为主图、后续为参考图;生产启用多图理解前仍需在 admin 配置视觉模型、默认别名和计费规则。
|
||||
|
||||
@@ -70,7 +70,7 @@ T-616~T-620 也已完成:生图失败自动重试、客户端版本文件校
|
||||
|
||||
MVP 只做:
|
||||
|
||||
- **用户端(Django 模板 SSR + Bootstrap)**:自助注册/登录、注册成功一次性赠送 100 点试用点数、扫码充值、查看充值记录/充值总额/剩余点数/消费记录、自助生成与删除 API Key。
|
||||
- **用户端(Django 模板 SSR + Bootstrap)**:自助注册/登录、注册成功一次性赠送 10 点试用点数、扫码充值、查看充值记录/充值总额/剩余点数/消费记录、自助生成与删除 API Key。
|
||||
- 对外生成 / 理解接口:`POST /api/v1/generate/title`(同步返回标题)、`POST /api/v1/generate/image`(旧同步生图,保留兼容)、`POST /api/v1/generate/image/tasks` + `GET /api/v1/generate/image/tasks/{task_id}`(异步生图提交 / 轮询)、`POST /api/v1/analyze/images`(同步多图理解并返回文字)。
|
||||
- API Key 鉴权,识别所属注册用户(API 只认 Key,不认 Web session)。
|
||||
- 点数计费:按「操作类型 + 能力别名(+ 可选分辨率)」查计费规则得点数;本地余额原子扣减;不足报错。
|
||||
@@ -83,7 +83,7 @@ MVP 不做:
|
||||
- Celery/RQ 等外部任务队列(T-614 已用 DB 任务表 + management command worker 实现生图异步提交 / 轮询;本期不做 cancel、回调通知或专业队列)。
|
||||
- 自建支付/收银台(充值走外部支付系统,本服务发起扫码下单并接收回调,不碰资金清算)。
|
||||
- 面向终端消费者的「内容生成产品页」(用户端只做账户自助,生成结果仍只经 API 输出)。
|
||||
- 复杂活动赠点、邀请奖励或历史用户自动补发;除 T-608 明确定义的新用户一次性 100 点注册试用额度外,不做其他免费点数活动。
|
||||
- 复杂活动赠点、邀请奖励或历史用户自动补发;除 T-608 明确定义的新用户一次性 10 点注册试用额度外,不做其他免费点数活动。
|
||||
- 多币种、分账、自动退款对账。
|
||||
|
||||
## 事实来源
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@
|
||||
- **核心流程优先**:先把「鉴权 → 计费 → 生成 → 扣点 → 记录」这条主链路做顺。
|
||||
- **真实数据优先**:点数、金额、扣费、充值不造假;不用演示逻辑冒充计费逻辑。
|
||||
- **账目必须对得上**:每一笔点数变动都有流水、可追溯到充值订单或调用记录。
|
||||
- **试用额度可控**:新用户注册送 100 点试用点数降低首次接入门槛,但必须按账本发放、可追溯、可防重复。
|
||||
- **试用额度可控**:新用户注册送 10 点试用点数降低首次接入门槛,但必须按账本发放、可追溯、可防重复。
|
||||
- **小步交付**:每一步都能运行、能验证、能回退。
|
||||
- **少即是稳**:MVP 不追求完整,只追求最小闭环可靠;先同步、先单机、先后台手工开通。
|
||||
- **可维护**:复用 `cmbot` 现有 AI 调用代码,不另起一套。
|
||||
@@ -40,7 +40,7 @@
|
||||
- 不做自建支付/收银台,付款在外部支付系统完成,本服务发起扫码下单并接收回调,不碰资金清算。
|
||||
- 不做异步任务队列(第一版图片生成走同步等待)。
|
||||
- 不做面向终端消费者的「内容生成产品页」;用户端只做账户自助(注册/充值/API Key 管理/记录查询)。
|
||||
- 不做复杂活动赠点、邀请奖励或历史用户自动补发;当前只做新用户注册一次性 100 点试用额度,且必须配套防刷、幂等和流水留痕。
|
||||
- 不做复杂活动赠点、邀请奖励或历史用户自动补发;当前只做新用户注册一次性 10 点试用额度,且必须配套防刷、幂等和流水留痕。
|
||||
- 不做多币种、分账、自动退款对账等容易膨胀、不属于 MVP 的能力。
|
||||
|
||||
> MVP 的具体功能范围与验收标准,见 [需求](02-requirements.md)。
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
|
||||
| 功能 | 用户能做什么 | 优先级 |
|
||||
| --- | --- | --- |
|
||||
| 用户注册/登录 | 终端用户在用户端自助注册、登录(**免邮箱验证、注册即可用;邮箱仍必填且唯一**);注册成功一次性赠送 **100 点**试用点数 | P0 |
|
||||
| 用户注册/登录 | 终端用户在用户端自助注册、登录(**免邮箱验证、注册即可用;邮箱仍必填且唯一**);注册成功一次性赠送 **10 点**试用点数 | P0 |
|
||||
| API Key 自助管理 | 登录后自助生成/删除 API Key;Key 只在生成时显示一次(库内哈希存储) | P0 |
|
||||
| 扫码充值 | 用户端发起充值→展示支付二维码→扫码付款→回调到账;金额按汇率转点数 | P0 |
|
||||
| 个人中心 | 查看剩余点数、充值总额、充值记录、点数使用(消费)记录 | P0 |
|
||||
@@ -48,13 +48,13 @@
|
||||
| --- | --- | --- |
|
||||
| 旧同步生图接口用量遥测与弃用 | 观察旧同步生图调用量、错误率和客户端版本,满足条件后再单独任务下线旧同步接口 | V2 |
|
||||
| 用量统计报表 | 按用户/时间/模型聚合消耗与成本 | V2 |
|
||||
| 复杂活动赠点 / 邀请奖励 | 注册 100 点之外的活动额度、邀请返利、历史用户补发等,需单独风控与审批 | V2 |
|
||||
| 复杂活动赠点 / 邀请奖励 | 注册 10 点之外的活动额度、邀请返利、历史用户补发等,需单独风控与审批 | V2 |
|
||||
| API Key 轮换 / 授权 | Key 到期轮换、按 Key 限授权别名 | V2 |
|
||||
| 退款对账自动化 | 外部退款联动本地点数冲正 | V3 |
|
||||
|
||||
## 四、核心用户故事(MVP)
|
||||
|
||||
1. 作为新用户,我在用户端自助注册登录后先获得 100 点试用点数;后续扫码充值一笔钱,看到对应点数按汇率到账。
|
||||
1. 作为新用户,我在用户端自助注册登录后先获得 10 点试用点数;后续扫码充值一笔钱,看到对应点数按汇率到账。
|
||||
2. 作为已登录用户,我自助生成一把 API Key(明文只显示一次),也能删除不用的 Key。
|
||||
3. 作为接入方,我带着 API Key 调用生成标题接口,传入 prompt,能拿到生成的标题。
|
||||
4. 作为接入方,我可以提交一张或多张图片生成商品图:第一张作为主商品图,后续图片仅作风格、构图、场景或排版参考;可调用旧同步接口在同一个响应里拿到图片结果,也可先提交异步图片任务拿到 `task_id` 再轮询直到成功或失败。
|
||||
@@ -74,7 +74,7 @@
|
||||
- **余额查询 API**:返回的余额等于该账号点数流水累加结果。
|
||||
- **充值转点数**:模拟一次支付系统回调(含订单号、金额、签名),验签通过后按汇率加点;**同一订单号重复回调只入账一次**(幂等);验签失败不入账。
|
||||
- **调用记录 / 点数流水**:每次成功/失败调用、每次充值/退款/调整/注册赠点都各生成一条记录,字段完整、可在后台检索。
|
||||
- **用户注册/登录**:新用户能自助注册(**免邮箱验证、注册即可用;邮箱仍必填且唯一**)、登录;注册成功后点数为 100,且有一条对应的注册赠点流水。重复提交或服务重试不得重复赠送。
|
||||
- **用户注册/登录**:新用户能自助注册(**免邮箱验证、注册即可用;邮箱仍必填且唯一**)、登录;注册成功后点数为 10,且有一条对应的注册赠点流水。重复提交或服务重试不得重复赠送。
|
||||
- **API Key 自助管理**:登录用户能生成 API Key(明文只显示一次,库内存哈希)、能删除;删除落库为吊销,吊销后该 Key 调用返回 403,缺失/无效/不存在 Key 返回 401。
|
||||
- **扫码充值**:用户端发起充值→展示二维码→(mock 或真实)支付成功回调后点数按汇率到账,充值记录与流水各一条;同一订单号重复回调只入账一次。
|
||||
- **个人中心**:剩余点数 = 点数流水累加;充值总额、充值记录、消费记录与实际一致。
|
||||
@@ -92,7 +92,7 @@
|
||||
| 生成返回方式 | 标题仍同步返回;图片旧同步接口保留兼容,新版客户端优先使用异步提交 / 轮询 |
|
||||
| 模型选择方式 | 对外用**能力别名**(如 `image-hd`),不暴露具体模型名;后台配置别名→模型映射 |
|
||||
| 充值入口 | 用户端自助发起扫码充值(本服务向支付系统下单取二维码),付款成功由支付系统**服务端回调**入账 |
|
||||
| 注册是否送点数 | 是。新用户注册成功一次性赠送 100 点试用点数;只对功能上线后的新注册用户自动发放,历史用户是否补发需另行审批和单独任务 |
|
||||
| 注册是否送点数 | 是。新用户注册成功一次性赠送 10 点试用点数;只对本次额度调整上线后的新注册用户自动发放,历史用户是否补发需另行审批和单独任务 |
|
||||
| 暂不支持 | 复杂活动赠点 / 邀请奖励、多币种、分账、自动退款对账;异步生图本期只做提交 / 轮询,不做 cancel、回调通知或 Celery/RQ |
|
||||
|
||||
## 七、待确认 / 风险点
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
| Web 框架 | Django 5.2 LTS | 已定 | 自带 ORM、迁移、admin,适合「API + 运营后台」;选 LTS 维护到 2028,安全更新窗口最长。**禁用已 EOL 的 4.0/4.1**(无安全补丁,资金服务不可用) |
|
||||
| API 框架 | Django REST Framework (DRF) | 已定 | 鉴权、序列化、参数校验、限流现成 |
|
||||
| 运营后台 | django-admin | 已定 | 近零代码即得用户/点数/记录的增删改查与检索,省 80% 后台工作量 |
|
||||
| 用户端 | Django 模板 SSR + Bootstrap 5 + django-allauth | 已定 | T-501 已落地自助注册/登录/登出与最小 dashboard;T-605 起注册策略固定为**免邮箱验证、注册即可用,邮箱仍必填且唯一**;T-608 已落地新用户注册成功经计费层赠送 100 点并写注册赠点流水;T-502 已落地 API Key 自助生成 / 删除页;T-503 已落地个人中心、充值记录和点数记录页;T-504 已落地充值页(创建订单、展示二维码票据、轮询到账后刷新);T-505 已把 Bootstrap 与 qrcode.js 改为本地 static 自托管,并给记录页加分页;MVP 先用 Django form + Bootstrap 模板,不为简单表单引入 crispy-forms |
|
||||
| 用户端 | Django 模板 SSR + Bootstrap 5 + django-allauth | 已定 | T-501 已落地自助注册/登录/登出与最小 dashboard;T-605 起注册策略固定为**免邮箱验证、注册即可用,邮箱仍必填且唯一**;T-608 已落地新用户注册成功经计费层赠送 10 点并写注册赠点流水;T-502 已落地 API Key 自助生成 / 删除页;T-503 已落地个人中心、充值记录和点数记录页;T-504 已落地充值页(创建订单、展示二维码票据、轮询到账后刷新);T-505 已把 Bootstrap 与 qrcode.js 改为本地 static 自托管,并给记录页加分页;MVP 先用 Django form + Bootstrap 模板,不为简单表单引入 crispy-forms |
|
||||
| 后台美化 | django-unfold 或 simpleui | 待定 | 仅外观,MVP 可先用原生 admin,后期按需引入 |
|
||||
| AI 上游对接 | **Provider 适配器层**(按 `api_type` 注册)+ **能力别名** 映射 + `requests` HTTP 客户端 | 已定 | 对外只暴露 `generate text/image` 两接口与别名;换供应商改后台映射,不动对外契约。移植 `cmbot` 的调用逻辑到各适配器。当前 3 模型机制不同:文本 chat、`nano-banana2` chat 多模态返图、`gpt-image-2` images/edits 改图(详见 `04` 3.1) |
|
||||
| 供应商密钥存储 | 应用层 Fernet 加密(`cryptography`) | 已定 | `AiModel.api_key_encrypted` 加密入库、admin 写入型字段不回显;加密主密钥 `AI_KEY_ENCRYPTION_KEY` 走环境变量,配置清单见 `env.md` |
|
||||
@@ -41,7 +41,7 @@
|
||||
- **新异步接口优先给新版客户端**:新版桌面端提交 `/api/v1/generate/image/tasks` 获得 `task_id`,再轮询 `/api/v1/generate/image/tasks/{task_id}`,避免 HTTP 长连接占住生成池,也支持客户端重启后继续查结果。
|
||||
- **任务队列选择**:T-614 采用数据库任务表 + management command worker,不引入 Celery/RQ/Redis;后续只有在 DB worker 吞吐或运维能力不够时再评估专业队列。
|
||||
- **数据库:MySQL 8.4 LTS,cmhub 专用独立实例**:① 部署环境的 VPS 已装 MySQL 5.7 供其他服务用,但 5.7 跑不了 Django 5.2(需 ≥8.0.11)、已 EOL、且不支持 CHECK 约束,故**不复用**它;② 机器内存宽裕(`available` 7.4G),给 cmhub **单开一个 MySQL 8.4 LTS 实例**(独立端口/容器),与已有 5.7 完全隔离、互不影响;③ 选 8.4 LTS 取长维护窗口 + 完整 CHECK 约束(CHECK 需 MySQL ≥8.0.16 才真正生效);④ 强制 InnoDB + utf8mb4(5.7/老配置默认非 utf8mb4,prompt 的 emoji/生僻字会写失败);⑤ MySQL 默认隔离级别 REPEATABLE READ(不同于 PostgreSQL 的 READ COMMITTED),`select_for_update` 扣点仍安全,但计费实现按此语义验证;⑥ 开发环境同用 MySQL,不要用 SQLite——SQLite 会静默忽略 `FOR UPDATE`,并发扣点逻辑测不出来;⑦ 不在代码里写死只适配某一种库的 SQL。
|
||||
- **用户端用 Django 模板 SSR 单体,不引前端框架**:需求含终端用户自助(注册/充值/API Key/记录),选 Django 模板 + Bootstrap + allauth 与后端同工程单体部署,复用 Django auth/session,开发部署最快、最契合单机 MVP;代价是交互不如 SPA,可后续加 HTMX。T-501 已接入 django-allauth 65.18.0,使用 session 与 CSRF;T-605 起注册策略固定为 `ACCOUNT_EMAIL_VERIFICATION="none"`,免邮箱验证、注册即可用,邮箱仍必填且唯一;T-608 已把注册成功后的初始化改为经 `apps.billing` 发放 100 点试用点数并写 `signup_bonus` 流水,且显式配置 `ACCOUNT_SIGNUP_RATE_LIMIT` 做基础注册限流。T-502 已用 Django Form + Bootstrap 模板落地 `/apikeys`,生成 Key 后明文只显示一次,删除写为 `revoked`。T-503 已用只读 Django TemplateView 落地 dashboard 汇总、充值记录和点数记录。T-504 已用 Django Form + Bootstrap 模板落地 `/recharge`:页面 POST 创建 pending 充值订单,展示支付二维码票据,并用浏览器轮询 `/api/v1/recharge/status`,订单 paid 后刷新余额。T-505 已把 Bootstrap 5 CSS 与 qrcode.js vendoring 到 `apps/portal/static/portal/vendor/`,页面不再依赖 jsdelivr,充值/点数记录页改为 Django `Paginator` 分页。放弃 Vue/React 前后端分离(两套项目/部署,与单体 MVP 调性冲突)。用户模型:`User`(auth) 持登录态、`UserWallet` 持点数(扣点锁 wallet、与 auth 解耦)、`ApiKey`(User 1:N,哈希存储)。新注册用户一次性赠送 100 点,必须走计费层和点数流水。
|
||||
- **用户端用 Django 模板 SSR 单体,不引前端框架**:需求含终端用户自助(注册/充值/API Key/记录),选 Django 模板 + Bootstrap + allauth 与后端同工程单体部署,复用 Django auth/session,开发部署最快、最契合单机 MVP;代价是交互不如 SPA,可后续加 HTMX。T-501 已接入 django-allauth 65.18.0,使用 session 与 CSRF;T-605 起注册策略固定为 `ACCOUNT_EMAIL_VERIFICATION="none"`,免邮箱验证、注册即可用,邮箱仍必填且唯一;T-608 已把注册成功后的初始化改为经 `apps.billing` 发放 10 点试用点数并写 `signup_bonus` 流水,且显式配置 `ACCOUNT_SIGNUP_RATE_LIMIT` 做基础注册限流。T-502 已用 Django Form + Bootstrap 模板落地 `/apikeys`,生成 Key 后明文只显示一次,删除写为 `revoked`。T-503 已用只读 Django TemplateView 落地 dashboard 汇总、充值记录和点数记录。T-504 已用 Django Form + Bootstrap 模板落地 `/recharge`:页面 POST 创建 pending 充值订单,展示支付二维码票据,并用浏览器轮询 `/api/v1/recharge/status`,订单 paid 后刷新余额。T-505 已把 Bootstrap 5 CSS 与 qrcode.js vendoring 到 `apps/portal/static/portal/vendor/`,页面不再依赖 jsdelivr,充值/点数记录页改为 Django `Paginator` 分页。放弃 Vue/React 前后端分离(两套项目/部署,与单体 MVP 调性冲突)。用户模型:`User`(auth) 持登录态、`UserWallet` 持点数(扣点锁 wallet、与 auth 解耦)、`ApiKey`(User 1:N,哈希存储)。新注册用户一次性赠送 10 点,必须走计费层和点数流水。
|
||||
|
||||
## 三、构建与运行命令
|
||||
|
||||
|
||||
+11
-11
@@ -18,7 +18,7 @@
|
||||
|
||||
组件落位:
|
||||
|
||||
- **用户端层(Django 模板 SSR)**:公开首页、注册/登录(Django auth / allauth)、个人中心(余额/充值总额/充值记录/点数记录)、API Key 自助管理、发起扫码充值、模型目录与客户端下载入口。入口 `apps/portal/`,公开首页匿名可访问,其他自助页面用 session 鉴权。T-501/T-608 已落地 `/signup`、`/login`、`/logout` 与 `/dashboard`;注册成功后经计费层一次性发放 100 点试用点数,并写 `signup_bonus` 点数流水。T-502 已落地 `/apikeys`,用户可自助生成和删除(吊销)自己的 API Key,明文只显示一次,列表只显示 prefix。T-503/T-608 已扩展 `/dashboard` 并新增 `/records/recharge`、`/records/usage`,只读展示当前用户余额、充值订单、注册赠点与消费/退款流水。T-504 已落地 `/recharge`,用户可创建 pending 充值订单、查看二维码票据,并轮询订单状态;到账仍以服务端回调或主动查单入账后的本地订单状态为准。T-505 已把 Bootstrap/qrcode.js 改成本地 static 自托管,并把充值/点数记录页从固定切片改为分页。T-606 已把 `/` 改为公开首页,并新增 `DownloadRelease` 下载版本配置用于展示 Windows 客户端版本、下载地址、SHA256 与发布说明;T-607/T-609/T-617 已新增公开 JSON 版本检查接口给桌面端自动更新使用,并返回强制更新标记和安装包文件大小字节数。T-610 已在公开首页下载区增加导入模板下载入口,由后台 `ImportTemplate` 配置当前模板。
|
||||
- **用户端层(Django 模板 SSR)**:公开首页、注册/登录(Django auth / allauth)、个人中心(余额/充值总额/充值记录/点数记录)、API Key 自助管理、发起扫码充值、模型目录与客户端下载入口。入口 `apps/portal/`,公开首页匿名可访问,其他自助页面用 session 鉴权。T-501/T-608 已落地 `/signup`、`/login`、`/logout` 与 `/dashboard`;注册成功后经计费层一次性发放 10 点试用点数,并写 `signup_bonus` 点数流水。T-502 已落地 `/apikeys`,用户可自助生成和删除(吊销)自己的 API Key,明文只显示一次,列表只显示 prefix。T-503/T-608 已扩展 `/dashboard` 并新增 `/records/recharge`、`/records/usage`,只读展示当前用户余额、充值订单、注册赠点与消费/退款流水。T-504 已落地 `/recharge`,用户可创建 pending 充值订单、查看二维码票据,并轮询订单状态;到账仍以服务端回调或主动查单入账后的本地订单状态为准。T-505 已把 Bootstrap/qrcode.js 改成本地 static 自托管,并把充值/点数记录页从固定切片改为分页。T-606 已把 `/` 改为公开首页,并新增 `DownloadRelease` 下载版本配置用于展示 Windows 客户端版本、下载地址、SHA256 与发布说明;T-607/T-609/T-617 已新增公开 JSON 版本检查接口给桌面端自动更新使用,并返回强制更新标记和安装包文件大小字节数。T-610 已在公开首页下载区增加导入模板下载入口,由后台 `ImportTemplate` 配置当前模板。
|
||||
- **用户与账号层**:注册用户 `User`、点数钱包 `UserWallet`、`ApiKey`(一用户多把、哈希存储)。入口 `apps/users/`。
|
||||
- **API 层(DRF)**:对外生成接口、异步图片任务接口、余额查询、支付回调接收、扫码下单、公开版本检查接口。入口 `apps/api/`。生成/余额/模型目录这类对外业务 API **只认 API Key,不接受 Web session**;充值下单/状态查询属于用户端流程,走 Web session + CSRF;支付回调走平台验签;T-607/T-609/T-617 的客户端下载版本检查接口为公开只读例外,不需要 API Key,不读取用户、不扣点,`release.force_update` 仅表示当前发布版本是否强制升级,`release.size_bytes` 仅表示下载文件大小字节数。
|
||||
- **计费层**:点数计算、原子扣减(锁 `UserWallet` 行)、退点、充值入账、流水记账。入口 `apps/billing/`。
|
||||
@@ -66,7 +66,7 @@ T-619 多图理解继续复用上述 URL 下载器和逐跳 SSRF 校验,并额
|
||||
- 计费规则查询:按「操作类型 + 能力别名(+ 可选分辨率)」算出本次点数 N。**按别名定价,不按具体供应商 SKU 定价**,这样后台换底层模型时计费不变。
|
||||
- 点数原子扣减与退回:数据库事务 + 行锁,保证并发不超扣、不为负。
|
||||
- 充值入账:接收已验签的支付回调数据,按汇率换算点数,幂等入账,写流水。
|
||||
- 注册赠点:新用户注册成功后一次性发放 100 点试用点数,必须幂等、防并发重复,并写注册赠点流水。
|
||||
- 注册赠点:新用户注册成功后一次性发放 10 点试用点数,必须幂等、防并发重复,并写注册赠点流水。
|
||||
- 手工调点:运营后台只收集点数变动和原因,必须调用计费层 `adjust_wallet_points()`;服务在事务内锁 `UserWallet`,拒绝扣成负数,并写 `PointsLedger(change_type=adjust)`。
|
||||
- 点数流水记账:所有点数变动(充值/消费/调整/冲正/注册赠点)都生成一条流水。
|
||||
- 是点数余额的唯一写入方。
|
||||
@@ -259,7 +259,7 @@ CREATE TABLE user_wallet (
|
||||
CREATE TABLE signup_bonus_grant (
|
||||
id INTEGER PRIMARY KEY,
|
||||
user_id INTEGER UNIQUE NOT NULL REFERENCES "user"(id),
|
||||
points_granted BIGINT NOT NULL DEFAULT 100,
|
||||
points_granted BIGINT NOT NULL DEFAULT 10,
|
||||
created_at TEXT NOT NULL
|
||||
);
|
||||
|
||||
@@ -379,7 +379,7 @@ CREATE TABLE image_generation_task_input (
|
||||
- `payment_user_id`、`payment_txn_no` 为对账预留,字段先建。
|
||||
- `recharge_order.exchange_rate` 与 `points_granted` 在下单时写入,状态为 `pending` 时也必须有值;支付回调金额必须与订单金额一致,入账时不得按新的汇率重算。
|
||||
- `call_record.status` 状态机为 `pending -> success / failed`。异步任务临时性失败等待重试时仍保持 `pending`;最终上游失败退点后才变为 `failed`,退款流水通过 `points_ledger(change_type=refund, ref_call_id=call_record.id)` 关联,不单独增加 `refunded` 状态,避免调用结果与账务动作混在一个字段里。
|
||||
- T-201 已落地 `UserWallet` / `ApiKey` 于 `apps.users`,`PointsLedger` / `CallRecord` 于 `apps.billing`;T-203 已落地扣点/退点服务;T-304 已落地 `RechargeOrder`、回调幂等入账服务和 `points_ledger(ref_order_id, change_type)` 复合唯一约束,`ref_order_id` 当前仍为数值引用 `RechargeOrder.id`;T-305 已落地 `create_recharge_order()`,负责创建 pending 订单、锁定汇率/点数并回填二维码票据;T-401 已落地 `adjust_wallet_points()`,手工调整点数必须带原因并写 `adjust` 流水,后台钱包余额字段只读;T-608 已新增 `signup_bonus` 流水类型和 MySQL 兼容的注册赠点幂等标记 `SignupBonusGrant(user UNIQUE)`,并把 allauth 自助注册路径改为调用 `grant_signup_bonus()` 发放 100 点;T-614 已在 `apps.api` 落地 `ImageGenerationTask` 与 `api.0001_initial` 迁移,使用 MySQL 兼容的 `(api_key, idempotency_key_hash)` 唯一约束处理幂等键,不使用条件唯一约束;T-616 已在 `ImageGenerationTask` 增加 `next_attempt_at` 与 `(status, next_attempt_at)` 索引,用于 worker 避免立即反复抢占等待重试的任务;T-502 已把 API Key 自助管理接到 `ApiKey.create_for_user()`,删除动作写为 `revoked` 状态而非物理删除;T-503/T-608 已把个人中心和记录页接到只读查询,余额用 `get_balance_snapshot()`,充值总额按 paid `RechargeOrder` 汇总,充值 / 注册赠点 / 消费 / 退款按 `PointsLedger` 汇总;T-504 已把 `/recharge` 页面接到 `create_recharge_order()` 与 `/api/v1/recharge/status`。
|
||||
- T-201 已落地 `UserWallet` / `ApiKey` 于 `apps.users`,`PointsLedger` / `CallRecord` 于 `apps.billing`;T-203 已落地扣点/退点服务;T-304 已落地 `RechargeOrder`、回调幂等入账服务和 `points_ledger(ref_order_id, change_type)` 复合唯一约束,`ref_order_id` 当前仍为数值引用 `RechargeOrder.id`;T-305 已落地 `create_recharge_order()`,负责创建 pending 订单、锁定汇率/点数并回填二维码票据;T-401 已落地 `adjust_wallet_points()`,手工调整点数必须带原因并写 `adjust` 流水,后台钱包余额字段只读;T-608 已新增 `signup_bonus` 流水类型和 MySQL 兼容的注册赠点幂等标记 `SignupBonusGrant(user UNIQUE)`,并把 allauth 自助注册路径改为调用 `grant_signup_bonus()` 发放 10 点;T-614 已在 `apps.api` 落地 `ImageGenerationTask` 与 `api.0001_initial` 迁移,使用 MySQL 兼容的 `(api_key, idempotency_key_hash)` 唯一约束处理幂等键,不使用条件唯一约束;T-616 已在 `ImageGenerationTask` 增加 `next_attempt_at` 与 `(status, next_attempt_at)` 索引,用于 worker 避免立即反复抢占等待重试的任务;T-502 已把 API Key 自助管理接到 `ApiKey.create_for_user()`,删除动作写为 `revoked` 状态而非物理删除;T-503/T-608 已把个人中心和记录页接到只读查询,余额用 `get_balance_snapshot()`,充值总额按 paid `RechargeOrder` 汇总,充值 / 注册赠点 / 消费 / 退款按 `PointsLedger` 汇总;T-504 已把 `/recharge` 页面接到 `create_recharge_order()` 与 `/api/v1/recharge/status`。
|
||||
|
||||
## 四、计费时序(核心,务必照此实现)
|
||||
|
||||
@@ -464,22 +464,22 @@ CREATE TABLE image_generation_task_input (
|
||||
- **兜底**:回调可能丢失,须提供按 `order_no` 主动查单补入账;前端每 ~1s 轮询订单状态仅作 UX。
|
||||
- 仅商户密钥/证书为真实值待提供(微信 appid/mchid/apiv3_key/证书、支付宝 appid/公私钥/RSA2、notify_url 域名),协议已明确,可先 mock。
|
||||
|
||||
### 4.3 注册赠点(新用户 100 点试用额度)
|
||||
### 4.3 注册赠点(新用户 10 点试用额度)
|
||||
|
||||
```text
|
||||
1. allauth 注册成功并保存 User(邮箱必填且唯一,当前免邮箱验证)
|
||||
2. 调用 billing.grant_signup_bonus(user, points=100)
|
||||
2. 调用 billing.grant_signup_bonus(user, points=10)
|
||||
3. 事务:创建或锁定该用户的 UserWallet;创建 SignupBonusGrant(user UNIQUE) 幂等标记
|
||||
若标记已存在 → 直接返回已发放,不改余额、不写新流水
|
||||
否则 points_balance += 100
|
||||
写 points_ledger(signup_bonus, +100, balance_after, reason="new_user_registration")
|
||||
4. 注册后 dashboard / balance API 读取到包含 100 点赠点后的余额
|
||||
否则 points_balance += 10
|
||||
写 points_ledger(signup_bonus, +10, balance_after, reason="new_user_registration")
|
||||
4. 注册后 dashboard / balance API 读取到包含 10 点赠点后的余额
|
||||
```
|
||||
|
||||
要点:
|
||||
|
||||
- 注册赠点不是充值收入,但属于可消费点数,必须纳入点数账本和后台审计。
|
||||
- 不允许在 adapter / view / signal 中直接 `points_balance=100`;所有余额变动必须走计费层。
|
||||
- 不允许在 adapter / view / signal 中直接 `points_balance=10`;所有余额变动必须走计费层。
|
||||
- 幂等要有数据库级兜底。MySQL 不支持条件唯一约束,不要用 partial unique;也不要用 `PointsLedger(user, change_type)` 这类会误伤其他流水类型的全局唯一约束。推荐独立 `SignupBonusGrant(user UNIQUE)` 标记表。
|
||||
- 只对 T-608 上线后的新注册用户自动发放。历史用户是否补发不在本流程内,需单独审批、单独任务、单独批处理流水。
|
||||
- 由于当前注册免邮箱验证,注册送点会提高刷号动机。T-608 已显式配置 `ACCOUNT_SIGNUP_RATE_LIMIT`(默认 `20/m/ip`)并复用 allauth signup rate limit;图形验证码 / 人机验证可作为上线前风控项继续增强。
|
||||
@@ -502,7 +502,7 @@ CREATE TABLE image_generation_task_input (
|
||||
| 配置热生效 | 后台改模型/密钥后运行时仍用旧值 | 不在进程内长缓存;每次查库或保存时失效缓存 |
|
||||
| 配置变更审计 | 改密钥/模型/别名映射无痕 | `AiConfigAuditLog` 自动记录后台 create/update/delete;密钥只记录 empty/set 变化,日志只读 |
|
||||
| API Key 泄露 | 明文存库一旦泄露全泄 | Key **哈希存储**(sha256),明文只在创建时显示一次,库内存 `key_hash`+`key_prefix`,鉴权做哈希比对 |
|
||||
| 注册滥用 | 自助注册被批量刷以获取 100 点试用额度 | **免邮箱验证**(`ACCOUNT_EMAIL_VERIFICATION="none"`)下已显式配置 `ACCOUNT_SIGNUP_RATE_LIMIT` 基础注册限流;图形验证码 / 人机验证仍是上线前风控增强项;注册赠点走 `SignupBonusGrant(user UNIQUE)` 幂等标记 + `PointsLedger(signup_bonus)` 留痕,防重复发放 |
|
||||
| 注册滥用 | 自助注册被批量刷以获取 10 点试用额度 | **免邮箱验证**(`ACCOUNT_EMAIL_VERIFICATION="none"`)下已显式配置 `ACCOUNT_SIGNUP_RATE_LIMIT` 基础注册限流;图形验证码 / 人机验证仍是上线前风控增强项;注册赠点走 `SignupBonusGrant(user UNIQUE)` 幂等标记 + `PointsLedger(signup_bonus)` 留痕,防重复发放 |
|
||||
| Web/API 抢 worker | 图片同步长请求占满 worker、拖慢用户端页面 | 单体下按路径把 `/api/v1/generate/*` 与用户端页面**分流到不同 gunicorn/worker 池**(见 5.1) |
|
||||
| 充错账户 | 扫码订单未绑定发起用户 | 订单创建即绑定 `user`;回调按 `order_no` 定位订单→其 user 入账 |
|
||||
| SSRF / 任意 URL 下载 | `image_url` 让服务端请求调用方指定地址 | 仅允许公网 http/https;请求前解析 IP 并拒绝内网/回环/链路本地/保留地址;重定向逐跳校验;流式读取并限制大小 |
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
## 3. 范围纪律
|
||||
|
||||
- MVP 只做 `02-requirements.md` 中列为 P0 的功能。
|
||||
- V2 / V3 功能(异步队列、报表、复杂活动赠点 / 邀请奖励、自动退款对账)只记录,不实现。(自助注册/扫码充值/API Key 管理已纳入 MVP;新用户一次性注册送 100 点已拆为 T-608)
|
||||
- V2 / V3 功能(异步队列、报表、复杂活动赠点 / 邀请奖励、自动退款对账)只记录,不实现。(自助注册/扫码充值/API Key 管理已纳入 MVP;新用户一次性注册送 10 点已由 T-608 落地。)
|
||||
- 需求明确排除的非目标不得实现(自建收银台、多币种、分账等)。
|
||||
- 不为“将来可能用到”提前抽象。
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
- 技术栈以 `03-tech-stack.md` 为准;新增依赖前先说明理由,未经确认不引入重量级依赖(Celery、Redis 等)。
|
||||
- 模块职责以 `04-architecture.md` 为准,不跨层偷写逻辑。
|
||||
- **点数余额只能经 `apps/billing` 修改**:余额存 `UserWallet`(与 auth `User` 分离),扣点锁 wallet 行;API 层/Admin/用户端都不得直接写 `points_balance`。
|
||||
- **注册赠点也只能经 `apps/billing` 修改**:T-608 的 100 点试用额度必须走 `grant_signup_bonus()` 这类计费层服务,写 `PointsLedger(signup_bonus)`,不得在 allauth adapter、view 或 signal 里直接把钱包余额设为 100。
|
||||
- **注册赠点也只能经 `apps/billing` 修改**:当前 10 点试用额度必须走 `grant_signup_bonus()` 这类计费层服务,写 `PointsLedger(signup_bonus)`,不得在 allauth adapter、view 或 signal 里直接把钱包余额设为 10。
|
||||
- **API Key 哈希存储**(sha256),明文只在生成时返回一次;不存明文、任何页面不回显。
|
||||
- **对外 API 只挂 API Key 认证,不挂 SessionAuthentication**;用户端页面用 session + CSRF;自助注册**免邮箱验证**(`ACCOUNT_EMAIL_VERIFICATION="none"`,邮箱仍必填且唯一)、生成接口须限流。
|
||||
- **用户端与后台账号分离**:portal 与 `/admin/` 共用同一个 Django 会话(同一 `sessionid`),后台访问只多一道 `is_staff` 门槛。因此 **终端用户一律 `is_staff=False`**(普通用户登 portal 进不了后台,无泄露);**运营用专用 admin superuser 登录 `/admin/`,不要拿这个账号登 portal**——账号分离(方案 A)就是「解耦入口」的正解,不要为同账号双会话去拆 cookie/子域名。详见 `04-architecture.md`。
|
||||
@@ -91,7 +91,7 @@ python manage.py runserver
|
||||
- **回调防护与兜底**:支付回调端点必须 `@csrf_exempt`(网关调用无 CSRF token);回调可能丢失,须提供按 `order_no` 主动查单兜底,避免已付款却一直 pending。
|
||||
- **失败必退**:调用上游失败时,已预扣的点数必须冲正退回。
|
||||
- **全程留痕**:每笔点数变动写 `points_ledger`,每次调用写 `call_record`,运营手工调整必须填原因。
|
||||
- **注册赠点幂等**:新用户 100 点试用额度必须有数据库级幂等保护,同一用户无论注册回调、重试或并发触发多少次,都最多发放一次;不得用 MySQL 不支持的条件唯一约束。
|
||||
- **注册赠点幂等**:新用户 10 点试用额度必须有数据库级幂等保护,同一用户无论注册回调、重试或并发触发多少次,都最多发放一次;不得用 MySQL 不支持的条件唯一约束。
|
||||
- **敏感信息**:密钥/凭证只用环境变量或后台配置,不写真实值进代码与文档。
|
||||
- 资金相关改动必须有对应测试(并发扣点、重复回调、上游失败退点至少各一条)。
|
||||
- 不绕过支付系统的鉴权、验签或风控。
|
||||
|
||||
+2
-1
@@ -86,7 +86,7 @@
|
||||
| T-604 | 中文敏感词本地过滤(本地 keyword provider) | T-302, T-401 | 按 [`moderation.md`](moderation.md) 实施。**范围收紧**:T-604 只做输入 prompt 的本地敏感词快筛,不做云内容安全、不做输出审核、不做图片审核。**关键时序**:serializer 后先审 prompt,命中即 `400 content_blocked`;不得先下载 `image_url`,不得预扣点,不写 `CallRecord` / `PointsLedger`,不调上游。**核心实现**:新增 `apps.moderation`、`SensitiveWord` 模型/admin/迁移、keyword provider、归一化管线、Aho-Corasick matcher;`ahocorapy` 作为候选依赖,编码前必须验证 PyPI 可用性和 API 形状。**缓存**:matcher 进程内缓存,词库变更用共享 cache 版本号失效,不能只靠 `post_save` signal;生产依赖共享 cache。**配置**:`MODERATION_ENABLED=false` 默认 no-op;启用时 `MODERATION_PROVIDER=keyword`;MVP `SensitiveWord.action` 只支持 `block`。**验收**:`check`/`test` 全绿,覆盖 no-op、命中拦截且不扣点/不建记录/不调上游/不下载图片、归一化防绕过、词库变更后 matcher 重建;真实词库数据不进仓库,`__pycache__` 不进 Git | DONE |
|
||||
| T-606 | 公开首页 + 客户端下载入口 | T-501 | 给网站补「前门」并提供桌面端下载。**路由改造**:`/` 从「重定向到 `/dashboard`」改为**公开首页**(匿名可访问、不跳登录);已登录用户显示「进入控制台」,匿名显示「注册/登录 + 下载客户端」。**首页内容**(SSR 模板):项目一句话介绍(生成标题/图片、按点数计费)+ 三步上手(注册→充值→建 API Key→桌面端填 Key)+ 下载入口 + 文档链接。**`DownloadRelease` 模型**:`platform`(如 windows)、`version`、`file`(FileField,**前期存 `MEDIA_ROOT`、服务器托管**) + `external_url`(URLField 可选,**后续切对象存储/CDN 用,有则优先**)、`sha256`、`is_current`(每平台仅一个当前版本)、`release_notes`、时间戳;admin 可上传安装包并标记当前版本;迁移。**下载区块**:展示当前 release 的版本、下载按钮、**SHA256 校验值**、可选 release notes;无 current release 时优雅提示「暂未发布」。**托管策略**:**前期安装包放本服务器**(生产由 **Nginx 直接服务 media/下载文件、不走 Django**,与 T-403 static/media serving 一致,大文件不占 gunicorn worker);`external_url` 预留,后续切对象存储只改后台链接不改代码。**安全**:下载走 HTTPS,页面展示 SHA256 供校验;**代码签名**作为决策登记——未签名 Windows 安装包会被 SmartScreen 拦「未知发布者」、macOS 被 Gatekeeper 拦,首页先给「如何忽略警告」说明,正式签名后续补(挂 Backlog / deployment)。**含测试**:`/` 匿名 200 不跳登录、下载区展示当前 release、无 current release 优雅处理、已登录用户显示「进入控制台」。**视觉原型(已定 v1)**:按 `prototypes/cmhub-homepage-v1.svg` 落地——「生成台」方向:靛蓝=生成 / 琥珀=点数;Hero 为「商品图 + 一句话 → 吸睛标题 + 生成主图 + 点数计量」转化图;四步上手 01–04、两张能力卡、深色计费 band、下载区(版本/SHA256/未签名提示);配色、间距、结构照此原型转成 Django 模板(Bootstrap + 本地 static)。**视觉一致性(brand token)**:按 [`brand.md`](brand.md) 抽出共享 CSS 变量(如 `apps/portal/static/portal/brand.css`),**首页与现有 portal 页面(dashboard/记录/充值/API Key)一起套用同一套 token**(把配色/字体变量灌进现有 Bootstrap,各页只引用变量不散写 hex),确保落地页与登录后控制台风格一致——**不是只做漂亮首页**。验收 `check`/`test`/`init` 全绿并在 `../progress.md` 留证据 | DONE |
|
||||
| T-607 | 桌面端最新版本检查接口 | T-606 | 给桌面端自动检查更新提供只读 JSON 合约。**新增路由**:`GET /api/v1/client/releases/latest?platform=windows`,公开匿名可访问,**不需要 API Key、不读取用户、不扣点、不占用生成接口限流**;只返回发布元数据,不返回本地文件系统路径、后台 ID、内部状态或任何用户数据。**请求参数**:`platform` 支持 `windows` / `macos` / `linux`,缺省按 `windows`;非法平台返回 `400 bad_request`。**响应结构**:有当前版本时返回 `{platform, release:{version, download_url, sha256, release_notes, published_at}}`;无当前版本或当前版本没有下载地址时返回 `{platform, release:null, message:"暂未发布"}` 且 HTTP 200,方便客户端安静处理。**数据来源**:复用 `DownloadRelease`,只查 `platform + is_current=True`;`download_url` 继续按 `external_url` 优先,否则由 `file.url` 生成绝对 HTTPS URL;`published_at` 可先使用 `updated_at`。**缓存与安全**:可加短 TTL 公共缓存(如 60 秒);生产下载仍走 HTTPS + SHA256 校验;不得把 `MEDIA_ROOT` 或服务器路径暴露给客户端。**含测试**:匿名无 Key 可访问;当前 release 返回完整结构和绝对下载 URL;无 current release 返回 `release:null`;非法 platform 返回 400;`external_url` 优先于 `file`;响应不含本地路径、模型/密钥/用户字段;`check`/目标测试通过并在 `../progress.md` 留证据 | DONE |
|
||||
| T-608 | 新用户注册赠送 100 点试用点数 | T-501, T-203, T-401 | 把 2026-07-08 的产品口径落地为账本安全实现。**业务口径**:只对 T-608 上线后的新注册用户自动发放 100 点;历史用户是否补发不在本任务内,需单独审批和批处理任务。**数据与服务**:新增 `PointsLedger.ChangeType.SIGNUP_BONUS`(展示为注册赠点)和 MySQL 兼容的数据库级幂等兜底 `SignupBonusGrant(user UNIQUE)`,不要用 partial unique / 条件唯一约束;新增 `apps.billing.services.grant_signup_bonus(user, points=100)`,在事务内锁/创建钱包、发放点数、写 `PointsLedger(signup_bonus,+100,balance_after,reason)`,重复调用或并发触发不得重复发放。**接入点**:allauth adapter 注册成功后调用 billing 服务,不得在 portal 直接写 `points_balance`;失败要清晰暴露并保持注册 / 账务一致性。**页面与文案**:公开首页、注册页、dashboard/记录页等用户端文案同步「注册送 100 点」;点数记录页能展示注册赠点正向流水;admin 可检索该流水和注册赠点记录。**防刷**:免邮箱验证策略下显式配置 `ACCOUNT_SIGNUP_RATE_LIMIT`(默认 `20/m/ip`),由 allauth signup rate limit 执行;图形验证码 / 人机验证仍作为上线前风控增强项。**测试**:注册后余额为 100 且有一条 `signup_bonus` 流水;重复调用服务不重复加点;并发触发不重复发放;现有用户不会自动补发;dashboard / 点数记录显示一致;`check`/迁移/目标测试通过并在 `../progress.md` 留证据 | DONE |
|
||||
| T-608 | 新用户注册赠送试用点数(当前 10 点) | T-501, T-203, T-401 | 已完成:仅对 T-608 上线后的新注册用户,经 `apps.billing.services.grant_signup_bonus(user, points=10)` 一次性发放 10 点;历史用户不补发。服务在事务内锁/创建钱包、写 `SignupBonusGrant(user UNIQUE)` 幂等记录和 `PointsLedger(signup_bonus,+10,balance_after,reason)`,重复调用或并发触发不重复发放;allauth adapter 只调用 billing 服务,不直接改余额。公开首页、注册页、dashboard/点数记录页展示当前 10 点,admin 可检索记录;免邮箱验证下由 `ACCOUNT_SIGNUP_RATE_LIMIT=20/m/ip` 限制注册频率。已覆盖注册余额/流水、重复调用、并发幂等、页面文案和后台检索;当前默认值由 `billing.0009_signup_bonus_default_ten` 与服务默认参数共同保证。 | DONE |
|
||||
| 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 |
|
||||
@@ -123,6 +123,7 @@
|
||||
## 待办池(Backlog)
|
||||
|
||||
- ~~异步生成(任务队列 + 轮询/回调)~~ → 已立项 **T-612~T-615**(生图异步任务化:先硬截止 + 长请求池校准止血,再抽共享 core,最后新增 `/tasks` 提交+轮询接口与旧同步接口共存、旧路遥测后弃用)。
|
||||
- **T-621 注册赠点运营后台配置**:将当前固定 10 点改为 admin 可管理的单例策略,包含策略审计、停用时的 0 点决定记录及不追溯历史用户。该项涉及账本与后台配置,现移入 Backlog,暂不实施。
|
||||
- 按账号授权可用别名(`account_alias_permission`),防止调用未授权/昂贵模型。
|
||||
- 别名按比例分流到多个模型(灰度 / A/B / 故障转移);供应商 A 故障自动切 B。
|
||||
- 异步生图提交时模型配置快照:当前 worker 会复跑 `prepare_generation()`,重新审核 prompt、解析别名 / Provider / 定价,但账务使用已预扣 `CallRecord.points_cost`。短队列下可接受;若后续队列积压或后台频繁切换别名,应在 submit 阶段快照 `ai_model_id` / `model_used` / 必要 Provider 配置,worker 使用提交时模型执行,同时保留 prompt 复审。
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@
|
||||
- [Phase 1 AI 层审核](phase-1-review.md):T-101~104 代码审核结论与修补清单(P1/P2/P3),对应任务 T-105;重点提示图片同步风险未退与 `parameters` 越权计费隐患。
|
||||
- [Phase 2 计费核心审核](phase-2-review.md):T-201~203 代码审核结论(资金安全逐条核对)与加固清单(**零 P1**,P2/P3),对应任务 T-204。
|
||||
- [Phase 3 对外 API 与充值审核](phase-3-review.md):T-301~305 代码审核结论(鉴权/回调/幂等/入账逐条核对)与优化建议,对应任务 T-306;**P1 提示 `image_url` SSRF 上线前必修**。
|
||||
- [Phase 4 用户端审核](phase-4-review.md):T-501~504 代码审核结论(按当时口径核对注册不送点/越权/CSRF/明文只显一次/到账以回调为权威;2026-07-08 新需求已由 T-608 改为注册送 100 点)与优化建议(**零 P1**,P2/P3),对应任务 T-505。
|
||||
- [Phase 4 用户端审核](phase-4-review.md):T-501~504 代码审核结论(按当时口径核对注册不送点/越权/CSRF/明文只显一次/到账以回调为权威;2026-07-08 新需求曾由 T-608 改为注册送 100 点,当前额度为 10 点)与优化建议(**零 P1**,P2/P3),对应任务 T-505。
|
||||
- [MVP 完整验收报告](mvp-acceptance.md):T-402 对 `02-requirements.md` P0 验收项的逐项结论、测试证据和已知限制。
|
||||
- [部署 / 运行文档](deployment.md):T-403 生产部署步骤、宝塔 / Nginx / Gunicorn 配置、静态文件、共享 cache、图片超时与上线检查。
|
||||
- [API 合约](api.md):对外接口、支付回调、AI 调用模块合约、错误码。
|
||||
|
||||
+4
-4
@@ -15,7 +15,7 @@
|
||||
- 例外:客户端下载版本检查接口只返回公开发布元数据,设计为匿名只读接口,不需要 API Key,不读取用户、不扣点。
|
||||
- 图片生成提供两条并存路径:旧 `POST /api/v1/generate/image` 为同步接口,可能耗时较长;T-614 起新增异步任务接口 `POST /api/v1/generate/image/tasks` + `GET /api/v1/generate/image/tasks/{task_id}`,新版桌面端优先使用异步提交 / 轮询,旧客户端继续走同步接口。
|
||||
- 用户端注册使用同一个 `User` 账本主体;注册邮箱**必填且唯一**(`ACCOUNT_EMAIL_VERIFICATION="none"`,**不做邮箱验证**、注册即可用),唯一约束避免同邮箱对应多个点数账户。
|
||||
- T-608 起新用户注册成功一次性赠送 **100 点**试用点数;赠点必须经计费层写入钱包和 `PointsLedger(change_type=signup_bonus)`,不得直接改余额字段。历史用户是否补发不属于默认注册流程。
|
||||
- T-608 起新用户注册成功一次性赠送 **10 点**试用点数;赠点必须经计费层写入钱包和 `PointsLedger(change_type=signup_bonus)`,不得直接改余额字段。历史用户是否补发不属于默认注册流程。
|
||||
- API Key 库内只存 `key_hash`(SHA-256)与 `key_prefix`,明文只在创建时返回一次,不在 admin、日志或调用记录中回显。
|
||||
- 每次生成调用写 `CallRecord`;只允许保存 `result_ref` / `result_summary` 这类引用或摘要,不保存 provider `raw`、base64 图片或敏感上游字段。
|
||||
|
||||
@@ -41,7 +41,7 @@ T-306 已实现对外 API 安全加固:`image_url` 下载只允许 `http` / `h
|
||||
|
||||
T-604 目标口径:生成接口在 serializer 基础校验后先执行 prompt 本地敏感词检查;命中返回 `400 content_blocked`,且不得下载 `image_url`、不得预扣点、不得写 `CallRecord` / `PointsLedger`、不得调用上游。T-604 不启用输出审核和图片审核;详细规则见 [`moderation.md`](moderation.md)。
|
||||
|
||||
T-501/T-608 已实现用户端注册 / 登录基线:`/signup` `/login` `/logout` 走 django-allauth + Django session + CSRF;**免邮箱验证、注册即可用(`ACCOUNT_EMAIL_VERIFICATION="none"`,邮箱仍必填且唯一)**。注册成功后 allauth adapter 调用 `grant_signup_bonus()` 一次性发放 100 点注册试用额度,并创建 `signup_bonus` 流水;注册限流由 allauth signup rate limit 执行,项目显式配置 `ACCOUNT_SIGNUP_RATE_LIMIT`(默认 `20/m/ip`)。对外 API 仍只认 API Key,不接受 Web session。(免验证策略见 T-605 与 2026-07-06 决策)
|
||||
T-501/T-608 已实现用户端注册 / 登录基线:`/signup` `/login` `/logout` 走 django-allauth + Django session + CSRF;**免邮箱验证、注册即可用(`ACCOUNT_EMAIL_VERIFICATION="none"`,邮箱仍必填且唯一)**。注册成功后 allauth adapter 调用 `grant_signup_bonus()` 一次性发放 10 点注册试用额度,并创建 `signup_bonus` 流水;注册限流由 allauth signup rate limit 执行,项目显式配置 `ACCOUNT_SIGNUP_RATE_LIMIT`(默认 `20/m/ip`)。对外 API 仍只认 API Key,不接受 Web session。(免验证策略见 T-605 与 2026-07-06 决策)
|
||||
|
||||
T-502 已实现用户端 API Key 自助管理基线:`/apikeys` 走 Django session + CSRF;登录用户可生成和删除自己的 Key,生成后的明文只在重定向后的首个页面显示一次,库内只保存 `key_hash` 与 `key_prefix`。用户端“删除”落库为 `revoked`,保留历史记录关联;吊销后的 Key 调用生成 / 余额接口返回 `403 account_disabled`,缺失、无效或不存在的 Key 仍返回 `401 unauthorized`。
|
||||
|
||||
@@ -475,7 +475,7 @@ calculate_points_cost(operation_type: str, alias: str, resolution: str | None =
|
||||
quote_recharge_points(amount, currency: str = "CNY", at=None) -> RechargeQuote
|
||||
calculate_points_granted(amount, currency: str = "CNY", at=None) -> int
|
||||
create_recharge_order(..., user, amount, pay_method: str, currency: str = "CNY") -> RechargeOrder
|
||||
grant_signup_bonus(user, points: int = 100) -> SignupBonusGrantResult
|
||||
grant_signup_bonus(user, points: int = 10) -> SignupBonusGrantResult
|
||||
precharge_call(..., user, points_cost: int, operation_type: str, alias: str, ...) -> CallCharge
|
||||
mark_call_success(call_record: CallRecord, ...) -> CallRecord
|
||||
refund_call_points(call_record: CallRecord, ...) -> RefundResult
|
||||
@@ -490,7 +490,7 @@ query_and_apply_recharge_payment(order_no: str, query_func) -> RechargeResult
|
||||
- 缺计费规则抛 `NoPricingRuleError(code="no_pricing_rule")`,API 层应翻译为上方同名错误码。
|
||||
- `ExchangeRate` 按 `currency + effective_from` 取当前 active 汇率;充值下单时应锁定当时的 `exchange_rate` / `points_granted` 到订单,回调入账不得按新汇率重算。
|
||||
- 金额换点数采用 `floor(amount * points_per_unit)`,点数为整数。
|
||||
- `grant_signup_bonus()` 是注册赠点唯一入口:只对当前用户首次成功发放 100 点,锁定 / 创建 `UserWallet`,写 `PointsLedger(change_type=signup_bonus, points_delta=+100)`,并用 MySQL 兼容的唯一幂等标记防重复发放。
|
||||
- `grant_signup_bonus()` 是注册赠点唯一入口:只对当前用户首次成功发放 10 点,锁定 / 创建 `UserWallet`,写 `PointsLedger(change_type=signup_bonus, points_delta=+10)`,并用 MySQL 兼容的唯一幂等标记防重复发放。
|
||||
- `create_recharge_order()` 创建 `RechargeOrder(status=pending)` 并绑定发起用户;写入订单创建时的金额、币种、汇率、预计点数,再调用支付网关下单取二维码票据并回填 `code_url` / `expires_at`;支付平台下单失败时订单标记 `failed`。
|
||||
- `precharge_call()` 使用事务 + `select_for_update()` 锁 `UserWallet` 行;余额不足抛 `InsufficientPointsError(code="insufficient_points")`,不创建 `CallRecord`、不写 `PointsLedger`、不调上游。
|
||||
- 预扣成功后写 `CallRecord(status=pending)` 与 `PointsLedger(change_type=consume, points_delta=-N)`;上游成功只更新调用记录,余额不再变化。
|
||||
|
||||
+1
-1
@@ -79,7 +79,7 @@ cmhub 有双重身份——**AI 生成** + **按点数计费**。视觉主线
|
||||
## 5. 语气(Voice)
|
||||
|
||||
- **说人话**:按用户看得懂的说,不用系统术语(说「管理 API Key」,不说「凭证配置」)。
|
||||
- **诚实**:如实说「注册送 100 点试用点数」「失败自动退点」「首次安装点『仍要运行』」——不粉饰。
|
||||
- **诚实**:如实说「注册送 10 点试用点数」「失败自动退点」「首次安装点『仍要运行』」——不粉饰。
|
||||
- **动词优先、句子式大小写**:按钮说清「做完会发生什么」(「下载 .exe」而非「获取」)。
|
||||
- **同一动作全程同名**:按钮「充值」→ 结果提示也用「充值」。
|
||||
|
||||
|
||||
+10
-10
File diff suppressed because one or more lines are too long
+1
-1
@@ -148,7 +148,7 @@ python3.12 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key
|
||||
注意:
|
||||
|
||||
- `AI_KEY_ENCRYPTION_KEY` 生产不可随意更换;更换会导致已加密的 `AiModel.api_key_encrypted` 无法解密。
|
||||
- 当前注册策略为免邮箱验证,注册登录不依赖邮件服务;T-608 后注册成功会赠送 100 点,生产必须保留或收紧 `ACCOUNT_SIGNUP_RATE_LIMIT`,并使用共享 Django cache 承载限流计数;若后续启用密码找回、通知或恢复邮箱验证,再把 `DJANGO_EMAIL_BACKEND` 改为真实 SMTP / 邮件服务并配置 `DJANGO_DEFAULT_FROM_EMAIL`。
|
||||
- 当前注册策略为免邮箱验证,注册登录不依赖邮件服务;新注册用户成功后会赠送 10 点,生产必须保留或收紧 `ACCOUNT_SIGNUP_RATE_LIMIT`,并使用共享 Django cache 承载限流计数;若后续启用密码找回、通知或恢复邮箱验证,再把 `DJANGO_EMAIL_BACKEND` 改为真实 SMTP / 邮件服务并配置 `DJANGO_DEFAULT_FROM_EMAIL`。
|
||||
- `PAYMENT_CALLBACK_MODE=sdk` 必须配齐微信 / 支付宝商户配置;未配齐时先保持 `mock`。
|
||||
- 宝塔 / Nginx 已强制 HTTPS 时,`DJANGO_SECURE_SSL_REDIRECT=false` 即可;全站 HTTPS 稳定后再把 `DJANGO_SECURE_HSTS_SECONDS` 调大,避免 HSTS 误锁域名。
|
||||
- T-614 异步生图 worker 没有 request 对象,生产必须配置 `MEDIA_PUBLIC_BASE_URL` 或 `PUBLIC_BASE_URL` 为公开 HTTPS 域名,否则异步轮询成功时可能返回相对 `/media/...` URL。
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
| P0 验收项 | 结论 | 主要证据 |
|
||||
| --- | --- | --- |
|
||||
| 用户注册 / 登录 | PASS | T-402 历史验收口径为 `apps.portal` 注册创建 0 点钱包且不写赠点流水;T-605 后注册为免邮箱验证、注册后可直接登录,邮箱仍必填且唯一。T-608 已按新需求改为注册赠送 100 点并写 `signup_bonus` 流水,且通过 `SignupBonusGrant(user UNIQUE)` 防重复发放 |
|
||||
| 用户注册 / 登录 | PASS | T-402 历史验收口径为 `apps.portal` 注册创建 0 点钱包且不写赠点流水;T-605 后注册为免邮箱验证、注册后可直接登录,邮箱仍必填且唯一。T-608 已按新需求改为注册赠点并写 `signup_bonus` 流水,且通过 `SignupBonusGrant(user UNIQUE)` 防重复发放;当前额度为 10 点。 |
|
||||
| API Key 自助管理 | PASS | `apps.portal`:Key 明文只显示一次、列表仅显示 prefix、删除为吊销、不可删除他人 Key;`apps.api`:缺失/无效 Key 为 401,吊销 Key 为 403 |
|
||||
| 扫码充值 | PASS | `apps.portal` / `apps.api`:创建 pending 订单不直接加点、不写流水;二维码票据展示;状态轮询只允许本人订单;主动查单可补入账 |
|
||||
| 个人中心 / 记录 | PASS | `apps.portal`:余额、充值总额、获得点数、注册赠点/消费/退款记录与实际订单/流水一致;充值记录和点数记录分页且仅见本人 |
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
## 已知限制
|
||||
|
||||
- 一次单条 `py -3.12 manage.py test --noinput --keepdb --verbosity 2` 发现 119 tests,已运行 98 tests 后远程 MySQL 在 `apps.portal.tests.PortalAccountFlowTests.setUpClass` 阶段连接重置;已通过用例无断言失败。随后按 `portal` / `ai` / `api` / `billing+users` 四组拆分,合计同一 119 条测试全部通过。
|
||||
- 一次单条 `py -3.12 manage.py test --noinput --keepdb --verbosity 2` 发现 119 tests,已运行 98 tests 后远程 MySQL 在 `apps.portal.tests.PortalAccountFlow-ests.setUpClass` 阶段连接重置;已通过用例无断言失败。随后按 `portal` / `ai` / `api` / `billing+users` 四组拆分,合计同一 119 条测试全部通过。
|
||||
- 测试阶段仍有 allauth `account.EmailAddress` 条件唯一约束在 MySQL 上不可创建的 `models.W036` 警告;本项目账号邮箱唯一性由 `user.email` 唯一约束承担。
|
||||
- 真实微信/支付宝商户密钥、证书、生产 SDK 依赖和公网回调地址仍待提供;MVP 验收使用 mock 支付路径。
|
||||
- 真实 AI 上游调用和图片同步真实耗时仍需配置 `AI_KEY_ENCRYPTION_KEY`、导入真实 AiModel/ModelAlias 后执行;部署超时口径已登记到 T-403。
|
||||
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
**第一版做**:
|
||||
|
||||
- 用户端:自助注册登录、注册成功赠送 100 点试用点数、扫码充值、查看点数/充值/消费记录、自助生成与删除 API Key。
|
||||
- 用户端:自助注册登录、注册成功赠送 10 点试用点数、扫码充值、查看点数/充值/消费记录、自助生成与删除 API Key。
|
||||
- 生成标题、生成图片接口;图片保留旧同步接口,并新增异步提交 / 轮询接口给新版客户端。
|
||||
- 点数计费、扣点、余额查询。
|
||||
- 充值到账(对接已有支付系统)。
|
||||
@@ -69,7 +69,7 @@
|
||||
|
||||
**第一版先不做**(留待后续迭代):
|
||||
|
||||
- 用量统计报表、自动退款对账、复杂活动赠点 / 邀请奖励等(自助注册/扫码充值/API Key 管理、注册送 100 点与生图异步提交 / 轮询已纳入当前口径)。
|
||||
- 用量统计报表、自动退款对账、复杂活动赠点 / 邀请奖励等(自助注册/扫码充值/API Key 管理、注册送 10 点与生图异步提交 / 轮询已纳入当前口径)。
|
||||
|
||||
> 取舍原则:先把「充值 → 调用 → 计费 → 记录」最小闭环做稳,再扩展。
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
- Phase 5 已完成 T-401:运营后台可管理/检索用户、钱包、API Key(脱敏)、计费规则、汇率、充值订单、点数流水和调用记录;手工调点必须填写原因,并经计费层锁钱包、写 `adjust` 流水。
|
||||
- Phase 5 已完成 T-402:MVP P0 验收通过,注册/充值/API Key/调用/余额/记录/后台/别名映射均有测试证据,详见 `mvp-acceptance.md`。
|
||||
- Phase 5 已完成 T-403:已补部署 / 运行文档,明确宝塔/Nginx/Gunicorn、生产静态与媒体文件、共享缓存限流、图片同步超时、真实商户配置和上线检查;当前免邮箱验证,邮件服务仅作为后续密码找回/通知等邮件能力配置项,详见 `deployment.md`。
|
||||
- Phase 6 已完成 T-601 可用别名发现、T-602 后台表名/分组中文化、T-603 字段级中文化、T-604 中文敏感词本地过滤、T-605 免邮箱验证策略落地、T-606 公开首页 + 客户端下载入口、T-607 桌面端最新版本检查接口、T-608 新用户注册赠送 100 点试用点数、T-609 桌面端版本强制更新标记、T-610 首页导入模板下载入口、T-611 用户端品牌名统一、T-612~T-615 生图异步化与旧同步接口遥测;线上真实标题生成已恢复并验证扣点。
|
||||
- Phase 6 已完成 T-601 可用别名发现、T-602 后台表名/分组中文化、T-603 字段级中文化、T-604 中文敏感词本地过滤、T-605 免邮箱验证策略落地、T-606 公开首页 + 客户端下载入口、T-607 桌面端最新版本检查接口、T-608 新用户注册赠送试用点数(当前 10 点)、T-609 桌面端版本强制更新标记、T-610 首页导入模板下载入口、T-611 用户端品牌名统一、T-612~T-615 生图异步化与旧同步接口遥测;线上真实标题生成已恢复并验证扣点。
|
||||
- 下一步可继续补跑真实支付回调到账闭环、配置并发布客户端下载包,并在生产日志中观察旧同步生图接口用量与弃用条件。
|
||||
|
||||
---
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
|
||||
## 第一版范围
|
||||
|
||||
做:自助用户端(注册注册送 100 点/扫码充值/API Key 管理/记录)、两个生成接口、点数计费、充值到账、调用记录、运营后台。
|
||||
先不做:报表、复杂活动赠点 / 邀请奖励、自动退款对账(后续迭代;自助注册/充值/API Key、注册送 100 点和生图异步提交 / 轮询已在当前版本)。
|
||||
做:自助用户端(注册注册送 10 点/扫码充值/API Key 管理/记录)、两个生成接口、点数计费、充值到账、调用记录、运营后台。
|
||||
先不做:报表、复杂活动赠点 / 邀请奖励、自动退款对账(后续迭代;自助注册/充值/API Key、注册送 10 点和生图异步提交 / 轮询已在当前版本)。
|
||||
|
||||
## 需要拍板
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
## 进度
|
||||
|
||||
M1 骨架已完成;M2 已通过录制生成 smoke 验证 AI 调用链路;M3 计费、对外 API、充值闭环与上线前安全加固已完成到 T-306;M4 用户端已完成注册 / 登录、API Key 管理、个人中心 / 记录页、充值页和审核优化;M5 已完成 T-401 运营后台完善、T-402 MVP 完整验收与 T-403 部署 / 运行文档;M7 注册试用额度已完成,注册后经账本发放 100 点并留流水;M11 生图异步任务化已完成到 T-615,旧同步接口继续兼容并写结构化用量日志。下一步是在 VPS 上按部署文档接真实支付回调闭环、发布客户端,并观察旧同步生图用量。里程碑:M1 骨架可跑 · M2 跑通生成 · M3 计费充值闭环 · M4 用户端可用 · M5 验收上线 · M7 试用额度安全落地 · M11 生图异步任务化。
|
||||
M1 骨架已完成;M2 已通过录制生成 smoke 验证 AI 调用链路;M3 计费、对外 API、充值闭环与上线前安全加固已完成到 T-306;M4 用户端已完成注册 / 登录、API Key 管理、个人中心 / 记录页、充值页和审核优化;M5 已完成 T-401 运营后台完善、T-402 MVP 完整验收与 T-403 部署 / 运行文档;M7 注册试用额度已完成,注册后经账本发放 10 点并留流水;M11 生图异步任务化已完成到 T-615,旧同步接口继续兼容并写结构化用量日志。下一步是在 VPS 上按部署文档接真实支付回调闭环、发布客户端,并观察旧同步生图用量。里程碑:M1 骨架可跑 · M2 跑通生成 · M3 计费充值闭环 · M4 用户端可用 · M5 验收上线 · M7 试用额度安全落地 · M11 生图异步任务化。
|
||||
|
||||
---
|
||||
*详见 `project-brief.md`(完整介绍)。*
|
||||
|
||||
+2
-2
@@ -8,7 +8,7 @@
|
||||
| 路由 | 方法 | 职责 | 鉴权 |
|
||||
| --- | --- | --- | --- |
|
||||
| `/` | GET | 公开首页:项目介绍、四步上手、客户端下载入口、导入模板下载入口、API/控制台入口 | 公开 |
|
||||
| `/signup` `/login` `/logout` | GET/POST | 自助注册(**免邮箱验证、注册即可用**;注册成功一次性赠送 100 点试用点数)/登录/登出(Django auth/allauth) | 公开 |
|
||||
| `/signup` `/login` `/logout` | GET/POST | 自助注册(**免邮箱验证、注册即可用**;注册成功一次性赠送 10 点试用点数)/登录/登出(Django auth/allauth) | 公开 |
|
||||
| `/dashboard` | GET | 个人中心:剩余点数、充值总额、快捷入口 | session |
|
||||
| `/recharge` | GET/POST | 发起充值:选金额→展示支付二维码→轮询到账 | session |
|
||||
| `/records/recharge` | GET | 充值记录 | session |
|
||||
@@ -16,7 +16,7 @@
|
||||
| `/apikeys` | GET/POST | API Key 管理:列表 / 生成 / 删除(删除即吊销,明文只显示一次) | session |
|
||||
| `/models` | GET | 可用模型:只读展示可调用能力别名、能力、是否需要原图和点数单价 | session |
|
||||
|
||||
T-501/T-608 已落地 `/signup`、`/login`、`/logout` 与 `/dashboard`:注册成功后经计费层一次性发放 100 点试用点数并写 `signup_bonus` 流水,注册限流由 allauth signup rate limit 执行。T-502 已落地 `/apikeys`:登录用户只能管理自己的 Key,生成后明文只显示一次,列表只显示 prefix,删除为吊销 `revoked`。T-503/T-505/T-608 已扩展 `/dashboard` 为个人中心汇总,并落地 `/records/recharge` 与 `/records/usage`:充值总额按已支付订单统计,注册赠点 / 入账 / 消费 / 退款点数按 `PointsLedger` 统计,记录页只查询当前登录用户数据并分页展示。T-504/T-505 已落地 `/recharge`:登录用户可选择金额和支付方式创建 pending 充值订单,页面用本地 static 自托管 qrcode.js 展示二维码票据并轮询 `/api/v1/recharge/status`,到账后刷新余额。
|
||||
T-501/T-608 已落地 `/signup`、`/login`、`/logout` 与 `/dashboard`:注册成功后经计费层一次性发放 10 点试用点数并写 `signup_bonus` 流水,注册限流由 allauth signup rate limit 执行。T-502 已落地 `/apikeys`:登录用户只能管理自己的 Key,生成后明文只显示一次,列表只显示 prefix,删除为吊销 `revoked`。T-503/T-505/T-608 已扩展 `/dashboard` 为个人中心汇总,并落地 `/records/recharge` 与 `/records/usage`:充值总额按已支付订单统计,注册赠点 / 入账 / 消费 / 退款点数按 `PointsLedger` 统计,记录页只查询当前登录用户数据并分页展示。T-504/T-505 已落地 `/recharge`:登录用户可选择金额和支付方式创建 pending 充值订单,页面用本地 static 自托管 qrcode.js 展示二维码票据并轮询 `/api/v1/recharge/status`,到账后刷新余额。
|
||||
T-601 已落地 `/models`:登录用户可查看当前公开可调用别名、能力、是否需要原图和点数单价;页面不展示底层 SKU、模型 URL、provider key、`api_key_encrypted` 或 `extra_body`。
|
||||
T-606 已落地 `/` 公开首页:匿名访问返回 200,不再重定向到 `/dashboard`;匿名用户看到注册 / 登录 / 下载入口,登录用户看到「进入控制台」。首页下载区读取 `DownloadRelease(platform=windows, is_current=True)`,优先使用 `external_url`,否则使用后台上传文件的 `file.url`;无当前版本时显示「暂未发布」。T-610 已在同一下载区“下载客户端”右侧增加“下载导入模板”,模板由后台配置当前版本,匿名可下载;模板本地文件 URL 会转成当前站点绝对 URL,页面不暴露本地文件路径。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user