docs: refine moderation and signup policy

This commit is contained in:
QiuSW
2026-07-06 10:44:13 +08:00
parent e4565de0c4
commit eedc35cc4b
10 changed files with 225 additions and 16 deletions
+67
View File
@@ -1149,3 +1149,70 @@
- `py -3.12 manage.py test apps.portal.tests.PortalAccountFlowTests.test_recharge_page_requires_login_and_shows_form apps.portal.tests.PortalAccountFlowTests.test_recharge_page_rejects_amount_above_configured_maximum apps.portal.tests.PortalAccountFlowTests.test_recharge_page_rejects_hidden_alipay_submit --keepdb --noinput --verbosity 2`:通过,3 tests OK。
- 线上:同步热修后 `python3.12 manage.py check` 通过,`cmhub-web` / `cmhub-generate` 重启后均为 `active`;修复后的微信 1 分诊断预支付请求返回 `weixin://wxpay/bizpayurl` 票据;用户端表单 choices 仅剩 `微信`,支付宝提交无效。
- 后续:微信下单已通,但线上微信回调曾出现 `PaymentVerificationError`,仍需修复并做真实支付到账闭环;支付宝需在开放平台把 VPS 出口 IP `43.128.3.240` 加入可信 IP 后再恢复页面选项。
## 2026-07-06 需求+方案:中文敏感词本地过滤(T-604,ahocorapy)
- 需求:对中文 prompt 做本地敏感词过滤,命中即在**预扣点之前**拦截(不扣点、不调上游、返回 400 content_blocked)。
- 定位(重要):本地词表 = **免费快筛 + 运营自定义黑名单**,**不替代合规内容审核**。国内 AIGC 上线通常仍需有资质的云内容安全服务;云 API 作为后续可插拔槽位,不在 T-604 范围。
- 选型:匹配引擎用 **`ahocorapy`(纯 Python Aho-Corasick,免编译,VPS 上 pip 一定装得上)**,放弃需编译的 `pyahocorasick`。繁简归一化 `opencc` 可选。
- 方案要点:
1. 接现有 `apps/moderation/` 骨架(provider 接口 + `moderate_input`/`moderate_output_*` 钩子 + fail-closed),本任务把骨架一并转正提交;`MODERATION_ENABLED` 默认 False → no-op,现有测试不受影响。
2. `KeywordModerationProvider`:**先归一化再匹配**(全半角/去空白分隔标点/零宽/大小写/可选繁简)以抗低级绕过;ahocorapy 做子串匹配。
3. `SensitiveWord` 模型(word/category/action/is_active)+ admin 维护 + 迁移。
4. **缓存 matcher**:启动/词库变更时构建自动机缓存内存,信号或版本号失效重建,绝不每请求重建;多 worker 各建各的(只读)。
5. 命中默认 block(脱敏/flag 后续可配);留痕只记分类/词 id,不落违规原文。
6. 可选 `seed_sensitive_words` 命令导开源词库打底,真实词库数据不进仓库。
- 依赖:现有 `apps/moderation/` 骨架(当前未提交),本任务转正;`requirements.txt` 加 `ahocorapy`。
- 待确认(已给默认):本地是「补充」非「替代」云 API(推荐);命中动作默认 block;词库 admin 维护 + 可选 seed。
- 任务:`06-tasks.md` T-604。下一步:实现 T-604(并处理 T-603 的 `ACCOUNT_EMAIL_VERIFICATION` 阻塞)。
## 2026-07-06 决策:永久免邮箱验证(ACCOUNT_EMAIL_VERIFICATION="none")
- 决策:用户端注册**不做邮箱验证**,`ACCOUNT_EMAIL_VERIFICATION="none"` 为**长期既定策略**(不再考虑改回 mandatory)。注册填邮箱 + 密码即注册成功、可直接登录使用。
- 影响:
- 邮箱**仍必填且唯一**(`User.email` unique 约束不变),只是不验证。
- 注册流程**不再发验证邮件**——注册本身不再依赖 SMTP/邮件服务(找回密码等其它邮件功能如启用才需要)。
- 原假设 mandatory 的 2 条 portal 测试(`test_signup_creates_unverified_user_wallet_...`、`test_unverified_email_cannot_establish_login_session`)需**按新策略更新**,不是恢复 mandatory。
- `settings.py` 现为 `"none"#"mandatory"` 的临时写法,需清理成干净的 `"none"`。
- 防刷改由「注册限流 / 图形验证码」补位(邮箱验证不再承担这个作用)。
- 本决策为**全项目权威口径**:`02-requirements`/`05-coding-rules`/`api`/`04-architecture`/`03-tech-stack`/`routes`/`env`/`deployment`/`00-ai-start-here` 中所有「邮箱验证」表述以本决策为准,统一改为「免邮箱验证,邮箱仍唯一」,由 **T-605** 落实。
- T-603 解封路径随之改变:不再「恢复 mandatory」,而是等 T-605 更新测试后重跑标 DONE。
## 2026-07-06 发现+决策:用户端与后台共用会话 → 账号分离(方案 A)
- 发现:portal(`/`)、`/admin/`、`/api/` 挂同一域名/同一 Django 工程,共用同一个 `sessionid` cookie;`/admin/` 不是另一套登录,只是在同一登录态上加 `is_staff=True` 门槛。所以 staff/superuser 账号登了 portal,去 `/admin/` 也是登录态(观察到的「用户端登录后台跟着登」根因)。属单体复用 Django auth 的必然结果,非 bug。
- 澄清:普通用户 `is_staff=False` 登 portal **进不了后台**,无越权、无泄露。
- 决策:采用**方案 A·账号分离(零代码)**——终端用户一律 `is_staff=False`;运营用**专用 admin superuser 只登 `/admin/`,不与 portal 账号混用**。不采用「同账号双会话」(需 admin 独立子域名/独立 cookie,成本高、MVP 不值)。
- 加固(上线前,deployment):`/admin/` 加访问保护(改路径 / IP 白名单 / 反代 basic auth / 2FA),永不给终端用户 `is_staff`。
- 文档落点:`04-architecture.md`(设计事实 + 方案 A)、`05-coding-rules.md`(「用户端与后台账号分离」规则)。属**运营/编码约定,无代码改动**。
## 2026-07-06 T-604 文档方案收紧:本地 prompt 敏感词过滤
- 状态:DONE(文档先行,未改代码)。
- 背景:复核 Claude Code 提出的“提示词敏感词检查”方案后,结论为方向合理,但原方案把本地关键词、云内容安全、输出审核和图片审核混在一起,且现有 `generation.py` 接入顺序存在“先下载 image_url 再审 prompt”的实现风险。
- 变更:
- 新增 `docs/moderation.md`,作为 T-604 权威设计:T-604 只做输入 prompt 本地敏感词快筛;命中必须在扣点和调上游前拦截;云内容安全、输出审核、图片审核后续另做。
- 更新 `docs/06-tasks.md`:T-604 范围收紧为 keyword provider + `SensitiveWord` + matcher 缓存 + 共享 cache 版本号失效;明确 `ahocorapy` 只是候选依赖,编码前必须验证 PyPI 可用性和 API 形状。
- 更新 `docs/04-architecture.md`:新增内容安全层职责、`SensitiveWord` 配置数据、prompt 先审再下载图片/计费的时序,以及多 worker 下不能只依赖 Django signal。
- 更新 `docs/api.md`:补 `content_blocked` 错误码,明确命中不扣点、不写调用/流水、不调上游,也不得先下载 `image_url`。
- 更新 `docs/env.md`:补 `MODERATION_ENABLED`、`MODERATION_PROVIDER`、`MODERATION_FAIL_CLOSED`、`MODERATION_BLOCK_ON_REVIEW`、`MODERATION_CACHE_VERSION_KEY` 等配置,并说明生产依赖共享 cache。
- 更新 `docs/05-coding-rules.md` 与 `docs/README.md`:加入内容安全顺序规则和文档导航。
- 决策:
- T-604 不启用输出审核;`MODERATION_REFUND_ON_OUTPUT_BLOCK` 不作为 T-604 交付项,避免配置存在但行为未实现。
- `SensitiveWord.action` MVP 只支持 `block`,后续再扩展 `review` / `flag`。
- 词库变更后用共享 cache 版本号让各 worker 懒重建 matcher,不能只靠 `post_save` / `post_delete` signal。
- 验证:文档修改;未运行代码测试。
- 下一步:实现 T-604 时先清理 `apps/moderation/__pycache__`,把 `apps.moderation` 接入 `INSTALLED_APPS`,再按 `docs/moderation.md` 落模型、admin、provider、缓存和测试。
## 2026-07-06 复核:codex 更新的 T-604 敏感词方案(Claude Code review,非任务)
- 对象:codex 审核并扩写的中文 prompt 敏感词方案(新增 `docs/moderation.md`,更新 `04-architecture`/`api`/`05-coding-rules`/`06-tasks`/`env`/`README`)。
- 结论:**合理,且是明显改进,可放行**。
- codex 改对/改好:
- 范围收紧为「只审 prompt 文本」,砍掉 skeleton 里对输入图片做关键词匹配(无意义)。
- 请求时序:审 prompt 在下载 image 之前,命中即不下载图片/不别名/不计费/不调上游。
- 多 worker 缓存失效用共享 cache 版本号(`moderation:sensitive_words:version`),点破 post_save signal 只在当前进程生效——与 T-403 限流共享 cache 口径一致。
- 「ahocorapy 编码前必须验证 PyPI 可用性和 API 形状」——先核实真实 API 的纪律。
- 诚实标注归一化误伤风险并要求正常文本测试;不暴露未实现的输出审核配置。
- 实现时须盯的一点(skeleton 与新规格冲突,非文档错):现有未提交的 `generation.py` skeleton 是「先 load_image_input 再 moderate_input(含 image)」+ 有 output 钩子;T-604 实现必须按新规格翻正——① prompt 审核挪到图片下载之前;② moderate_input 改纯 prompt;③ 去掉/休眠 output 钩子与未实现的退点配置。
- 小注意(codex 已自标、可接受):归一化误伤需正常文本测试兜底;每请求一次共享 cache 版本检查(DatabaseCache 为一次 DB 读)。