chore: Phase 4 收尾——部署工件齐备,项目四阶段完成

Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
浅念
2026-10-14 13:45:14 +08:00
parent 7cdb4fc970
commit dcf9d4b54c
3 changed files with 47 additions and 20 deletions
+25 -7
View File
@@ -49,7 +49,7 @@
**安全自查**(读码 + 定向测试 28 条全绿:test_auth / test_admin_mounting / test_avatar_upload / test_host_routing): **安全自查**(读码 + 定向测试 28 条全绿:test_auth / test_admin_mounting / test_avatar_upload / test_host_routing):
- **密码/token 不进日志**:app/platform/ 全层**零 logger 调用**(干净由构造保证);main.py 启动日志仅静态串 + slug/db 路径;引擎层(Phase 1 既有)日志参数为会话内容摘录/session_id/notify_emails,无凭据字段。 - **密码/token 不进日志**:app/platform/ 全层**零 logger 调用**(干净由构造保证);main.py 启动日志仅静态串 + slug/db 路径;引擎层(Phase 1 既有)日志参数为会话内容摘录/session_id/notify_emails,无凭据字段。
- **gitignore 覆盖复核**(git check-ignore 实证全命中):`tenants/*.db{,-wal,-shm}`(租户库实际落 `tenants/<slug>.db`)、`platform.db{,-wal,-shm}`(仓库根)、`data/`(含 `data/uploads/` 上传卷)。 - **gitignore 覆盖复核**(git check-ignore 实证全命中):`tenants/*.db{,-wal,-shm}`(租户库实际落 `tenants/<slug>.db`)、`data/`(含 `data/uploads/` 上传卷)。platform.db 位置注记(Phase 4 修正):**现落 `data/platform.db`,由 `data/` 规则覆盖**(main.py PLATFORM_DB 与 compose bind mount 钉死,P4T1 审查修复);.gitignore 根级 `platform.db*` 三条为历史留存,无害。
- **登录限流在 /api/platform 豁免路径仍生效**:host_middleware 对 `/api/platform/` 前缀的豁免只跳过**租户解析**,认证守护在路由依赖;登录限流先于密码验证(锁定期内正确密码也 429)。测试钉位:test_auth.py::test_login_lockout_after_5_fails + test_admin_mounting.py::test_platform_api_bypasses_tenant_resolution / test_platform_prefix_not_open / test_prefix_match_precise。 - **登录限流在 /api/platform 豁免路径仍生效**:host_middleware 对 `/api/platform/` 前缀的豁免只跳过**租户解析**,认证守护在路由依赖;登录限流先于密码验证(锁定期内正确密码也 429)。测试钉位:test_auth.py::test_login_lockout_after_5_fails + test_admin_mounting.py::test_platform_api_bypasses_tenant_resolution / test_platform_prefix_not_open / test_prefix_match_precise。
- **上传目录不可执行**:上传只认魔数(png/jpg/webp)+ uuid 重命名落盘——.py 文件无进无出;avatar 下发(public.py)取 PurePosixPath.name 并显式拒绝 `/` `\` 与目录点(防 Windows 反斜杠穿透),FileResponse content-type 由扩展名映射(只可能 image/*)。 - **上传目录不可执行**:上传只认魔数(png/jpg/webp)+ uuid 重命名落盘——.py 文件无进无出;avatar 下发(public.py)取 PurePosixPath.name 并显式拒绝 `/` `\` 与目录点(防 Windows 反斜杠穿透),FileResponse content-type 由扩展名映射(只可能 image/*)。
@@ -102,8 +102,8 @@
8. **contact.template_languages 运行期接线**——后台批次(出处:配置 schema 审查)。 8. **contact.template_languages 运行期接线**——后台批次(出处:配置 schema 审查)。
9. **话术含引号/换行的转义**——编辑器批次(`_format_deflection_pool` docstring 有注)。 9. **话术含引号/换行的转义**——编辑器批次(`_format_deflection_pool` docstring 有注)。
10. **产品决策项**:国名纠正 e164 变化时是否补发更正邮件(上游行为更优);REST/WS 服务端 IP 口径是否统一(出处:上游吸收审查)。 10. **产品决策项**:国名纠正 e164 变化时是否补发更正邮件(上游行为更优);REST/WS 服务端 IP 口径是否统一(出处:上游吸收审查)。
11. **/health 分级健康**——Phase 4 部署批次(进程存活之外按依赖分级上报;出处:终审审查 M-3)。 11. ~~/health 分级健康~~(Phase 4 Task 1 完成:`/health` 返回 status/tenants(engine_ok 三态)/domains 分级 JSON——单租户库损坏 degraded 仍 200 不杀容器;compose healthcheck 消费同一端点,Phase 4 终验 docker 演练实测与手册 §2 解读一致)。
12. **PromptProvider.from_dir 的 FileNotFoundError 带路径上下文**——提示词目录缺失时异常信息含实际路径(出处:终审审查 M-4)。 12. ~~PromptProvider.from_dir 的 FileNotFoundError 带路径上下文~~(现状即满足:`read_text` 原生 FileNotFoundError 自带完整路径——终验实测 `PromptProvider.from_dir` 指向缺失目录时异常信息为 `[Errno 2] No such file or directory: '<完整路径>/system.md'`;DB 源路径另有 tenant_source 显式包装注记)。
## Phase 3 完成状态(2026-10-13 收尾核对) ## Phase 3 完成状态(2026-10-13 收尾核对)
@@ -142,16 +142,30 @@
- **admin 域名反代区分**:`/api/platform/*` 前缀豁免租户 Host 解析——平台后台 API 可与租户聊天域名同源反代(按路径分流)或独立域名,两形态皆可;租户聊天面(`/`、`/static`、WS、`/api/public`、`/api/chat*`)仍严格按 Host 解析租户,未知 Host 404。 - **admin 域名反代区分**:`/api/platform/*` 前缀豁免租户 Host 解析——平台后台 API 可与租户聊天域名同源反代(按路径分流)或独立域名,两形态皆可;租户聊天面(`/`、`/static`、WS、`/api/public`、`/api/chat*`)仍严格按 Host 解析租户,未知 Host 404。
- **ADMIN_PASSWORD 默认值警示**(终审 I-4):lifespan 启动检测到 ADMIN_PASSWORD 仍是出厂默认(admin123)时打 WARNING 日志——生产部署必须设 ADMIN_PASSWORD 环境变量换掉,且超管首登立即改密(must_change_password 门强制)。 - **ADMIN_PASSWORD 默认值警示**(终审 I-4):lifespan 启动检测到 ADMIN_PASSWORD 仍是出厂默认(admin123)时打 WARNING 日志——生产部署必须设 ADMIN_PASSWORD 环境变量换掉,且超管首登立即改密(must_change_password 门强制)。
- **Phase 4 清理单增补**(Phase 3 冒烟沉淀 + 终审记档;Phase 3 清理单未结项 5/6/8/9/10 一并滚入): - **Phase 4 清理单增补**(Phase 3 冒烟沉淀 + 终审记档;Phase 3 清理单未结项 5/6/8/9/10 一并滚入):
1. `components.d.ts` 构建行尾漂移(长期收口 = 生成物出库或 EOL 规范钩子,现阶段靠手工还原)。 1. `components.d.ts` 构建行尾漂移(长期收口 = 生成物出库或 EOL 规范钩子,现阶段靠手工还原)。**收档(已知现状非缺陷,2026-10-14 终验)**:build/dev 重写入库 dts 仅行尾差异(`components.d.ts` 与 `auto-imports.d.ts` 两文件同性状,终验 pnpm build 再证实)——`git diff --ignore-cr-at-eol` 为空即 `git checkout --` 还原,勿提交行尾噪音。
2. 推送探测 env 回退真址:租户 push URL 空槽时 `resolve_push_settings` 回退 env `PUSH_API_URL`(默认即真 UniService 生产址)——后台点「探测」会对真实服务发空批量 POST(`{"messages": []}`,按契约文档应为无操作,但属真实出站)。收口 = 部署设 stub 域或探测端点拒绝 env 回退 URL。 2. 推送探测 env 回退真址:租户 push URL 空槽时 `resolve_push_settings` 回退 env `PUSH_API_URL`(默认即真 UniService 生产址)——后台点「探测」会对真实服务发空批量 POST(`{"messages": []}`,按契约文档应为无操作,但属真实出站)。**收档(已知现状非缺陷,2026-10-14 终验)**:处置 = 介意真实出站则生产 .env 将 PUSH_API_URL 指 stub 域后再点探测。
3. 生产反代需规划 admin 域的头像/品牌公开端点:`/api/public/*` 按租户 Host 解析,admin 域直挂必 404——开发期靠 Vite Host 改写代理,生产要么同源反代改 Host(单租户形态)要么前端改用租户域名绝对 URL。 3. 生产反代需规划 admin 域的头像/品牌公开端点:`/api/public/*` 按租户 Host 解析,admin 域直挂必 404——开发期靠 Vite Host 改写代理,生产要么同源反代改 Host(单租户形态)要么前端改用租户域名绝对 URL。**收档(已知现状非缺陷,2026-10-14 终验)**:处置 = 生产选形态 B(租户域名路径分流)即规避;坚持形态 A 则接受预览缺失(页内本地简化预览兜底,手册 §3.3 已注记)。
4. `VITE_TENANT_PREVIEW_HOST` 单一预览域名:开发代理只指向一个租户 Host,切换租户时头像等公开资源预览不准(.env.development 已注记)。 4. `VITE_TENANT_PREVIEW_HOST` 单一预览域名:开发代理只指向一个租户 Host,切换租户时头像等公开资源预览不准(.env.development 已注记)。**收档(已知现状非缺陷,2026-10-14 终验)**:仅影响开发期预览,切租户时改 .env.development 预览 Host 重启 dev server 即可。
5. ~~resolver 平台默认回退链接入 platform_settings~~(Phase 4 Task 5A 完成:`app/platform/settings_store.py` 内存快照 + lifespan 装载 + PUT settings 后 refresh 热刷新;config_views 的 email/ai 两组改三级回退(租户槽位 → 平台设置快照 → env),push 无平台推荐键保持两级;平台设置页"仅存储"注记移除)。 5. ~~resolver 平台默认回退链接入 platform_settings~~(Phase 4 Task 5A 完成:`app/platform/settings_store.py` 内存快照 + lifespan 装载 + PUT settings 后 refresh 热刷新;config_views 的 email/ai 两组改三级回退(租户槽位 → 平台设置快照 → env),push 无平台推荐键保持两级;平台设置页"仅存储"注记移除)。
6. ~~email/test 与 push/test 速率限制~~(Phase 4 Task 5B 完成:config_routes 内 `SlidingWindowCounter` 滑动窗限流(登录限流器同款风格),每租户每类端点 15 分钟 5 次真实出站,超限 429;校验失败/未配置 400 不消耗预算,超限后 429 优先于一切预检)。 6. ~~email/test 与 push/test 速率限制~~(Phase 4 Task 5B 完成:config_routes 内 `SlidingWindowCounter` 滑动窗限流(登录限流器同款风格),每租户每类端点 15 分钟 5 次真实出站,超限 429;校验失败/未配置 400 不消耗预算,超限后 429 优先于一切预检)。
7. ~~锁屏功能已摘除入口~~ + ~~通知组件摘除~~(锁屏 Phase 3 摘入口,Phase 4 Task 5F 删代码:art-screen-lock/art-notification 组件目录、component.ts/headerBar.ts 配置项、useHeaderBar.shouldShowNotification、类型字段、components.d.ts 条目、crypto-js 依赖(env.d.ts 声明/package.json/optimizeDeps/lockfile)、en/zh 孤儿语言键全部清除,grep 零残留)。 7. ~~锁屏功能已摘除入口~~ + ~~通知组件摘除~~(锁屏 Phase 3 摘入口,Phase 4 Task 5F 删代码:art-screen-lock/art-notification 组件目录、component.ts/headerBar.ts 配置项、useHeaderBar.shouldShowNotification、类型字段、components.d.ts 条目、crypto-js 依赖(env.d.ts 声明/package.json/optimizeDeps/lockfile)、en/zh 孤儿语言键全部清除,grep 零残留)。
8. ~~租户切换器 composable 收拢~~(Phase 4 Task 5E 完成:`admin/src/composables/useTenantOptions.ts` 收拢会话/配置/统计三页租户下拉(默认形态选中首个 + bootstrapTenantContext 引导;stats 用 selectFirst:false 纯数据源);dashboard 卡片墙形态不在此列)。 8. ~~租户切换器 composable 收拢~~(Phase 4 Task 5E 完成:`admin/src/composables/useTenantOptions.ts` 收拢会话/配置/统计三页租户下拉(默认形态选中首个 + bootstrapTenantContext 引导;stats 用 selectFirst:false 纯数据源);dashboard 卡片墙形态不在此列)。
9. ~~ECharts 按需收窄~~(Phase 4 Task 5D 完成:echarts.use 收窄为 Bar/Line/Pie + Title/Tooltip/Grid/Legend + CanvasRenderer——全仓 grep 证实存活消费方仅 stats 页与 useChart;echarts chunk 767,864 B → 559,737 B(-27%),dist 总体积 -273 KB)。 9. ~~ECharts 按需收窄~~(Phase 4 Task 5D 完成:echarts.use 收窄为 Bar/Line/Pie + Title/Tooltip/Grid/Legend + CanvasRenderer——全仓 grep 证实存活消费方仅 stats 页与 useChart;echarts chunk 767,864 B → 559,737 B(-27%),dist 总体积 -273 KB)。
## Phase 4 完成状态(2026-10-14 收尾核对)
**测试基线:后端 pytest 630 passed + 2 skipped / 前端 vitest 164 passed**(后端根目录与 tests/ 子目录各跑一遍数字一致;唯一 warning 仍为 starlette TestClient 弃用提示,无害)。`pnpm build`(vue-tsc --noEmit && vite build)与 `docker compose build`(两阶段)复验零错误。**docker 演练终检实测**:`up -d` 后 healthcheck 约 20s 转 healthy → bootstrap(run --rm 形态)输出与手册 §2 逐字吻合 → 重启后 `/health` 分级 JSON 与手册示例一致(status=ok、两租户 active、domains=3、engine_ok null 属懒建正常态)→ `/admin/` 200 → down 后 data/ 演练产物删净、tenants/ 清空、无容器/网络残留。演练顺带核实:**容器运行中跑 bootstrap 不热刷新内存租户注册表**(/health 需重启才反映,手册 §6.6 已补注记;首次部署按 §2 顺序无此问题)。**项目四阶段至此全部完成,此为最终回归基线。**
**部署工件清单**(全部入库,上线路径自足):
- `Dockerfile`:两阶段构建(node:20-alpine 编译 admin dist → python:3.13-slim 运行时含 tzdata;服务器零 Python/node 依赖)。
- `docker-compose.yml`:`name: all-kefu`(防 1Panel 目录撞名互删);`./data` + `./tenants` 双 bind mount——**platform.db 在 data/ 卷内**(`data/platform.db`,容器重建不丢,P4T1 审查修复);healthcheck 用容器内 python urllib(slim 无 curl);json-file 日志封顶 10m×3;mem_limit 768m;`--workers 1` 钉死。
- `deploy/openresty-all-kefu.conf.template`:反代模板(多域名同 upstream、WS 升级头单套、1Panel include 行坑注记)。
- `docs/deploy-production.md`:runbook 工件(.env 逐项 / 首次部署 / 反代三件事 / 存量迁移对账 / 切换 runbook 四阶段 / 备份恢复演练 / 归档 / 踩坑实录 13 条;手册为 runbook 工件非实录,首次部署前按全局部署 SOP 与用户确认)。
- `scripts/` 四件:`bootstrap_platform.py`(幂等引导 schema+超管+出厂租户)、`import_legacy.py`(老库只读导入+四元组对账)、`archive.py`(push_logs 归档)、`breach_rate.py`(破防率观测,`--tenant` 多租户适配,Task 5 随迁)。
**上线前检查清单(浓缩版;命令与细节见手册)**:生产 .env 设 ADMIN_PASSWORD 等强凭据 → `docker compose build` → `docker compose run --rm app python scripts/bootstrap_platform.py` → `docker compose up -d` → `/health`(status=ok、domains=3)→ `/admin/` 超管首登强制改密、后台补租户管理员 → 1Panel 反代片段备好(Host 头 / WS 单套 / 5m 三件事,先不指流量)→ 老库导入对账(手册 §4)→ 隧道+hosts 全功能验证(清单见手册 §5 阶段一)→ 逐域名切流(先一切半观察再切二)→ 观察一周(日检清单 + breach_rate)→ 老项目停用归档(stop 不 rm,回滚预案在手册 §5)。
## 文档索引 ## 文档索引
- 设计文档(spec):`docs/superpowers/specs/2026-10-12-unified-kefu-platform-design.md` - 设计文档(spec):`docs/superpowers/specs/2026-10-12-unified-kefu-platform-design.md`
@@ -160,3 +174,7 @@
- Phase 3 实施计划:`docs/superpowers/plans/2026-10-13-phase3-admin-spa.md` - Phase 3 实施计划:`docs/superpowers/plans/2026-10-13-phase3-admin-spa.md`
- Phase 4 实施计划:`docs/superpowers/plans/2026-10-14-phase4-deploy-migration.md` - Phase 4 实施计划:`docs/superpowers/plans/2026-10-14-phase4-deploy-migration.md`
- 部署手册(含切换 runbook + 踩坑实录):`docs/deploy-production.md`;反代模板 `deploy/openresty-all-kefu.conf.template` - 部署手册(含切换 runbook + 踩坑实录):`docs/deploy-production.md`;反代模板 `deploy/openresty-all-kefu.conf.template`
## 项目完成总结(2026-10-14,四阶段收官)
ai-kefu / ai-kefu-jc 两套复制分叉代码 → 统一多租户平台,四个阶段全部完成:Phase 1 引擎合并与租户化(2026-10-12)、Phase 2 平台层(10-13)、Phase 3 管理后台 SPA(10-13)、Phase 4 部署与迁移工件(10-14)。历程数字:**测试 315 → 630+2skip(后端)+ 164(前端 vitest)**;终审环节抓出并当场收口的关键缝隙三例——**墙的执行侧缺口**(词表配置齐但执行路径未全量消费)、**站点停用语义**(停用租户的存量管理员 token 存活窗口与聊天面 503 边界)、**密钥掩码旁路**(GET 掩码但 PUT/回滚路径可绕过哨兵契约)——审查纪律的价值注脚。**后续演进方向**(均为增量,不动四层架构):提示词沙箱试聊(后台配置中心直接对话验证词表/提示词效果)、推送失败告警(lead_push 连续失败主动通知,当前只有推送健康表被动展示)、单租户独立部署路径已预留(engine 包不感知 platform,可整体拎走单租户跑)。
+9 -9
View File
@@ -1,16 +1,16 @@
# all-kefu # all-kefu
统一多租户 AI 客服平台:一套引擎 + 租户配置包,消除此前"每客户复制一套代码"的分叉模式。项目由 ai-kefu / ai-kefu-jc 两个复制分叉项目合并而来(jc 为主线),Phase 1 引擎合并与租户化改造、Phase 2 平台层(platform.db + admin API)、Phase 3 管理后台 SPA 均已完成。 统一多租户 AI 客服平台:一套引擎 + 租户配置包,消除此前"每客户复制一套代码"的分叉模式。项目由 ai-kefu / ai-kefu-jc 两个复制分叉项目合并而来(jc 为主线),**四个阶段已全部完成**(2026-10-14 收官):Phase 1 引擎合并与租户化、Phase 2 平台层(platform.db + admin API)、Phase 3 管理后台 SPA、Phase 4 部署与迁移工件。
**现状能力**(Phase 3 收尾时点): **能力总览(四层)**:
- 多租户引擎:TenantRuntime 隔离边界,engine 包不感知平台层,可整体拎走独立部署。 - **引擎层**(`app/engine/`,不感知平台层、可整体拎走单租户独立部署):TenantRuntime 租户隔离;cc 区号补全判定树、多语言墙(中/西/葡借道/俄/阿)、dual-contact 分步双要、CC 强制墙;lead 邮件推送与 UniService 询盘推送;Host 路由(未知 Host 404)+ WS 租户化 client key 防串库 + 每 IP 连接上限。
- 站点模型:一租户多站点(品牌/主题/站点级覆盖),词表、提示词、品牌全部配置化;配置存 platform.db 版本快照(分组校验 / 回滚 / 热加载),seed_profiles 为出厂档案与测试形态。 - **平台层**(`app/platform/`):scrypt 认证 + 登录限流 + 角色两级(超管/租户管理员);租户管理(创建向导/站点/域名/停用);配置版本管线(分组校验/整组替换/回滚/重置出厂/试金石/热加载);头像上传(魔数校验);数据视图与统计(逐租户库聚合禁 ATTACH);密钥掩码哨兵(`__SET__` 往返);平台设置三级回退(租户槽位 → 平台设置 → env)。
- Host 路由:按域名解析租户,未知 Host 404;WS 通道租户化客户端 key 防串库,另有限流与每 IP 连接上限。 - **管理后台**(`admin/`,Vue3 + TS + Element Plus SPA):登录/强制改密/角色化菜单;仪表盘;租户管理;会话与线索(消息流/推送日志);配置中心(品牌/提示词词表/试金石/凭据掩码编辑 + SMTP 测试 + 推送探测/通用 JSON 组/版本对比回滚);统计分析(ECharts 按需收窄);平台设置。admin API 全在 `/api/platform` 前缀,端点清单见 [CLAUDE.md](CLAUDE.md)。
- 引擎行为:cc 区号补全判定树、多语言墙(中/西/葡借道/俄/阿)、dual-contact 分步双要、CC 强制墙、lead 邮件推送。 - **部署工件**:`Dockerfile`(两阶段:node 编译前端 → python:3.13-slim 运行时)、`docker-compose.yml`(`name: all-kefu`,data/ + tenants/ 双 bind mount,healthcheck/日志封顶/内存限额)、`deploy/openresty-all-kefu.conf.template`(反代模板)、`scripts/{bootstrap_platform,import_legacy,archive,breach_rate}.py`(引导/存量迁移/归档/破防率观测四件)。
- 平台层:scrypt 认证 + 内存 token + 登录限流;租户管理(创建向导 / 站点 / 域名 / 停用);配置版本管线(整组替换 / 回滚 / 重置出厂 / 试金石);头像上传(魔数校验 + uuid 重命名);数据视图(会话 / 推送日志 / 删除,租户 scope 强制);统计(卡片 / 漏斗 / 趋势 / 分布 / 推送健康,逐库聚合禁 ATTACH);密钥掩码哨兵(`__SET__` 往返);DB 源生产装配(TENANT_SOURCE=db 默认 + bootstrap_platform.py 引导)。admin API 全在 `/api/platform` 前缀(Host 豁免、路由依赖守护),端点清单见 [CLAUDE.md](CLAUDE.md)。
- 管理后台 SPA(Phase 3,`admin/` 目录,Vue3 + Element Plus + pnpm):登录 / 强制改密 / 角色化菜单(超管 vs 租户管理员);仪表盘(平台总览 + 租户卡片墙 / 我的指标);租户管理与站点域名;会话与线索(筛选 / 详情消息流 / 推送日志 / 删除);配置中心(品牌 + 本地预览 + 嵌入代码 + 头像上传 / 提示词词表 / 试金石 / 凭据掩码编辑 + SMTP 测试 + 推送探测 / contact·engine·misc 通用 JSON 编辑 / 版本对比回滚重置);统计分析(ECharts 漏斗 / 趋势 / 分布 / 推送健康);平台设置(ai.* / smtp.* 推荐键 KV 表单 + 存储总览,现阶段仅存储不接引擎回退链)。
**本地跑法**:后端 `PYTHONUTF8=1 .venv/Scripts/python -m uvicorn app.main:app --port 8018 --workers 1`;管理后台 `cd admin && pnpm install && pnpm dev`(Vite 代理 /api → 8018)。工作约定与测试基线(后端 pytest 595 / 前端 vitest 156)见 [CLAUDE.md](CLAUDE.md)。 **上线指引**:见部署手册 [docs/deploy-production.md](docs/deploy-production.md)(.env 逐项说明、首次部署流程、1Panel 反代三件事、老项目存量迁移与对账、切换 runbook 四阶段、备份恢复演练、踩坑实录 13 条)。上线前浓缩清单与工件核验记录见 [CLAUDE.md](CLAUDE.md) Phase 4 完成状态段。
**本地跑法**:后端 `PYTHONUTF8=1 .venv/Scripts/python -m uvicorn app.main:app --port 8018 --workers 1`(`--workers 1` 为硬约束);管理后台 `cd admin && pnpm install && pnpm dev`(Vite 代理 /api → 8018)。工作约定与最终测试基线(后端 pytest 630 passed + 2 skipped / 前端 vitest 164 passed)见 [CLAUDE.md](CLAUDE.md)。
设计文档(spec):[docs/superpowers/specs/2026-10-12-unified-kefu-platform-design.md](docs/superpowers/specs/2026-10-12-unified-kefu-platform-design.md) 设计文档(spec):[docs/superpowers/specs/2026-10-12-unified-kefu-platform-design.md](docs/superpowers/specs/2026-10-12-unified-kefu-platform-design.md)
+13 -4
View File
@@ -1,7 +1,8 @@
# all-kefu 生产部署手册(含切换 runbook) # all-kefu 生产部署手册(含切换 runbook)
> 对应工件:`Dockerfile`(两阶段构建)、`docker-compose.yml`(`name: all-kefu`)、 > 对应工件:`Dockerfile`(两阶段构建)、`docker-compose.yml`(`name: all-kefu`)、
> `deploy/openresty-all-kefu.conf.template`(反代模板)、`scripts/{bootstrap_platform,import_legacy,archive}.py`。 > `deploy/openresty-all-kefu.conf.template`(反代模板)、
> `scripts/{bootstrap_platform,import_legacy,archive,breach_rate}.py`。
> 本文是 **runbook 工件**(Phase 4 交付),不是已执行实录——首次实际部署到阿里云前, > 本文是 **runbook 工件**(Phase 4 交付),不是已执行实录——首次实际部署到阿里云前,
> 按用户全局部署 SOP(`~/.claude/memory/general-deployment-sop.md` + 全局 CLAUDE.md 规程) > 按用户全局部署 SOP(`~/.claude/memory/general-deployment-sop.md` + 全局 CLAUDE.md 规程)
> 与用户确认环境与流程后再动手。 > 与用户确认环境与流程后再动手。
@@ -303,9 +304,14 @@ ssh -L 8018:127.0.0.1:8018 root@47.254.176.10 # 隧道保持
- [ ] `/health` 无 degraded(有 = 对应租户库问题,立刻查) - [ ] `/health` 无 degraded(有 = 对应租户库问题,立刻查)
- [ ] 后台"统计 → 推送健康"成功率正常(与切换前老平台口径对比) - [ ] 后台"统计 → 推送健康"成功率正常(与切换前老平台口径对比)
- [ ] 询盘邮件正常到达(单邮件通道,SMTP 失败不自动补发,头几天盯收件) - [ ] 询盘邮件正常到达(单邮件通道,SMTP 失败不自动补发,头几天盯收件)
- [ ] **breach_rate 双向偏差观察**(沿用 jc 观察法):脚本在老仓 - [ ] **breach_rate 双向偏差观察**(沿用 jc 观察法):脚本**已随迁**至本仓
`ai-kefu-jc/scripts/breach_rate.py`(**本仓未随迁**——观察期从老仓取用, `scripts/breach_rate.py`(多租户适配:`--tenant` 必填,经 platform.db
对 `tenants/<slug>.db` 直跑;漏放/误杀残差与 jc 期基线对比) 门禁后只读打开 `tenants/<slug>.db`,默认路径与容器挂载对齐,零额外参数):
```bash
docker compose run --rm app python scripts/breach_rate.py --tenant jiancai
# 容器已起时也可 exec 形态:docker compose exec app python scripts/breach_rate.py --tenant jiancai
```
(漏放/误杀残差与 jc 期基线对比;误杀侧不在脚本口径,用后台会话详情人工复核)
- [ ] 磁盘与日志:`df -h`、`docker stats all-kefu-app-1 --no-stream` - [ ] 磁盘与日志:`df -h`、`docker stats all-kefu-app-1 --no-stream`
(内存应显著低于 768m 限额)、`docker logs all-kefu-app-1 --tail 100` (内存应显著低于 768m 限额)、`docker logs all-kefu-app-1 --tail 100`
@@ -411,6 +417,9 @@ curl -s http://127.0.0.1:8018/health
`docker compose run --rm app python scripts/bootstrap_platform.py` 幂等: `docker compose run --rm app python scripts/bootstrap_platform.py` 幂等:
已存在 slug 的租户跳过、超管空表才建——发版后跑一遍无副作用(也可不跑, 已存在 slug 的租户跳过、超管空表才建——发版后跑一遍无副作用(也可不跑,
lifespan 启动同样保证 schema/超管就绪,两者同一套幂等实现)。 lifespan 启动同样保证 schema/超管就绪,两者同一套幂等实现)。
注意:**容器运行中跑 bootstrap 不会热刷新内存租户注册表**——`/health`
仍显示旧租户列表,重启容器(`docker compose restart app`)后才反映;
首次部署按 §2 顺序(bootstrap 先于 up)则无此问题。
## 7. 踩坑实录(排查手册——每条都是真事故/真审查发现) ## 7. 踩坑实录(排查手册——每条都是真事故/真审查发现)