chore: apply phase 0 review fixes
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
# Django
|
||||
DJANGO_SECRET_KEY=change-me-generate-a-random-secret
|
||||
DJANGO_DEBUG=true
|
||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,testserver
|
||||
DJANGO_TIME_ZONE=Asia/Shanghai
|
||||
|
||||
# MySQL 8.4
|
||||
MYSQL_HOST=127.0.0.1
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_DATABASE=cmhub
|
||||
MYSQL_USER=cmhub
|
||||
MYSQL_PASSWORD=change-me
|
||||
MYSQL_CHARSET=utf8mb4
|
||||
|
||||
# AI key encryption
|
||||
AI_KEY_ENCRYPTION_KEY=base64-fernet-key
|
||||
AI_DEFAULT_CONNECT_TIMEOUT_SECONDS=10
|
||||
AI_DEFAULT_READ_TIMEOUT_SECONDS=300
|
||||
|
||||
# WeChat Pay V3 native
|
||||
WECHAT_PAY_APPID=wx-your-appid
|
||||
WECHAT_PAY_MCHID=your-mchid
|
||||
WECHAT_PAY_API_V3_KEY=change-me
|
||||
WECHAT_PAY_CERT_SERIAL_NO=your-cert-serial-no
|
||||
WECHAT_PAY_PRIVATE_KEY_PATH=/secure/wechat/apiclient_key.pem
|
||||
WECHAT_PAY_NOTIFY_URL=https://cmhub.example.com/api/v1/recharge/callback/wechat
|
||||
|
||||
# Alipay face-to-face payment
|
||||
ALIPAY_APPID=your-alipay-appid
|
||||
ALIPAY_APP_PRIVATE_KEY_PATH=/secure/alipay/app_private_key.pem
|
||||
ALIPAY_PUBLIC_KEY_PATH=/secure/alipay/alipay_public_key.pem
|
||||
ALIPAY_NOTIFY_URL=https://cmhub.example.com/api/v1/recharge/callback/alipay
|
||||
ALIPAY_DEBUG=false
|
||||
|
||||
# Media storage
|
||||
STORAGE_BACKEND=local
|
||||
MEDIA_ROOT=D:\chengma\cmhub\media
|
||||
MEDIA_URL=/media/
|
||||
S3_ENDPOINT_URL=https://s3.example.com
|
||||
S3_BUCKET_NAME=cmhub-media
|
||||
S3_ACCESS_KEY_ID=change-me
|
||||
S3_SECRET_ACCESS_KEY=change-me
|
||||
@@ -25,7 +25,7 @@ Python 3.12 / Django 5.2 LTS + DRF / django-admin / 用户端 Django 模板 SSR
|
||||
|
||||
## 当前状态
|
||||
|
||||
MVP 起步:T-001 Django + DRF 最小骨架已完成,`manage.py` / `config/` 可运行。下一步是 T-002 建立 apps 目录、自定义 User 与配置。详见 [`docs/current-state.md`](docs/current-state.md)。
|
||||
Phase 0 地基与审核修补已完成:Django + DRF 骨架、自定义 User、MySQL 8.4 配置、django-admin smoke test、解释器版本断言和 `.env.example` 均已落地。下一步是 T-101 Provider 适配器层。详见 [`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) 第四节计费时序。
|
||||
|
||||
@@ -36,4 +36,4 @@ MVP 起步:T-001 Django + DRF 最小骨架已完成,`manage.py` / `config/`
|
||||
./init.ps1 # Windows 原生 PowerShell
|
||||
```
|
||||
|
||||
脚本完成依赖安装 + 验证 + 打印启动命令。骨架落地(T-001)后即可使用。
|
||||
脚本完成依赖安装 + 验证 + 打印启动命令。当前 Windows 标准入口为 `./init.ps1`。
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.15 on 2026-07-02 02:11
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('users', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='user',
|
||||
name='email',
|
||||
field=models.EmailField(max_length=254, unique=True, verbose_name='email address'),
|
||||
),
|
||||
]
|
||||
@@ -7,7 +7,7 @@ class User(AbstractUser):
|
||||
ACTIVE = "active", "Active"
|
||||
DISABLED = "disabled", "Disabled"
|
||||
|
||||
email = models.EmailField("email address")
|
||||
email = models.EmailField("email address", unique=True)
|
||||
payment_user_id = models.CharField(
|
||||
max_length=128,
|
||||
blank=True,
|
||||
|
||||
+6
-6
@@ -64,18 +64,18 @@ ALLOWED_HOSTS = env_list("DJANGO_ALLOWED_HOSTS", "127.0.0.1,localhost,testserver
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'rest_framework',
|
||||
'apps.users',
|
||||
'apps.portal',
|
||||
'apps.billing',
|
||||
'apps.ai',
|
||||
'apps.api',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'rest_framework',
|
||||
'apps.users',
|
||||
'apps.portal',
|
||||
'apps.billing',
|
||||
'apps.ai',
|
||||
'apps.api',
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
|
||||
@@ -38,11 +38,11 @@
|
||||
|
||||
## 当前阶段
|
||||
|
||||
当前项目处于:**MVP 起步**(`cmhub` 目录目前只有文档,尚无代码)。
|
||||
当前项目处于:**Phase 1 准备开始**。T-001~T-004 已完成并通过标准验证,下一步进入 T-101 Provider 适配器层。
|
||||
|
||||
优先路径:
|
||||
|
||||
1. Phase 0:Django 骨架可运行、**自定义 User 模型在首次迁移前定好**、django-admin 可登录。
|
||||
1. Phase 0:Django 骨架可运行、**自定义 User 模型在首次迁移前定好**、django-admin 可登录;T-004 审核修补项已完成。
|
||||
2. Phase 1:最高风险功能原型 —— 移植 `cmbot` 的 AI 调用并在服务端跑通一次标题/图片生成。
|
||||
3. Phase 2:计费核心 —— User/UserWallet/ApiKey 模型 + 点数扣减(并发安全,锁 Wallet 行)+ 计费规则 + 调用记录。
|
||||
4. Phase 3:对外 API 与充值 —— Key 鉴权、生成接口、余额查询、充值回调、扫码下单与轮询。
|
||||
@@ -126,5 +126,5 @@ python3.12 manage.py runserver
|
||||
说明:
|
||||
|
||||
- 改后端逻辑后跑:`py -3.12 manage.py test`(Windows)或 `python3.12 manage.py test`(Unix/WSL)。
|
||||
- 改数据模型后跑:`makemigrations && migrate && test`;T-002 接入 MySQL 与自定义 User 前不要提前迁移。
|
||||
- 改数据模型后跑:`makemigrations && migrate && test`;涉及 User 字段唯一约束时,先确认业务库无重复数据。
|
||||
- 如果命令当前不可运行,必须在回复里如实说明原因。
|
||||
|
||||
@@ -26,12 +26,12 @@
|
||||
| 任务队列 | 暂不引入(Celery/RQ) | 待定 | V2 异步化时再评估 |
|
||||
| 部署方式 | Docker + Gunicorn(gthread) + Nginx,单体 | 待定 | MVP 先 `runserver`;生产 Nginx 按路径把 `/api/generate/*`(图片长请求)与用户端页面**分流到不同 gunicorn/worker 池**,避免图片阻塞拖慢页面(见 `04-architecture.md` 5.1) |
|
||||
| 测试 | Django 自带 `manage.py test`(unittest)/ 可选 pytest-django | 已定 | 先用内置 test runner,重点覆盖计费与回调 |
|
||||
| 依赖管理 | 系统 Python 3.12 + pip + `requirements.txt` | 已定 | 不使用虚拟环境;Windows 用 `py -3.12`,Unix/WSL 用 `python3.12`;命令已同步到 init 脚本 |
|
||||
| 依赖管理 | 系统 Python 3.12 + pip + `requirements.txt` + `pyproject.toml` | 已定 | 不使用虚拟环境;Windows 用 `py -3.12`,Unix/WSL 用 `python3.12`;运行依赖仍由 `requirements.txt` 管理,`pyproject.toml` 只落地 `requires-python` 元数据;init 会显式校验解释器版本在 `>=3.12,<3.14` |
|
||||
|
||||
## 二、决策记录与演进
|
||||
|
||||
- **Django 而非 FastAPI**:核心收益是 django-admin 直接满足「运营后台」需求;FastAPI 需自建后台。代价是异步生态较弱,但 MVP 同步返回,不受影响。
|
||||
- **锁定 Django 5.2 LTS + Python 3.12**:① 版本红线属安全而非性能——生文/图生图瓶颈在「等上游 + worker 并发 + 超时」,不在框架版本(详见 [架构设计](04-architecture.md) 5.1),故版本选择只按安全与维护窗口定;② Django 4.0/4.1 已 EOL、无安全补丁,涉资金服务禁用;4.2 LTS 支持窗口临近尾声,不从其起步;5.2 LTS 维护到 2028,窗口最长。③ Django 5.2 支持 Python 3.10–3.13,锁 3.12 取「稳定 + 库全 + 性能」的平衡,避开 3.10(临近 EOL)与 3.14(不在 5.2 官方矩阵)。T-001 已按用户要求固定使用系统 Python 3.12:Windows PowerShell 用 `py -3.12`,Unix/WSL 用 `python3.12`。
|
||||
- **锁定 Django 5.2 LTS + Python 3.12**:① 版本红线属安全而非性能——生文/图生图瓶颈在「等上游 + worker 并发 + 超时」,不在框架版本(详见 [架构设计](04-architecture.md) 5.1),故版本选择只按安全与维护窗口定;② Django 4.0/4.1 已 EOL、无安全补丁,涉资金服务禁用;4.2 LTS 支持窗口临近尾声,不从其起步;5.2 LTS 维护到 2028,窗口最长。③ Django 5.2 支持 Python 3.10–3.13,锁 3.12 取「稳定 + 库全 + 性能」的平衡,避开 3.10(临近 EOL)与 3.14(不在 5.2 官方矩阵)。T-001 已按用户要求固定使用系统 Python 3.12:Windows PowerShell 用 `py -3.12`,Unix/WSL 用 `python3.12`;T-004 起 init 脚本在安装依赖前显式断言运行解释器版本在 `>=3.12,<3.14`。
|
||||
- **预付费点数而非实时查支付余额**:充值时按汇率把金额转点数存本地,解耦支付系统、降低调用延迟、并发扣减用本地数据库事务即可保证。代价是需处理充值幂等与对账。
|
||||
- **稳定接口 + 可插拔供应商**:对外只 `generate text/image` 两接口 + 能力别名;具体模型在后台配置并经适配器调用。收益是换供应商对调用方零改动、计费按别名稳定、可加授权与故障转移;代价是需维护适配器层与别名映射。**调用方不绑具体模型 SKU**。
|
||||
- **同步生成而非任务队列**:MVP 不引入 Celery/Redis,降低复杂度;图片耗时长,靠调大超时支撑,V2 再异步化。
|
||||
|
||||
@@ -133,7 +133,7 @@ CREATE TABLE pricing_rule (
|
||||
CREATE TABLE "user" (
|
||||
id INTEGER PRIMARY KEY,
|
||||
username TEXT UNIQUE NOT NULL,
|
||||
email TEXT NOT NULL, -- 注册邮箱,需验证
|
||||
email TEXT NOT NULL UNIQUE, -- 注册邮箱,需验证且唯一
|
||||
password TEXT NOT NULL, -- Django 哈希存储
|
||||
payment_user_id TEXT, -- 对应外部支付系统的用户标识
|
||||
status TEXT NOT NULL DEFAULT 'active', -- active / disabled
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
| T-001 | 初始化 Django + DRF 项目骨架 | - | `manage.py` 可运行;`runserver` 起得来;用真实命令替换 `init.sh`/`init.ps1` 与 `00-ai-start-here.md`/`03-tech-stack.md`/`current-state.md` 的占位命令 | DONE |
|
||||
| T-002 | 建立 apps 目录、自定义 User 与配置 | T-001 | 按 `04-architecture.md` 建 `apps/users|portal|billing|ai|api`;**首次迁移前定义自定义 `User` 模型(设 `AUTH_USER_MODEL`)**;settings 用环境变量读密钥、配 MySQL(utf8mb4),无明文密钥 | DONE |
|
||||
| T-003 | 接通 django-admin 与最小测试 | T-001 | `createsuperuser` 后能登录 `/admin/`;`manage.py test` 可运行(至少 1 条占位测试通过) | DONE |
|
||||
| T-004 | Phase 0 骨架审核修补 | T-003 | 按 [`phase-0-review.md`](phase-0-review.md) 修 **P1**(`User.email` 加 `unique`、`requires-python` 落地 + init 校验解释器版本)与 **P2**(`INSTALLED_APPS` 顺序、补 `.env.example`);同步修正根 `README.md` 当前状态;`check`/`test`/`init` 重新全绿并在 `../progress.md` 留证据。**建议先于 T-101 完成**(P1-1 趁 user 表空成本最低) | DONE |
|
||||
|
||||
## Phase 1 · 最高风险验证(AI 调用 + 可插拔供应商)
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
- [架构设计](04-architecture.md):系统结构、计费时序、数据模型、关键风险和开发顺序。
|
||||
- [编码规则](05-coding-rules.md):硬性约束,含资金/点数安全专项(第 8 节)。
|
||||
- [任务看板](06-tasks.md):按依赖拆分的小任务,agent 每轮只做一个。
|
||||
- [Phase 0 骨架审核](phase-0-review.md):T-001~003 代码审核结论与修补清单(P1/P2/P3),对应任务 T-004。
|
||||
- [API 合约](api.md):对外接口、支付回调、AI 调用模块合约、错误码。
|
||||
- [路由与页面结构](routes.md):API 路由与 django-admin 后台职责。
|
||||
- [环境变量与配置](env.md):Django、数据库、AI 密钥加密、支付、对象存储等配置项。
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
- 用户或 Key 被禁用/吊销(disabled/revoked):返回 `403`。
|
||||
- **对外 API 只接受 API Key 认证,不接受 Web session**(浏览器带 cookie 也不能调 API,防绕过计费归属)。
|
||||
- 图片生成为**同步**接口,可能耗时较长,调用方与网关需设置足够超时(≥ 300s)。
|
||||
- 用户端注册使用同一个 `User` 账本主体;注册邮箱必须验证且唯一,避免同邮箱对应多个点数账户。
|
||||
|
||||
通用错误响应:
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@
|
||||
## 当前快照
|
||||
|
||||
- 日期:2026-07-02
|
||||
- 阶段:Phase 0 地基已完成;下一步进入 Phase 1 的 T-101
|
||||
- 阶段:Phase 0 地基与审核修补已完成;下一步进入 Phase 1 的 T-101
|
||||
- 技术栈:系统 Python 3.12.3 + Django 5.2.15 + DRF 3.16.1 + PyMySQL 1.1.3 + cryptography 46.0.7 + django-admin;MySQL 8.4 已接入 settings;用户端(模板 SSR/Bootstrap/allauth) 后续任务落地;详见 `03-tech-stack.md`
|
||||
- 生产代码:已有最小 Django 工程骨架:`manage.py`、`config/`;T-002 已创建 `apps/users|portal|billing|ai|api`;T-003 已把自定义 `User` 注册进 django-admin
|
||||
- 测试:`manage.py check` 通过;`manage.py test` 通过(2 条 admin smoke tests);`./init.ps1` 通过
|
||||
- 生产代码:已有最小 Django 工程骨架:`manage.py`、`config/`;T-002 已创建 `apps/users|portal|billing|ai|api`;T-003 已把自定义 `User` 注册进 django-admin;T-004 已完成 email 唯一性、init 版本断言、app 顺序、`.env.example` 与 `pyproject.toml`
|
||||
- 测试:`makemigrations --check` 通过;`migrate` 通过;`manage.py check` 通过;`manage.py test` 通过(2 条 admin smoke tests);`./init.ps1` 通过
|
||||
- 数据:AI 上游调用与模型配置参考 `D:\chengma\cmbot`(`src/services/ai_text_service.py`、`ai_image_service.py`、`config/ai_models.json`)
|
||||
- 标准启动路径:Windows 用 `./init.ps1`;Unix/WSL 用 `./init.sh`
|
||||
- 标准验证路径:Windows 用 `py -3.12 manage.py check` / `py -3.12 manage.py test`
|
||||
@@ -30,10 +30,10 @@
|
||||
| `docs/` | 已有 | 全套 harness 文档 |
|
||||
| `AGENTS.md` / `CLAUDE.md` | 已有 | 仓库级入口 |
|
||||
| `progress.md` | 已有 | 执行流水,已记录多轮文档决策;后续任务继续追加 |
|
||||
| `init.sh` / `init.ps1` | 已有 | 启动验证入口,已固定系统 Python 3.12 命令 |
|
||||
| `requirements.txt` | 已有 | Django 5.2 / DRF 3.16 / PyMySQL / cryptography 依赖 |
|
||||
| `init.sh` / `init.ps1` | 已有 | 启动验证入口,已固定系统 Python 3.12 命令,并校验解释器版本 `>=3.12,<3.14` |
|
||||
| `requirements.txt` / `pyproject.toml` | 已有 | `requirements.txt` 管运行依赖;`pyproject.toml` 落地 `requires-python` |
|
||||
| `config/`(Django 工程) | 已有 | T-001 创建,含 settings / urls / wsgi / asgi |
|
||||
| `apps/`(users/portal/billing/ai/api) | 已有 | T-002 创建;`apps/users` 已定义自定义 `User`;T-003 已注册 admin 与 admin smoke test |
|
||||
| `apps/`(users/portal/billing/ai/api) | 已有 | T-002 创建;`apps/users` 已定义自定义 `User`;T-003 已注册 admin 与 admin smoke test;T-004 已给 `User.email` 加唯一约束 |
|
||||
| `manage.py` | 已有 | T-001 创建 |
|
||||
| `tests/` | 待建 | 随各任务补充 |
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
|
||||
任务状态以 [`06-tasks.md`](06-tasks.md) 为准,历史执行记录见 [`../progress.md`](../progress.md)。
|
||||
|
||||
- 已完成:T-001 初始化 Django + DRF 项目骨架;T-002 建立 apps 目录、自定义 User 与配置;T-003 接通 django-admin 与最小测试。
|
||||
- 已完成:T-001 初始化 Django + DRF 项目骨架;T-002 建立 apps 目录、自定义 User 与配置;T-003 接通 django-admin 与最小测试;T-004 Phase 0 骨架审核修补。
|
||||
- 正在进行:无。
|
||||
- 当前 blocker:无。
|
||||
- 下一个可领取任务:**T-101 Provider 适配器层 + 移植 cmbot 调用**。
|
||||
@@ -62,7 +62,7 @@ python3.12 manage.py test
|
||||
python3.12 manage.py runserver
|
||||
```
|
||||
|
||||
当前骨架可运行。T-002 已在首次迁移前创建自定义 User,并按 `env.md` 接入 MySQL 8.4 / utf8mb4;远程 MySQL 已完成 Django 初始迁移。T-003 已接通 django-admin,标准测试可创建/销毁 `test_cmhub` 测试库并通过。
|
||||
当前骨架可运行。T-002 已在首次迁移前创建自定义 User,并按 `env.md` 接入 MySQL 8.4 / utf8mb4;远程 MySQL 已完成 Django 初始迁移。T-003 已接通 django-admin,标准测试可创建/销毁 `test_cmhub` 测试库并通过。T-004 已应用 `users.0002_alter_user_email`,`user.email` 已有唯一索引。
|
||||
|
||||
## 开始编码前检查
|
||||
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@
|
||||
## 一、配置来源
|
||||
|
||||
- Django 运行级配置走环境变量或 `.env`(`.env` 不提交)。
|
||||
- 仓库根目录提供 `.env.example` 作为无密钥样例;新增配置项时同步更新 `.env.example` 与本文。
|
||||
- 上游 AI 模型的 `api_key` 存入数据库前必须用 `AI_KEY_ENCRYPTION_KEY` 加密,admin 脱敏展示且不回显明文。
|
||||
- 微信、支付宝商户密钥/证书走环境变量或部署机安全文件路径,不写入数据库明文字段。
|
||||
- 本地开发、测试、生产使用同一套变量名;差异只在变量值。
|
||||
@@ -26,7 +27,7 @@
|
||||
| 变量 | 必填 | 示例 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `MYSQL_HOST` | 是 | `127.0.0.1` | cmhub 专用 MySQL 实例地址 |
|
||||
| `MYSQL_PORT` | 是 | `3307` | 独立端口,避免复用已有 MySQL 5.7 |
|
||||
| `MYSQL_PORT` | 是 | `3306` | MySQL 默认端口;若与已有实例共存,可改为专用独立端口 |
|
||||
| `MYSQL_DATABASE` | 是 | `cmhub` | 数据库名 |
|
||||
| `MYSQL_USER` | 是 | `cmhub` | 应用账号 |
|
||||
| `MYSQL_PASSWORD` | 是 | `change-me` | 数据库密码 |
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
# Phase 0 骨架审核报告(T-001 ~ T-003)
|
||||
|
||||
> 审核人:Claude Code(全栈视角)|日期:2026-07-02|结论:**验收通过**。
|
||||
> 进入 Phase 1(T-101)前,建议先做 **T-004 骨架修补**(本文 P1/P2)。
|
||||
> 本文面向 codex 执行:每条修补项给出「症状 / 位置 / 怎么改 / 怎么验证」。修补任务见 [`06-tasks.md`](06-tasks.md) 的 **T-004**。
|
||||
|
||||
## 一、验收核对(全部达标)
|
||||
|
||||
| 任务 | 验收要点 | 结果 |
|
||||
| --- | --- | --- |
|
||||
| T-001 | manage.py 可跑、runserver 起得来、init 脚本真实命令、文档占位替换 | ✅ |
|
||||
| T-002 | 五个 app、**首迁移前定义自定义 User + `AUTH_USER_MODEL`**、env 读密钥无明文、MySQL+utf8mb4 | ✅ |
|
||||
| T-003 | superuser 能登录 `/admin/`、`manage.py test` 至少 1 条通过(实际 2 条) | ✅ |
|
||||
|
||||
## 二、做对的(勿在修补中回退)
|
||||
|
||||
以下是已正确落地的关键点,T-004 修补时**不要改坏**:
|
||||
|
||||
1. **自定义 User 先于首次迁移**:`apps/users/migrations/0001_initial.py` 只依赖 `auth`,`AUTH_USER_MODEL='users.User'` 已设,`db_table='user'`。Django 头号坑已避开。
|
||||
2. **PyMySQL 胶水**:`config/__init__.py` 的 `pymysql.install_as_MySQLdb()`——不可删。
|
||||
3. **密钥零泄露**:SECRET_KEY / DB 密码全走 env;`.env`、`ai_models.json` 均未被 git 跟踪且在 `.gitignore`。
|
||||
4. **测试库隔离**:坚持独立 `test_cmhub` 测试库,不碰业务库 `cmhub`。
|
||||
5. `cryptography` 依赖(MySQL8 `caching_sha2_password` + 未来 `api_key` 加密预留);admin 继承 `DjangoUserAdmin` 做脱敏/过滤/只读。
|
||||
|
||||
## 三、修补清单
|
||||
|
||||
### P1 · 现在改(趁地基未固化,低成本高收益)
|
||||
|
||||
#### P1-1 `User.email` 加 `unique=True`
|
||||
|
||||
- **症状**:`email` 必填但不唯一,允许同邮箱重复注册,与需求(`02-requirements.md`)「邮箱验证注册」语义冲突;后续 allauth 邮箱验证 / 找回密码通常要求 email 唯一。现在 `user` 表基本为空,是加约束的最便宜时机;拖到 T-501 再加要额外迁移 + 清洗重复数据。
|
||||
- **位置**:`apps/users/models.py`(`email` 字段定义处)。
|
||||
- **怎么改**:`email = models.EmailField("email address", unique=True)`。
|
||||
- **前提/权衡**:若产品最终确定「只用 username 登录、email 仅展示」,可不改——但需在本文此条标注「产品确认不需要」。**默认动作:加 unique。**
|
||||
- **注意**:改前确认业务库 `user` 表无重复邮箱(superuser 用唯一邮箱);否则先清理。
|
||||
- **验证**:`makemigrations users`(应生成一条 `AlterField`)→ `migrate` → `check` → `test` 全绿。
|
||||
|
||||
#### P1-2 `requires-python` 落地 + init 脚本校验解释器版本
|
||||
|
||||
- **症状**:`03-tech-stack.md` 要求「骨架须写死 `requires-python=">=3.12,<3.14"`,init 脚本校验解释器版本」。当前用 `requirements.txt`(表达不了 Python 版本约束),`init.sh`/`init.ps1` 只硬调 `python3.12` / `py -3.12` 命令、**无显式版本断言**——换台机器解释器指向 3.13 或不存在时不会明确报错。文档一致性欠账。
|
||||
- **位置**:项目根(无 `pyproject.toml`);`init.sh` 顶部;`init.ps1` 顶部。
|
||||
- **怎么改(二选一,取轻——推荐 A)**:
|
||||
- **A(推荐,最小改动)**:在 `init.sh` / `init.ps1` 安装依赖前加一步 Python 版本断言:解析解释器版本,若不在 `>=3.12,<3.14` 则打印错误并退出(非 0)。
|
||||
- **B**:新增 `pyproject.toml` 写 `requires-python=">=3.12,<3.14"`(仅在配合构建/安装工具时才强制,较重;若采用需同步 `03-tech-stack.md` 的依赖管理说明)。
|
||||
- **验证**:用非 3.12 解释器(或模拟)跑 init,应明确报错退出;用 3.12 正常走完安装 + `check`。
|
||||
|
||||
### P2 · 规范性(趁早理顺)
|
||||
|
||||
#### P2-1 `INSTALLED_APPS` 顺序
|
||||
|
||||
- **症状**:`rest_framework` 与 `apps.*` 排在整个 `django.contrib.*` **之前**。`APP_DIRS=True` 下模板按 `INSTALLED_APPS` 顺序查找——将来 `portal` 做用户端模板时,本地 app 模板会**优先于 admin**,若不慎放了同名模板(如 `admin/base_site.html`)会意外覆盖后台。当前无模板,是潜在隐患。
|
||||
- **位置**:`config/settings.py` 的 `INSTALLED_APPS`。
|
||||
- **怎么改**:调整为 `django.contrib.*`(admin/auth/contenttypes/sessions/messages/staticfiles)在前 → `rest_framework` → `apps.users|portal|billing|ai|api`。
|
||||
- **验证**:`check` / `test` 仍全绿;`/admin/` 正常。
|
||||
|
||||
#### P2-2 补 `.env.example`
|
||||
|
||||
- **症状**:`.gitignore` 有 `!.env.example` 白名单,说明本应提供样例,但文件缺失;新人不知道要配哪些环境变量。
|
||||
- **位置**:项目根。
|
||||
- **怎么改**:新增 `.env.example`,列出 `MYSQL_HOST/PORT/DATABASE/USER/PASSWORD/CHARSET`、`DJANGO_SECRET_KEY`、`DJANGO_DEBUG`、`DJANGO_ALLOWED_HOSTS` 等键,值用占位符(**不含任何真实值**)。以 `env.md` 为准。
|
||||
- **验证**:`git status` 显示 `.env.example` 被跟踪(未被 `.gitignore` 忽略)。
|
||||
|
||||
#### P2-3 同步根 `README.md` 当前状态
|
||||
|
||||
- **症状**:根 `README.md` 的「当前状态」仍停在 T-001 / 下一步 T-002,已落后于 T-003 完成后的现实状态。
|
||||
- **位置**:项目根 `README.md`。
|
||||
- **怎么改**:更新为 Phase 0 已完成、当前先做 T-004 修补、之后进入 T-101。
|
||||
- **验证**:`README.md` 与 `docs/current-state.md` 的下一步口径一致。
|
||||
|
||||
### P3 · 后续任务处理(**不在 T-004 范围**,仅登记)
|
||||
|
||||
- **REST_FRAMEWORK 认证配置**:`DEFAULT_AUTHENTICATION_CLASSES` 等(对外 API 只认 Key 不认 session)——留给 **T-301**。
|
||||
- **`sql_mode` 完整性**:`init_command` 仅 `STRICT_TRANS_TABLES`,会覆盖 MySQL 默认 sql_mode 其余项;对 InnoDB 防截断已够,可后续补 `NO_ENGINE_SUBSTITUTION` 等。
|
||||
- **生产 SECRET_KEY 保护**:`DEBUG=False` 且 `SECRET_KEY` 仍为默认 `django-insecure-*` 时应主动报错——留给部署任务 **T-403**。
|
||||
|
||||
## 四、说明:未本地复跑
|
||||
|
||||
审核机(WSL)无 `python3.12`,**未本地复跑 `check`/`test`**。本报告基于:静态审查(代码 + 迁移文件 + 配置)+ codex 的执行记录(记录含真实报错与修复过程:MySQL 授权、MySQL8 `caching_sha2_password` 需 `cryptography`,可信度高)。
|
||||
|
||||
T-004 修补后,请重跑 `check` / `test` / `init`,并把命令与结果记入 `progress.md` 作为证据(按 `06-tasks.md` 使用规则第 5 条)。
|
||||
|
||||
## 五、T-004 完成定义
|
||||
|
||||
- P1-1、P1-2、P2-1、P2-2、P2-3 全部处理(P1-1 若产品确认不需要则标注跳过)。
|
||||
- `check` 0 issues、`test` 全绿、`init` 通过,证据入 `progress.md`。
|
||||
- P3 各项已在 `06-tasks.md` 对应任务(T-301 / T-403)或 Backlog 有登记,不遗失。
|
||||
@@ -33,6 +33,22 @@ Assert-Configured -Name "StartCmd" -Value $StartCmd
|
||||
|
||||
Write-Host "==> 当前目录: $($PWD.Path)"
|
||||
|
||||
Write-Host "==> 校验 Python 版本"
|
||||
$PythonVersion = py -3.12 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}')"
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Error "无法运行 py -3.12。请安装 Python 3.12/3.13,并确保 py launcher 可用。"
|
||||
exit 3
|
||||
}
|
||||
|
||||
$VersionParts = $PythonVersion.Trim().Split(".")
|
||||
$MajorVersion = [int]$VersionParts[0]
|
||||
$MinorVersion = [int]$VersionParts[1]
|
||||
if ($MajorVersion -ne 3 -or $MinorVersion -lt 12 -or $MinorVersion -ge 14) {
|
||||
Write-Error "Python 版本必须满足 >=3.12,<3.14,当前为 $PythonVersion。"
|
||||
exit 3
|
||||
}
|
||||
Write-Host " Python $PythonVersion"
|
||||
|
||||
if (-not (Test-Path "manage.py")) {
|
||||
Write-Error "未找到 manage.py。Django 骨架尚未初始化(见 docs/06-tasks.md 的 T-001)。完成 T-001 后本脚本即可正常运行。"
|
||||
exit 1
|
||||
|
||||
@@ -33,6 +33,19 @@ ensure_configured "START_CMD" "${START_CMD[0]}"
|
||||
|
||||
echo "==> 当前目录: $PWD"
|
||||
|
||||
echo "==> 校验 Python 版本"
|
||||
if ! PYTHON_VERSION="$(python3.12 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")' 2>/dev/null)"; then
|
||||
echo "ERROR: 无法运行 python3.12。请安装 Python 3.12/3.13,并确保命令可用。"
|
||||
exit 3
|
||||
fi
|
||||
|
||||
IFS=. read -r PY_MAJOR PY_MINOR _ <<< "$PYTHON_VERSION"
|
||||
if [ "$PY_MAJOR" -ne 3 ] || [ "$PY_MINOR" -lt 12 ] || [ "$PY_MINOR" -ge 14 ]; then
|
||||
echo "ERROR: Python 版本必须满足 >=3.12,<3.14,当前为 ${PYTHON_VERSION}。"
|
||||
exit 3
|
||||
fi
|
||||
echo " Python ${PYTHON_VERSION}"
|
||||
|
||||
if [ ! -f "manage.py" ]; then
|
||||
echo "ERROR: 未找到 manage.py。Django 骨架尚未初始化(见 docs/06-tasks.md 的 T-001)。"
|
||||
echo " 完成 T-001 后本脚本即可正常运行。"
|
||||
|
||||
+36
@@ -230,3 +230,39 @@
|
||||
- 阻塞:无。
|
||||
- 决策:保留独立 `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 调用。
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[project]
|
||||
name = "cmhub"
|
||||
version = "0.1.0"
|
||||
description = "Self-service billing API gateway and django-admin operations backend for AI generation."
|
||||
requires-python = ">=3.12,<3.14"
|
||||
dependencies = []
|
||||
Reference in New Issue
Block a user