docs: add t-403 deployment guide
This commit is contained in:
@@ -2,9 +2,23 @@
|
||||
DJANGO_SECRET_KEY=change-me-generate-a-random-secret
|
||||
DJANGO_DEBUG=true
|
||||
DJANGO_ALLOWED_HOSTS=127.0.0.1,localhost,testserver
|
||||
DJANGO_CSRF_TRUSTED_ORIGINS=
|
||||
DJANGO_TIME_ZONE=Asia/Shanghai
|
||||
DJANGO_EMAIL_BACKEND=django.core.mail.backends.console.EmailBackend
|
||||
DJANGO_DEFAULT_FROM_EMAIL=noreply@cmhub.local
|
||||
DJANGO_SESSION_COOKIE_SECURE=false
|
||||
DJANGO_CSRF_COOKIE_SECURE=false
|
||||
DJANGO_SECURE_SSL_REDIRECT=false
|
||||
DJANGO_SECURE_HSTS_SECONDS=0
|
||||
DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS=false
|
||||
DJANGO_SECURE_HSTS_PRELOAD=false
|
||||
DJANGO_SECURE_PROXY_SSL_HEADER=false
|
||||
|
||||
# Static and shared cache
|
||||
STATIC_URL=/static/
|
||||
STATIC_ROOT=D:\chengma\cmhub\staticfiles
|
||||
DJANGO_CACHE_BACKEND=django.core.cache.backends.locmem.LocMemCache
|
||||
DJANGO_CACHE_LOCATION=cmhub-local-cache
|
||||
|
||||
# MySQL 8.4
|
||||
MYSQL_HOST=127.0.0.1
|
||||
|
||||
@@ -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 完整验收:用户可通过 allauth 自助注册、邮箱验证、登录、登出,扫码充值并轮询到账,生成 / 删除(吊销)API Key,查看余额、充值总额、分页充值记录与分页消费记录;运营可在 django-admin 检索用户、钱包、API Key、计费规则、汇率、充值订单、点数流水和调用记录,并通过计费层带原因手工调点。下一步进入 T-403 部署 / 运行文档。详见 [`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 部署 / 运行文档:用户可通过 allauth 自助注册、邮箱验证、登录、登出,扫码充值并轮询到账,生成 / 删除(吊销)API Key,查看余额、充值总额、分页充值记录与分页消费记录;运营可在 django-admin 检索用户、钱包、API Key、计费规则、汇率、充值订单、点数流水和调用记录,并通过计费层带原因手工调点;生产部署按 `docs/deployment.md` 执行。计划内 MVP 任务已完成,下一步是按部署文档上 VPS 配置真实邮件、支付、AI 模型和图片真实耗时验证。详见 [`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) 第四节计费时序。
|
||||
|
||||
|
||||
+27
-1
@@ -94,6 +94,21 @@ ALIPAY_NOTIFY_URL = os.environ.get("ALIPAY_NOTIFY_URL", "")
|
||||
ALIPAY_DEBUG = env_bool("ALIPAY_DEBUG", False)
|
||||
|
||||
ALLOWED_HOSTS = env_list("DJANGO_ALLOWED_HOSTS", "127.0.0.1,localhost,testserver")
|
||||
CSRF_TRUSTED_ORIGINS = env_list("DJANGO_CSRF_TRUSTED_ORIGINS", "")
|
||||
SESSION_COOKIE_SECURE = env_bool("DJANGO_SESSION_COOKIE_SECURE", not DEBUG)
|
||||
CSRF_COOKIE_SECURE = env_bool("DJANGO_CSRF_COOKIE_SECURE", not DEBUG)
|
||||
SECURE_SSL_REDIRECT = env_bool("DJANGO_SECURE_SSL_REDIRECT", False)
|
||||
SECURE_HSTS_SECONDS = env_int("DJANGO_SECURE_HSTS_SECONDS", 0)
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = env_bool(
|
||||
"DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS",
|
||||
False,
|
||||
)
|
||||
SECURE_HSTS_PRELOAD = env_bool("DJANGO_SECURE_HSTS_PRELOAD", False)
|
||||
SECURE_PROXY_SSL_HEADER = (
|
||||
("HTTP_X_FORWARDED_PROTO", "https")
|
||||
if env_bool("DJANGO_SECURE_PROXY_SSL_HEADER", False)
|
||||
else None
|
||||
)
|
||||
|
||||
API_GENERATE_THROTTLE_RATE = os.environ.get("API_GENERATE_THROTTLE_RATE", "60/min")
|
||||
API_AUTH_FAILURE_THROTTLE_RATE = os.environ.get("API_AUTH_FAILURE_THROTTLE_RATE", "30/min")
|
||||
@@ -207,6 +222,16 @@ DATABASES = {
|
||||
}
|
||||
}
|
||||
|
||||
CACHES = {
|
||||
"default": {
|
||||
"BACKEND": os.environ.get(
|
||||
"DJANGO_CACHE_BACKEND",
|
||||
"django.core.cache.backends.locmem.LocMemCache",
|
||||
),
|
||||
"LOCATION": os.environ.get("DJANGO_CACHE_LOCATION", "cmhub-local-cache"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/5.2/ref/settings/#auth-password-validators
|
||||
@@ -242,7 +267,8 @@ USE_TZ = True
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/5.2/howto/static-files/
|
||||
|
||||
STATIC_URL = 'static/'
|
||||
STATIC_URL = os.environ.get("STATIC_URL", "/static/")
|
||||
STATIC_ROOT = os.environ.get("STATIC_ROOT", str(BASE_DIR / "staticfiles"))
|
||||
|
||||
MEDIA_ROOT = os.environ.get("MEDIA_ROOT", str(BASE_DIR / "media"))
|
||||
MEDIA_URL = os.environ.get("MEDIA_URL", "/media/")
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
|
||||
## 当前阶段
|
||||
|
||||
当前项目处于:**Phase 5 后台与发布**。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 5 后台与发布已完成计划内任务**。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 部署 / 运行文档。下一步是按 `deployment.md` 在 VPS 上配置真实邮件、支付、AI 模型和图片真实耗时验证,或从 Backlog 重新规划后续任务。
|
||||
|
||||
优先路径:
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
3. Phase 2:计费核心 —— T-201/T-202/T-203 已完成 UserWallet/ApiKey/PointsLedger/CallRecord、计费规则、汇率、计费计算、并发安全扣点与失败退点。
|
||||
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 部署 / 运行文档。
|
||||
6. Phase 5:后台与发布 —— T-401 运营后台完善、T-402 完整验收 MVP、T-403 部署 / 运行文档已完成;计划内 MVP 任务已收尾。
|
||||
|
||||
## 领取任务规则
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
| 充值对接 | 自助扫码:微信 V3 native + 支付宝当面付;下单取二维码 + 服务端回调(验签 + 幂等) | 已定 | T-304/T-305 已落地回调、扫码下单、状态轮询、HMAC mock 联调与 SDK 模式入口;生产需安装并配置 `wechatpayv3` / `python-alipay-sdk` 与真实商户密钥/证书 |
|
||||
| 生成返回方式 | 同步 HTTP(无任务队列) | 已定 | MVP 简化;图片接口需调大网关/服务超时 |
|
||||
| 任务队列 | 暂不引入(Celery/RQ) | 待定 | V2 异步化时再评估 |
|
||||
| 部署方式 | Docker + Gunicorn(gthread) + Nginx,单体 | 待定 | MVP 先 `runserver`;生产 Nginx 按路径把 `/api/generate/*`(图片长请求)与用户端页面**分流到不同 gunicorn/worker 池**,避免图片阻塞拖慢页面(见 `04-architecture.md` 5.1) |
|
||||
| 部署方式 | VPS / 宝塔 + Nginx + Gunicorn(gthread) + systemd,Django 单体 | 已定(MVP) | 生产按 `deployment.md` 执行;Nginx 按路径把 `/api/v1/generate/*`(图片长请求)分流到独立 Gunicorn 池,用户端 / admin / 余额 / 充值走普通池;`/static/` 托管 `STATIC_ROOT`,`/media/` 托管本地媒体或后续换对象存储;DRF 限流生产必须使用共享 Django cache |
|
||||
| 测试 | Django 自带 `manage.py test`(unittest)/ 可选 pytest-django | 已定 | 先用内置 test runner,重点覆盖计费与回调;涉及 `select_for_update` 的并发扣点测试必须在 MySQL 上跑,SQLite 会忽略行锁导致假绿 |
|
||||
| 依赖管理 | 系统 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` |
|
||||
|
||||
@@ -51,12 +51,17 @@
|
||||
| --- | --- |
|
||||
| 安装依赖(Windows) | `py -3.12 -m pip install -r requirements.txt` |
|
||||
| 安装依赖(Unix/WSL) | `python3.12 -m pip install -r requirements.txt` |
|
||||
| 安装生产依赖(Linux) | `python3.12 -m pip install -r requirements-production.txt` |
|
||||
| 基础检查(Windows) | `py -3.12 manage.py check` |
|
||||
| 基础检查(Unix/WSL) | `python3.12 manage.py check` |
|
||||
| 测试(Windows) | `py -3.12 manage.py test` |
|
||||
| 本地开发(Windows) | `py -3.12 manage.py runserver` |
|
||||
| 创建后台管理员 | T-003 后执行 `py -3.12 manage.py createsuperuser` |
|
||||
| 数据库迁移 | T-002 接入 MySQL 后执行 `makemigrations` / `migrate` |
|
||||
| 生产静态文件收集 | `python3.12 manage.py collectstatic --noinput` |
|
||||
| 生产共享 cache 表 | `python3.12 manage.py createcachetable cmhub_cache` |
|
||||
| 生产 Gunicorn 普通池 | `gunicorn config.wsgi:application --bind 127.0.0.1:8001 --workers 2 --worker-class gthread --threads 4 --timeout 120` |
|
||||
| 生产 Gunicorn 生成池 | `gunicorn config.wsgi:application --bind 127.0.0.1:8002 --workers 1 --worker-class gthread --threads 4 --timeout 360` |
|
||||
| 导入 cmbot AI 模型配置 | `py -3.12 manage.py import_ai_models path\to\ai_models.json --create-default-aliases` |
|
||||
| AI 生成 smoke(录制标题) | `py -3.12 manage.py smoke_ai_generation title --recorded` |
|
||||
| AI 生成 smoke(录制图片) | `py -3.12 manage.py smoke_ai_generation image --recorded` |
|
||||
|
||||
@@ -347,7 +347,7 @@ CREATE TABLE call_record (
|
||||
| 配置变更审计 | 改密钥/模型/别名映射无痕 | `AiConfigAuditLog` 自动记录后台 create/update/delete;密钥只记录 empty/set 变化,日志只读 |
|
||||
| API Key 泄露 | 明文存库一旦泄露全泄 | Key **哈希存储**(sha256),明文只在创建时显示一次,库内存 `key_hash`+`key_prefix`,鉴权做哈希比对 |
|
||||
| 注册滥用 | 自助注册被批量刷 | 邮箱验证 + 生成接口限流(DRF throttle);**注册不送点数**,无免费额度可薅 |
|
||||
| Web/API 抢 worker | 图片同步长请求占满 worker、拖慢用户端页面 | 单体下按路径把 `/api/generate/*` 与用户端页面**分流到不同 gunicorn/worker 池**(见 5.1) |
|
||||
| Web/API 抢 worker | 图片同步长请求占满 worker、拖慢用户端页面 | 单体下按路径把 `/api/v1/generate/*` 与用户端页面**分流到不同 gunicorn/worker 池**(见 5.1) |
|
||||
| 充错账户 | 扫码订单未绑定发起用户 | 订单创建即绑定 `user`;回调按 `order_no` 定位订单→其 user 入账 |
|
||||
| SSRF / 任意 URL 下载 | `image_url` 让服务端请求调用方指定地址 | 仅允许公网 http/https;请求前解析 IP 并拒绝内网/回环/链路本地/保留地址;重定向逐跳校验;流式读取并限制大小 |
|
||||
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@
|
||||
| --- | --- | --- | --- | --- |
|
||||
| T-401 | 运营后台完善 | T-302, T-304 | admin 可管理用户/钱包/ApiKey(脱敏)、配规则/汇率、检索充值订单/流水/调用记录;手工调点带原因并经计费层写流水 | DONE |
|
||||
| T-402 | 完整验收 MVP | T-401, T-505 | `02-requirements.md` 的 P0 验收全部通过(含用户端注册/充值/API Key/记录) | DONE |
|
||||
| T-403 | 部署 / 运行文档 | T-402 | 新环境可按文档运行;明确图片接口超时配置;上线前必须引用一次真实图片生成耗时来设置 Gunicorn `--timeout`、Nginx `proxy_read_timeout`、客户端 read timeout;若尚无真实耗时,部署文档必须显式标注图片同步风险未退,不得声称已验证;生产必须配置真实 `DJANGO_EMAIL_BACKEND` / `DJANGO_DEFAULT_FROM_EMAIL`,否则 allauth 邮箱验证无法发信、用户无法完成登录;**生产静态文件 serving**:T-505 已把 Bootstrap/qrcode 自托管到 `apps/portal/static/`,但 `settings` 目前只有 `STATIC_URL`,`DEBUG=False` 下 Django 不发静态文件——必须配置 `STATIC_ROOT` + `collectstatic` + WhiteNoise 或 Nginx 托管 `/static/`,否则用户端 CSS 错版、充值二维码 404(P2-1 的国内可用性目标在生产失效);**DRF 限流依赖共享缓存**:多 Gunicorn worker 下默认 `LocMemCache` 是每进程的,会让 `generate`/`api_auth_failure` 限流按 worker 各算一份(实际速率≈worker 数×配置值),部署必须配置 Redis/Memcached 等共享 `CACHES` 后端并在文档说明,否则限流形同虚设 | TODO |
|
||||
| T-403 | 部署 / 运行文档 | T-402 | 新环境可按文档运行;明确图片接口超时配置;上线前必须引用一次真实图片生成耗时来设置 Gunicorn `--timeout`、Nginx `proxy_read_timeout`、客户端 read timeout;若尚无真实耗时,部署文档必须显式标注图片同步风险未退,不得声称已验证;生产必须配置真实 `DJANGO_EMAIL_BACKEND` / `DJANGO_DEFAULT_FROM_EMAIL`,否则 allauth 邮箱验证无法发信、用户无法完成登录;**生产静态文件 serving**:T-505 已把 Bootstrap/qrcode 自托管到 `apps/portal/static/`,但 `settings` 目前只有 `STATIC_URL`,`DEBUG=False` 下 Django 不发静态文件——必须配置 `STATIC_ROOT` + `collectstatic` + WhiteNoise 或 Nginx 托管 `/static/`,否则用户端 CSS 错版、充值二维码 404(P2-1 的国内可用性目标在生产失效);**DRF 限流依赖共享缓存**:多 Gunicorn worker 下默认 `LocMemCache` 是每进程的,会让 `generate`/`api_auth_failure` 限流按 worker 各算一份(实际速率≈worker 数×配置值),部署必须配置 Redis/Memcached 等共享 `CACHES` 后端并在文档说明,否则限流形同虚设 | DONE |
|
||||
|
||||
## 里程碑
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
- [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/明文只显一次/到账以回调为权威逐条核对)与优化建议(**零 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 调用模块合约、错误码。
|
||||
- [路由与页面结构](routes.md):API 路由与 django-admin 后台职责。
|
||||
- [环境变量与配置](env.md):Django、数据库、AI 密钥加密、支付、对象存储等配置项。
|
||||
|
||||
+20
-12
File diff suppressed because one or more lines are too long
@@ -0,0 +1,302 @@
|
||||
# 部署 / 运行文档(T-403)
|
||||
|
||||
> 面向 VPS + 宝塔面板 + Nginx + MySQL 8.4 的 MVP 部署说明。本文只写可执行步骤和上线前检查,不保存真实密钥、数据库密码、支付凭证或上游 API Key。
|
||||
|
||||
## 一、部署目标
|
||||
|
||||
生产形态:
|
||||
|
||||
```text
|
||||
公网 HTTPS
|
||||
-> 宝塔 / Nginx
|
||||
/static/ -> STATIC_ROOT
|
||||
/media/ -> MEDIA_ROOT(MVP 本地媒体;后续可换对象存储)
|
||||
/api/v1/generate/* -> Gunicorn 长请求池(图片同步,超时更长)
|
||||
其他路径 -> Gunicorn 普通请求池(用户端 / admin / 余额 / 充值)
|
||||
-> cmhub Django 单体
|
||||
-> MySQL 8.4
|
||||
-> Django shared cache(MVP 可用 MySQL DatabaseCache;高并发换 Redis/Memcached)
|
||||
```
|
||||
|
||||
当前约束:
|
||||
|
||||
- 使用系统 Python 3.12,不使用虚拟环境。
|
||||
- 图片生成仍是同步接口;真实图片生成耗时尚未在生产链路验证,**上线前必须跑一次真实图片 smoke 并记录耗时**。
|
||||
- 真实支付需微信 / 支付宝商户密钥、证书、生产 SDK 与公网回调地址;未配置前只能用 `PAYMENT_CALLBACK_MODE=mock`。
|
||||
|
||||
## 二、系统准备
|
||||
|
||||
1. 安装系统依赖:
|
||||
|
||||
```bash
|
||||
python3.12 --version
|
||||
python3.12 -m pip --version
|
||||
```
|
||||
|
||||
2. 准备 MySQL 8.4:
|
||||
|
||||
- 使用 cmhub 专用 MySQL 8.4 实例,不复用已有 MySQL 5.7。
|
||||
- 默认端口为 `3306`;如果 VPS 上已有 MySQL 占用 3306,则为 cmhub 的 MySQL 8.4 配专用端口,并同步写入 `.env` 的 `MYSQL_PORT`。
|
||||
- 数据库字符集使用 `utf8mb4`,表引擎使用 InnoDB。
|
||||
|
||||
示例 SQL(密码仅占位):
|
||||
|
||||
```sql
|
||||
CREATE DATABASE cmhub CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
CREATE USER 'cmhub'@'%' IDENTIFIED BY 'change-me-strong-password';
|
||||
GRANT ALL PRIVILEGES ON cmhub.* TO 'cmhub'@'%';
|
||||
FLUSH PRIVILEGES;
|
||||
```
|
||||
|
||||
3. 拉取代码到生产目录,例如:
|
||||
|
||||
```bash
|
||||
cd /www/wwwroot
|
||||
git clone <your-remote-url> cmhub
|
||||
cd /www/wwwroot/cmhub
|
||||
```
|
||||
|
||||
## 三、安装依赖
|
||||
|
||||
生产 Linux 安装运行依赖:
|
||||
|
||||
```bash
|
||||
python3.12 -m pip install -r requirements-production.txt
|
||||
```
|
||||
|
||||
如果启用真实支付 SDK,还需按支付 SDK 文档在生产机安装:
|
||||
|
||||
```bash
|
||||
python3.12 -m pip install wechatpayv3 python-alipay-sdk
|
||||
```
|
||||
|
||||
如果暂未提供真实商户配置,不安装支付 SDK 也能以 `PAYMENT_CALLBACK_MODE=mock` 运行本地/测试流程。
|
||||
|
||||
## 四、配置 `.env`
|
||||
|
||||
从样例复制后只在部署机填写真实值:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
生产关键配置:
|
||||
|
||||
```dotenv
|
||||
DJANGO_SECRET_KEY=change-me-to-a-long-random-secret
|
||||
DJANGO_DEBUG=false
|
||||
DJANGO_ALLOWED_HOSTS=cmhub.example.com,127.0.0.1
|
||||
DJANGO_CSRF_TRUSTED_ORIGINS=https://cmhub.example.com
|
||||
DJANGO_TIME_ZONE=Asia/Shanghai
|
||||
|
||||
DJANGO_EMAIL_BACKEND=django.core.mail.backends.smtp.EmailBackend
|
||||
DJANGO_DEFAULT_FROM_EMAIL=noreply@cmhub.example.com
|
||||
DJANGO_SESSION_COOKIE_SECURE=true
|
||||
DJANGO_CSRF_COOKIE_SECURE=true
|
||||
DJANGO_SECURE_PROXY_SSL_HEADER=true
|
||||
DJANGO_SECURE_SSL_REDIRECT=false
|
||||
DJANGO_SECURE_HSTS_SECONDS=0
|
||||
|
||||
MYSQL_HOST=127.0.0.1
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_DATABASE=cmhub
|
||||
MYSQL_USER=cmhub
|
||||
MYSQL_PASSWORD=change-me
|
||||
MYSQL_CHARSET=utf8mb4
|
||||
MYSQL_CONNECT_TIMEOUT=30
|
||||
MYSQL_READ_TIMEOUT=120
|
||||
MYSQL_WRITE_TIMEOUT=120
|
||||
|
||||
STATIC_URL=/static/
|
||||
STATIC_ROOT=/www/wwwroot/cmhub/staticfiles
|
||||
MEDIA_ROOT=/www/wwwroot/cmhub/media
|
||||
MEDIA_URL=/media/
|
||||
|
||||
DJANGO_CACHE_BACKEND=django.core.cache.backends.db.DatabaseCache
|
||||
DJANGO_CACHE_LOCATION=cmhub_cache
|
||||
|
||||
AI_KEY_ENCRYPTION_KEY=base64-fernet-key
|
||||
|
||||
PAYMENT_CALLBACK_MODE=sdk
|
||||
WECHAT_PAY_NOTIFY_URL=https://cmhub.example.com/api/v1/recharge/callback/wechat
|
||||
ALIPAY_NOTIFY_URL=https://cmhub.example.com/api/v1/recharge/callback/alipay
|
||||
```
|
||||
|
||||
生成 Fernet 主密钥:
|
||||
|
||||
```bash
|
||||
python3.12 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
- `AI_KEY_ENCRYPTION_KEY` 生产不可随意更换;更换会导致已加密的 `AiModel.api_key_encrypted` 无法解密。
|
||||
- 生产必须配置真实邮件服务,否则 allauth 邮箱验证邮件发不出,用户无法完成注册登录。
|
||||
- `PAYMENT_CALLBACK_MODE=sdk` 必须配齐微信 / 支付宝商户配置;未配齐时先保持 `mock`。
|
||||
- 宝塔 / Nginx 已强制 HTTPS 时,`DJANGO_SECURE_SSL_REDIRECT=false` 即可;全站 HTTPS 稳定后再把 `DJANGO_SECURE_HSTS_SECONDS` 调大,避免 HSTS 误锁域名。
|
||||
|
||||
## 五、初始化数据库与静态文件
|
||||
|
||||
```bash
|
||||
python3.12 manage.py check
|
||||
python3.12 manage.py migrate
|
||||
python3.12 manage.py createcachetable cmhub_cache
|
||||
python3.12 manage.py collectstatic --noinput
|
||||
python3.12 manage.py createsuperuser
|
||||
```
|
||||
|
||||
如果后续改用 Redis / Memcached,则把 `DJANGO_CACHE_BACKEND` / `DJANGO_CACHE_LOCATION` 换成对应共享后端配置,并安装对应 Python backend 依赖。多 Gunicorn worker 下不要使用默认 `LocMemCache`,否则生成接口和认证失败限流会按 worker 各算一份。
|
||||
|
||||
## 六、导入 AI 模型配置
|
||||
|
||||
真实上游调用前:
|
||||
|
||||
```bash
|
||||
python3.12 manage.py import_ai_models /secure/cmhub/ai_models.json --create-default-aliases
|
||||
```
|
||||
|
||||
要求:
|
||||
|
||||
- `/secure/cmhub/ai_models.json` 不提交到 git。
|
||||
- `AiModel.timeout_seconds` 不能继续依赖默认 `0` 口径上线;图片模型必须按真实耗时设置读取超时。
|
||||
- 运营后台需配置 `PricingRule` 和 `ExchangeRate`,否则生成和充值会因缺规则被拒绝。
|
||||
|
||||
## 七、Gunicorn 运行
|
||||
|
||||
建议把同步图片生成分流到独立 Gunicorn 池,避免长请求占满普通页面和 admin 的 worker。
|
||||
|
||||
普通请求池示例:
|
||||
|
||||
```bash
|
||||
gunicorn config.wsgi:application \
|
||||
--bind 127.0.0.1:8001 \
|
||||
--workers 2 \
|
||||
--worker-class gthread \
|
||||
--threads 4 \
|
||||
--timeout 120 \
|
||||
--access-logfile - \
|
||||
--error-logfile -
|
||||
```
|
||||
|
||||
生成长请求池示例:
|
||||
|
||||
```bash
|
||||
gunicorn config.wsgi:application \
|
||||
--bind 127.0.0.1:8002 \
|
||||
--workers 1 \
|
||||
--worker-class gthread \
|
||||
--threads 4 \
|
||||
--timeout 360 \
|
||||
--access-logfile - \
|
||||
--error-logfile -
|
||||
```
|
||||
|
||||
`--timeout` 必须按真实图片生成耗时校准:`Gunicorn timeout` 应大于 `AiModel.timeout_seconds`,Nginx `proxy_read_timeout` 应大于 Gunicorn timeout,调用方 read timeout 应不小于 Nginx。
|
||||
|
||||
systemd 单元可分别命名为 `cmhub-web.service` 和 `cmhub-generate.service`。服务的 `WorkingDirectory` 指向 `/www/wwwroot/cmhub`,`ExecStart` 使用上面的两条 Gunicorn 命令,环境变量由项目根目录 `.env` 在 Django settings 中读取。
|
||||
|
||||
## 八、宝塔 / Nginx 配置
|
||||
|
||||
宝塔中新建站点并绑定域名和 SSL 后,在站点 Nginx 配置中加入或调整:
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name cmhub.example.com;
|
||||
|
||||
client_max_body_size 25m;
|
||||
|
||||
location /static/ {
|
||||
alias /www/wwwroot/cmhub/staticfiles/;
|
||||
expires 30d;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
location /media/ {
|
||||
alias /www/wwwroot/cmhub/media/;
|
||||
expires 7d;
|
||||
add_header Cache-Control "public";
|
||||
}
|
||||
|
||||
location /api/v1/generate/ {
|
||||
proxy_pass http://127.0.0.1:8002;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 360s;
|
||||
proxy_read_timeout 360s;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8001;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_connect_timeout 30s;
|
||||
proxy_send_timeout 120s;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
说明:
|
||||
|
||||
- `/static/` 必须指向 `STATIC_ROOT`,否则 Bootstrap/qrcode 本地资源在 `DEBUG=False` 下 404。
|
||||
- `/media/` 是 MVP 本地图片结果访问路径;如果改对象存储,应同步更新 `MEDIA_URL` 和存储配置。
|
||||
- 宝塔若已在外层配置 HTTP 到 HTTPS 跳转,`DJANGO_SECURE_SSL_REDIRECT=false` 即可;如果由 Django 负责跳转,再设为 `true`。
|
||||
|
||||
## 九、上线前验证
|
||||
|
||||
基础验证:
|
||||
|
||||
```bash
|
||||
python3.12 manage.py check
|
||||
python3.12 manage.py check --deploy
|
||||
python3.12 manage.py makemigrations --check --dry-run
|
||||
python3.12 manage.py findstatic portal/vendor/bootstrap/bootstrap.min.css portal/vendor/qrcode/qrcode.js --verbosity 1
|
||||
python3.12 manage.py collectstatic --dry-run --noinput
|
||||
```
|
||||
|
||||
账务与用户端测试:
|
||||
|
||||
```bash
|
||||
python3.12 manage.py test apps.billing apps.users --noinput --keepdb --verbosity 2
|
||||
python3.12 manage.py test apps.api --noinput --keepdb --verbosity 2
|
||||
python3.12 manage.py test apps.portal --noinput --keepdb --verbosity 2
|
||||
```
|
||||
|
||||
AI smoke:
|
||||
|
||||
```bash
|
||||
python3.12 manage.py smoke_ai_generation title --recorded
|
||||
python3.12 manage.py smoke_ai_generation image --recorded
|
||||
python3.12 manage.py smoke_ai_generation title
|
||||
python3.12 manage.py smoke_ai_generation image
|
||||
```
|
||||
|
||||
上线前必须记录真实 `image` smoke 的 `elapsed_ms`,并据此回填:
|
||||
|
||||
- 图片 `AiModel.timeout_seconds`
|
||||
- Gunicorn 长请求池 `--timeout`
|
||||
- Nginx `/api/v1/generate/` 的 `proxy_read_timeout`
|
||||
- 接入方客户端 read timeout
|
||||
|
||||
如果真实图片 smoke 仍未跑通,只能按保守值(例如 300s~360s)上线内测,并在发布记录中明确“图片同步真实耗时风险未退”,不能声称已验证生产图片链路。
|
||||
|
||||
## 十、发布检查清单
|
||||
|
||||
- `DJANGO_DEBUG=false`。
|
||||
- `DJANGO_SECRET_KEY`、`AI_KEY_ENCRYPTION_KEY`、MySQL 密码、支付密钥均为生产值且未提交。
|
||||
- `DJANGO_ALLOWED_HOSTS`、`DJANGO_CSRF_TRUSTED_ORIGINS`、微信 / 支付宝 `notify_url` 使用同一 HTTPS 域名。
|
||||
- 邮件后端可发送验证邮件。
|
||||
- HTTPS 已由宝塔 / Nginx 强制跳转;如由 Django 强制跳转则设置 `DJANGO_SECURE_SSL_REDIRECT=true`。HSTS 只在确认全站 HTTPS 后启用。
|
||||
- `STATIC_ROOT` 已 `collectstatic`,Nginx 可访问 `/static/portal/vendor/bootstrap/bootstrap.min.css` 和 `/static/portal/vendor/qrcode/qrcode.js`。
|
||||
- `MEDIA_ROOT` 或对象存储可访问生成图片 URL。
|
||||
- `DJANGO_CACHE_BACKEND` 为共享 cache,不是 `LocMemCache`。
|
||||
- MySQL 是 8.4 / InnoDB / `utf8mb4`。
|
||||
- 真实支付 SDK 与商户配置齐全后,`PAYMENT_CALLBACK_MODE=sdk`。
|
||||
- 真实图片生成耗时已记录并用于设置超时链路;若未记录,发布说明必须标注风险。
|
||||
- `manage.py check`、迁移、静态文件、关键测试和 smoke 均有记录。
|
||||
+25
-3
@@ -21,6 +21,13 @@
|
||||
| `DJANGO_TIME_ZONE` | 否 | `Asia/Shanghai` | 默认按中国业务时区 |
|
||||
| `DJANGO_EMAIL_BACKEND` | 否 | `django.core.mail.backends.console.EmailBackend` | allauth 注册邮箱验证发信后端;生产应改为真实 SMTP / 邮件服务 |
|
||||
| `DJANGO_DEFAULT_FROM_EMAIL` | 生产是 | `noreply@cmhub.example.com` | allauth 邮件默认发件人 |
|
||||
| `DJANGO_SESSION_COOKIE_SECURE` | 生产是 | `true` | 生产 HTTPS 下 session cookie 仅允许安全连接传输 |
|
||||
| `DJANGO_CSRF_COOKIE_SECURE` | 生产是 | `true` | 生产 HTTPS 下 CSRF cookie 仅允许安全连接传输 |
|
||||
| `DJANGO_SECURE_SSL_REDIRECT` | 否 | `false` | 若 Nginx/宝塔已强制 HTTPS,可保持 `false`;若由 Django 强制跳转则设 `true` |
|
||||
| `DJANGO_SECURE_HSTS_SECONDS` | 否 | `31536000` | 全站确认只走 HTTPS 后再启用;未确认前保持 `0`,避免 HSTS 误锁域名 |
|
||||
| `DJANGO_SECURE_HSTS_INCLUDE_SUBDOMAINS` | 否 | `false` | 是否把 HSTS 应用于子域名 |
|
||||
| `DJANGO_SECURE_HSTS_PRELOAD` | 否 | `false` | 是否声明 HSTS preload;提交 preload 前必须确认全部子域长期 HTTPS |
|
||||
| `DJANGO_SECURE_PROXY_SSL_HEADER` | 反代 HTTPS 是 | `true` | Nginx 反代并传 `X-Forwarded-Proto https` 时开启,避免 Django 误判当前请求为 HTTP |
|
||||
|
||||
## 三、数据库配置
|
||||
|
||||
@@ -64,7 +71,18 @@ AI 上游连接超时与读取超时不走全局环境变量:连接超时由 `
|
||||
|
||||
`image_url` 只允许 `http` / `https`,服务端会在请求前解析域名,拒绝私有网段、回环、链路本地、保留地址、组播、未指定地址;重定向后的目标地址也会重复执行同样校验。内网图片不应通过 `image_url` 传入,调用方应改用 `image_base64`。
|
||||
|
||||
## 六、支付配置
|
||||
## 六、静态文件与限流缓存
|
||||
|
||||
| 变量 | 必填 | 示例 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| `STATIC_URL` | 否 | `/static/` | 静态资源 URL 前缀 |
|
||||
| `STATIC_ROOT` | 生产是 | `/www/wwwroot/cmhub/staticfiles` | `collectstatic` 输出目录,Nginx/宝塔需托管此目录 |
|
||||
| `DJANGO_CACHE_BACKEND` | 生产是 | `django.core.cache.backends.db.DatabaseCache` | Django cache 后端;开发可用 locmem,生产多 Gunicorn worker 必须用共享后端 |
|
||||
| `DJANGO_CACHE_LOCATION` | 生产是 | `cmhub_cache` | cache 位置;DatabaseCache 时为表名,Redis/Memcached 时为连接地址 |
|
||||
|
||||
生产限流依赖 Django cache。默认 `LocMemCache` 只适合单进程本地开发;多 worker 部署时每个进程各算一份限流,会放大实际请求速率。MVP 可先用 MySQL 的 `DatabaseCache`,部署时执行 `python3.12 manage.py createcachetable cmhub_cache`;高并发后再换 Redis / Memcached 等共享 cache,并同步安装对应 backend 依赖。
|
||||
|
||||
## 七、支付配置
|
||||
|
||||
| 变量 | 必填 | 示例 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
@@ -95,7 +113,7 @@ AI 上游连接超时与读取超时不走全局环境变量:连接超时由 `
|
||||
|
||||
缺少真实商户配置时,充值任务只能使用 mock 支付客户端;mock 必须在代码和测试中标明,不得伪装成真实支付。
|
||||
|
||||
## 七、对象存储配置
|
||||
## 八、对象存储配置
|
||||
|
||||
图片结果默认返回 URL,避免大 base64 进入同步响应体。对象存储选型未最终落地前,可使用本地开发存储,但生产必须给出可公开访问或可签名访问的 URL。
|
||||
|
||||
@@ -109,11 +127,15 @@ AI 上游连接超时与读取超时不走全局环境变量:连接超时由 `
|
||||
| `S3_ACCESS_KEY_ID` | s3 是 | `change-me` | access key |
|
||||
| `S3_SECRET_ACCESS_KEY` | s3 是 | `change-me` | secret key |
|
||||
|
||||
## 八、上线前检查
|
||||
## 九、上线前检查
|
||||
|
||||
- `DJANGO_DEBUG=false`。
|
||||
- `DJANGO_SECRET_KEY`、`AI_KEY_ENCRYPTION_KEY`、数据库密码、支付密钥均已使用生产值。
|
||||
- `ALLOWED_HOSTS`、`CSRF_TRUSTED_ORIGINS`、支付 `notify_url` 使用同一公网域名。
|
||||
- `STATIC_ROOT` 已执行 `collectstatic`,Nginx/宝塔已托管 `/static/`;若继续用本地媒体存储,也必须托管 `/media/` 或切换对象存储。
|
||||
- `DJANGO_CACHE_BACKEND` 已切到共享后端(如 DatabaseCache / Redis / Memcached),不是默认 `LocMemCache`。
|
||||
- 生产 HTTPS 下 `DJANGO_SESSION_COOKIE_SECURE=true`、`DJANGO_CSRF_COOKIE_SECURE=true`,反代场景按需开启 `DJANGO_SECURE_PROXY_SSL_HEADER=true`。
|
||||
- 全站 HTTPS 稳定后再设置 `DJANGO_SECURE_HSTS_SECONDS`;未确认子域名 HTTPS 前不要启用 includeSubDomains / preload。
|
||||
- MySQL 为 8.4 LTS / InnoDB / `utf8mb4`,不是 SQLite 或已有 MySQL 5.7。
|
||||
- `image_url` 下载上限、生成限流、认证失败限流、单笔充值金额上限已按生产容量调整。
|
||||
- 图片同步链路的客户端、Nginx、Gunicorn、上游 read timeout 均按最慢图片模型放大到同一量级。
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# cmhub 项目介绍(给管理层)
|
||||
|
||||
> 面向决策与汇报的项目概览。技术细节见同目录架构与需求文档。
|
||||
> 日期:2026-07-03 | 阶段:Phase 5 后台与发布(T-402 已完成)
|
||||
> 日期:2026-07-03 | 阶段:Phase 5 后台与发布(计划内 MVP 任务已完成)
|
||||
|
||||
## 一句话概括
|
||||
|
||||
@@ -107,7 +107,8 @@
|
||||
- Phase 4 已完成 T-501~T-505:用户端注册 / 登录(allauth)、邮箱验证、登出、API Key 自助管理、个人中心汇总、充值记录、消费记录和充值页已落地;用户可创建充值订单、查看二维码票据并轮询到账;Key 明文只显示一次,库内只保留 hash 和 prefix,删除即吊销;记录页仅见本人数据并支持分页;Bootstrap 与 qrcode.js 已改为本地 static 自托管。
|
||||
- Phase 5 已完成 T-401:运营后台可管理/检索用户、钱包、API Key(脱敏)、计费规则、汇率、充值订单、点数流水和调用记录;手工调点必须填写原因,并经计费层锁钱包、写 `adjust` 流水。
|
||||
- Phase 5 已完成 T-402:MVP P0 验收通过,注册/充值/API Key/调用/余额/记录/后台/别名映射均有测试证据,详见 `mvp-acceptance.md`。
|
||||
- 下一步是 T-403:补部署 / 运行文档,明确生产静态文件 serving、邮件后端、共享缓存限流、图片同步超时和真实商户配置。
|
||||
- Phase 5 已完成 T-403:已补部署 / 运行文档,明确宝塔/Nginx/Gunicorn、生产静态与媒体文件、真实邮件后端、共享缓存限流、图片同步超时、真实商户配置和上线检查,详见 `deployment.md`。
|
||||
- 下一步是按 `deployment.md` 在 VPS 上配置真实环境,并补跑真实支付和真实 AI 图片耗时验证。
|
||||
|
||||
---
|
||||
*更多细节:愿景 `01-vision.md` | 需求与验收 `02-requirements.md` | 架构 `04-architecture.md` | 任务计划 `06-tasks.md`。*
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
## 进度
|
||||
|
||||
M1 骨架已完成;M2 已通过录制生成 smoke 验证 AI 调用链路;M3 计费、对外 API、充值闭环与上线前安全加固已完成到 T-306;M4 用户端已完成注册 / 登录、API Key 管理、个人中心 / 记录页、充值页和审核优化;M5 已完成 T-401 运营后台完善与 T-402 MVP 完整验收,下一步做 T-403 部署 / 运行文档。里程碑:M1 骨架可跑 · M2 跑通生成 · M3 计费充值闭环 · M4 用户端可用 · M5 验收上线。
|
||||
M1 骨架已完成;M2 已通过录制生成 smoke 验证 AI 调用链路;M3 计费、对外 API、充值闭环与上线前安全加固已完成到 T-306;M4 用户端已完成注册 / 登录、API Key 管理、个人中心 / 记录页、充值页和审核优化;M5 已完成 T-401 运营后台完善、T-402 MVP 完整验收与 T-403 部署 / 运行文档。下一步是在 VPS 上按部署文档接真实邮件、支付、AI 模型并补真实图片耗时验证。里程碑:M1 骨架可跑 · M2 跑通生成 · M3 计费充值闭环 · M4 用户端可用 · M5 验收上线。
|
||||
|
||||
---
|
||||
*详见 `project-brief.md`(完整介绍)。*
|
||||
|
||||
+28
@@ -940,3 +940,31 @@
|
||||
- 已知限制:真实微信/支付宝商户凭证和生产 SDK 未接入;真实 AI 上游 smoke 尚未执行;图片同步真实耗时仍未验证,需在 T-403 部署 / 运行文档中明确超时配置和风险口径。
|
||||
- 决策:T-402 不改业务代码,仅完成验收、口径修正和文档归档;MVP P0 结论为通过。
|
||||
- 下一步:领取 T-403 部署 / 运行文档。
|
||||
|
||||
## 2026-07-03 T-403 部署 / 运行文档
|
||||
|
||||
- 状态:DONE
|
||||
- 变更:
|
||||
- 新增 `docs/deployment.md`:按 VPS / 宝塔 / Nginx / Gunicorn(gthread) / MySQL 8.4 写生产部署步骤,覆盖 `.env`、迁移、`collectstatic`、共享 cache、双 Gunicorn 池、Nginx 分流、上线检查和真实图片耗时验证口径。
|
||||
- 新增 `requirements-production.txt`:Linux 生产运行在基础依赖外追加 Gunicorn,避免 Windows 本地开发强制安装生产 runner。
|
||||
- `config/settings.py`:新增 `STATIC_ROOT`、`STATIC_URL` 环境变量支持;新增 `CSRF_TRUSTED_ORIGINS`;新增 `CACHES` 环境变量配置,生产可用 DatabaseCache / Redis / Memcached 等共享 cache;新增 HTTPS cookie、proxy SSL 与 HSTS 环境变量支持。
|
||||
- `.env.example` / `docs/env.md`:同步新增生产静态、共享 cache、CSRF trusted origins、HTTPS cookie/proxy/HSTS 配置项。
|
||||
- `docs/03-tech-stack.md`:部署方式定为 VPS / 宝塔 + Nginx + Gunicorn(gthread) + systemd,并记录生产安装、cache table、collectstatic 与 Gunicorn 命令。
|
||||
- `docs/04-architecture.md`:修正部署分流路径为实际的 `/api/v1/generate/*`。
|
||||
- 同步更新 `README.md`、`docs/00-ai-start-here.md`、`docs/README.md`、`docs/06-tasks.md`、`docs/current-state.md`、`docs/project-brief.md`、`docs/project-onepager.md`;T-403 标记 DONE,计划内 MVP 任务暂无下一个 TODO。
|
||||
- 验证:
|
||||
- `./init.ps1`:开工前通过。
|
||||
- `py -3.12 manage.py check`:通过,0 issues。
|
||||
- `py -3.12 manage.py makemigrations --check --dry-run`:通过,No changes detected。
|
||||
- `py -3.12 manage.py findstatic portal/vendor/bootstrap/bootstrap.min.css portal/vendor/qrcode/qrcode.js --verbosity 1`:通过,两个本地 static 文件均可发现。
|
||||
- `py -3.12 manage.py check --deploy`:当前开发 `.env` 下只报预期安全配置警告;临时注入生产型安全环境变量(含 HSTS includeSubDomains/preload)后通过,0 issues。
|
||||
- `py -3.12 manage.py collectstatic --dry-run --noinput`:通过,预期收集 169 个 static 文件。
|
||||
- `py -3.12 manage.py createcachetable --dry-run cmhub_cache`:通过,输出 MySQL cache 表 DDL。
|
||||
- `py -3.12 -m compileall config`:通过。
|
||||
- 尝试 `py -3.12 manage.py test apps.api --noinput --keepdb --verbosity 2`:未取得单次全绿;25 条用例通过,`GenerateApiTests` 14 条因远程 MySQL `OperationalError 2013` / 连接重置 / 事务中断被记 ERROR。
|
||||
- `Test-NetConnection 43.128.3.240 -Port 3306`:`TcpTestSucceeded=True`。
|
||||
- `py -3.12 manage.py test apps.api.tests.GenerateApiTests --noinput --keepdb --verbosity 2`:通过,14 tests OK。
|
||||
- 阻塞:T-403 文档与配置支撑无功能阻塞;完整 API 套件单次运行仍受远程 MySQL 间歇断连影响。
|
||||
- 已知限制:真实 AI 上游和真实图片耗时仍未验证,因当前环境未配置 `AI_KEY_ENCRYPTION_KEY` 且数据库无真实 AiModel/ModelAlias;真实微信/支付宝商户配置和 SDK 仍待生产环境提供。`deployment.md` 已明确未跑通真实图片 smoke 前不能声称生产图片链路已验证。
|
||||
- 决策:生产限流共享 cache 的 MVP 推荐路径先用 Django `DatabaseCache` + MySQL cache 表,不引入 Redis 作为当前代码依赖;高并发后可切换 Redis/Memcached 并安装对应 backend。生产静态资源采用 `STATIC_ROOT + collectstatic + Nginx/宝塔托管`,不在应用内引入 WhiteNoise。
|
||||
- 下一步:计划内 MVP 任务已完成;进入 VPS 实际部署、真实邮件/支付/AI 配置和真实图片耗时验证,或从 Backlog 重新拆后续任务。
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
-r requirements.txt
|
||||
|
||||
# Linux production runtime. Keep Windows development on requirements.txt.
|
||||
gunicorn>=23,<24
|
||||
Reference in New Issue
Block a user