Commit Graph

174 Commits

Author SHA1 Message Date
浅念 6d6d8a8e32 chore: Batch 4 收口——终审 Minor 处置记档 + WallAdvanced 注释修正
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 21:56:02 +08:00
浅念 1df1fc7922 fix(admin): 重建 watch 补 slug 源(防缺组租户切换草稿泄漏)
c6bd542 拆分后的分组 watch 只盯组 props 引用——seed 租户快照可能缺组
(如无 ai/contact/misc 组),两家租户都缺时切租户该组 prop 走
undefined→undefined 引用不变、watch 不触发,上一家租户的草稿留在当前
租户界面(dirty 也残留)。旧的全量耦合顺带防住了它,拆分后暴露。

修复:六个 pane 的重建 watch 源统一加 () => props.slug 兜底——slug 变化
即强制重建(缺组时空槽归位、dirty 归 false);单卡保存路径不受影响
(组引用照常换新触发)。覆盖 CredsPane 三卡 + WallPane / PromptsPane /
ContactFormPane / EngineFormPane / MiscFormPane(均已声明 slug prop,
index.vue 挂载处均已传 activeSlug,零接线改动)。

顺手:CredsPane 测试态注释仍提已删除的 resetAll → 改提三卡 watch;
计划文档 Task 15 段落末补 Batch 1 遗留打磨项处置注记(色列宽度/头像
提示样式经 Task 16 走查目检后定夺)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 21:40:29 +08:00
浅念 c6bd54229d fix(admin): CredsPane 单卡保存不再联动重置兄弟卡
旧 array-source watch 盯 [emailGroup, pushGroup, aiGroup] 三元数组——任一
组引用变化即 resetAll 三卡齐重建:单卡保存(如 email)后父层 onPaneSaved
换整份快照引用,push/ai 卡上未保存的编辑被静默丢弃(Task 14 评审挂账)。

改为三表各自 watch 本组 props 引用:父层保存回写是 {...snapshot, [group]:
config} 展开——只有被保存组引用换新,兄弟组引用不动 → 只重建该卡;切租户/
回滚时快照先置 null 再整份换新,三组引用齐变 → 三卡全量重置(行为保持)。
resetAll 相应拆为 resetEmailCard / resetPushCard / resetAiCard(备注/错误/
测试态随所属卡重置)。

自查两场景:改 email 保存 → push 草稿与 dirty 均保留;切租户 → 三卡齐重置。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 21:23:18 +08:00
浅念 f92a4be139 polish(admin): 各页空态与文案轻量打磨
- 会话列表/推送日志表空态给动作指引(empty-text,不再落 Element 默认「暂无数据」)
- 统计六图空态文案经 useChart 新增 emptyText 参数下发「暂无数据——产生会话后展示分析」
  (textContent 替代 innerHTML,缺省值不变,其余消费方零影响)
- 平台设置存储总览空表指引「暂无设置项——从上方推荐键开始」
- 租户详情站点表空态指引「暂无站点——点右上角「新建站点」创建」
- CredsPane 邮件测试 hint 的字面 **已保存** 星号改 <b>(模板不吃 markdown)
- 品牌预览卡右侧副标去掉与新增副标题重复的「本地简化」字样
- 仪表盘/租户列表/会话页既有 ElEmpty 已是动作指引文案,核对后无需改动

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 21:21:53 +08:00
浅念 914bd49128 docs: Batch 3 完成记档
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 21:16:10 +08:00
浅念 26dc93bc31 fix(admin): 头像上传基线只回写持久化字段(防脏检测假阴性)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 21:14:23 +08:00
浅念 e2aa166701 fix(admin): 脏保护三缺陷(brand 丢弃空操作/头像假脏/取消高亮错位)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 21:08:57 +08:00
浅念 edf58ce0a0 feat(admin): 未保存离开保护(Batch 3 收口)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 20:42:18 +08:00
浅念 250ffdfa53 feat(admin): contact/engine/misc 表单 pane + JsonGroup 退役
Task 13(feature/config-ux Batch 3):contact/engine/misc 三组从通用
JSON 整组编辑退役为专用表单卡——ContactFormPane(双开关 + 模板语言)、
EngineFormPane(限流数值 + context_seed_keys 高级折叠)、MiscFormPane
(国名 → 区号行编辑),共用新 KeyValueEditor 行编辑器(直改 reactive
rows,与 ScenarioCard 同契约);JsonGroupPane.vue 删除,model.ts 通用
JSON 组区块(JsonGroupKey/jsonGroupDraft/parseJsonGroupDraft/
JSON_GROUP_FIELDS)与对应测试一并退役;rowsToRecord/recordToRows 补
JSDoc(Task 12 评审折入)。

vitest 182 passed(185 − 3 旧 JSON 组用例);vue-tsc + vite build 零错误。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 20:23:26 +08:00
浅念 4dd74d6682 feat(admin): contact/engine/misc 表单映射纯函数
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 20:03:09 +08:00
浅念 8b430565d6 feat(admin): PromptsPane 重组(company_facts 主面+引擎级折叠)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 19:50:03 +08:00
浅念 f4907c1e27 docs: Batch 2 完成记档
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 19:45:45 +08:00
浅念 12b8dab5f0 feat(admin): WallPane 重组为场景卡+高级折叠(Batch 2 收口)
- 主面换 ConfigCard 卡壳:WALL_SCENARIOS 双状态场景卡 + no_contact 三键
  白话行编辑 + cc_templates 四组封闭语言集 + 试金石面板(整块平移)
- 高级区 WallAdvanced 挂载(正则/单正则/reminders,默认折叠);旧池区/
  正则区/提醒区/旧 collapse 结构与失效辅助全部删除(grep 零残留)
- 保存链加模板变量保护:collectRemovedWallVariables 集差检出被删的
  {intl}/{shown} 等运行期占位符 → ElMessageBox 二次确认(先于试金石)
- emits 追加 navigate;index.vue WallPane 挂载处接线 @navigate
- ScenarioCard 评审折入:requiredMissing 收紧(空白行保留但两池全空的
  必留语言也预警);× 删除钮键盘可达(role/tabindex/enter/space);
  addLang 严格正则注记(异常存量语言码可显示可删不可重加)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 19:34:31 +08:00
浅念 0553ccc32c feat(admin): WallAdvanced 高级折叠区(正则/提醒迁移)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 19:20:58 +08:00
浅念 79374a5c1d docs: Task10 补 Task8 评审折入项(空白行预警/×键盘可达/正则注记)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 19:16:55 +08:00
浅念 ab0cf9f64e feat(admin): WallScenarioCard 双状态场景卡组件
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 19:08:59 +08:00
浅念 36fe534029 fix(admin): 变量集差替代配对递归(删尾行/整键检出)+ 标签契约钉位
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 19:03:36 +08:00
浅念 2e6811a55b feat(admin): wall 重组辅助纯函数(场景卡/语言并集/模板变量保护)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 18:49:04 +08:00
浅念 d480a9f04e docs: Batch 1 完成记档
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 18:46:41 +08:00
浅念 680c4bade6 feat(admin): 品牌卡套视觉基线(Batch 1 收口)
- 品牌表单 ElCard → ConfigCard(图标/副标题/信息条/footer/danger 行);
  表单双列 grid(标题|主色、WhatsApp|邮箱 同排;头像/欢迎语/话题/占位/隐私 span-2);
  保存备注移 footer-right、重置出厂移 #danger(既有 resetting/onResetBrand 逻辑不动)
- 预览卡头加副标题「本地简化预览(真机效果以嵌入站点为准)」(cc-subtitle 观感)
- CredsPane 挂载处补 @navigate=onGroupSelect 接线;email 卡 info 去「带 • 的」前缀
  (push/ai 卡核实无该串);头注释同步收口
- 剪除 pane 条件链尾部 v-else 占位死分支(activeGroupLabel/ALL_NAV_ITEMS/
  .placeholder-card/.save-bar 等配套同清)
- form-grid 样式与 CredsPane 同款规则就地复用(不建共用文件)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 18:34:09 +08:00
浅念 20ab561859 docs: Task6 补评审折入项(navigate 接线/•文案清理/死分支剪除)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 18:26:18 +08:00
浅念 06e28e4435 feat(admin): 凭据页套视觉基线+SecretField 四件套
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 18:15:23 +08:00
浅念 712c5f9027 feat(admin): 配置中心导航分层双模式(常用/高级/版本独立)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 17:31:00 +08:00
浅念 f087b96adf docs: 计划 Task3 代码块同步组件变量名修正
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 17:24:35 +08:00
浅念 46dfbef176 fix(admin): ConfigCard footer 守卫修正(footer-left/right 判定)+ 主题变量对齐
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 17:21:38 +08:00
浅念 2e00db16b9 feat(admin): ConfigCard 视觉基线卡壳
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 17:10:02 +08:00
浅念 6881ccc3cd feat(admin): SecretField 密钥四件套组件
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 17:02:19 +08:00
浅念 0a413526bb feat(admin): secretFieldState 密钥四态展示纯函数
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 16:52:25 +08:00
浅念 eb2220c26c docs: 计划二轮修复(GroupKey 显式联合/v-else-if 链位/onPaneSaved 名)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 16:41:45 +08:00
浅念 bae51b00e3 docs: 计划评审修复(SecretField 接线/引擎测试咬合/退役时序/导入约定)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 16:36:05 +08:00
浅念 faf981ec9b docs: 配置中心优化实施计划(4 批 16 任务)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 16:25:59 +08:00
浅念 5b4b767334 chore: gitignore 增补 .superpowers/(brainstorm 工作区)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 16:15:21 +08:00
浅念 5bb891aade docs: spec 评审收口(cc_templates 语言封闭集 + 测试计数措辞)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 16:14:45 +08:00
浅念 3bb0147311 docs: 配置中心易用性与视觉优化设计 spec
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 16:09:41 +08:00
浅念 5ae32589da docs: 终态基线 632+2skip
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 14:04:54 +08:00
浅念 a20d53887d fix: 终审微修(admin no-cache/PII挂账/死配置清理)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 14:03:50 +08:00
浅念 dcf9d4b54c chore: Phase 4 收尾——部署工件齐备,项目四阶段完成
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 13:45:14 +08:00
浅念 7cdb4fc970 chore: 锁屏与通知组件删除(enabled:false的最终清理)
Phase 3 终审 M-1/M-2 摘入口后组件保留待决,本提交最终删除:
- art-screen-lock/ 与 art-notification/ 组件目录
- component.ts screen-lock 全局组件项、headerBar.ts notification 项
- types/config HeaderBarFeatureConfig.notification 字段、
  useHeaderBar shouldShowNotification
- art-header-bar 通知按钮/挂载/showNotice/visibleNotice/
  bodyCloseNotice 与 document 点击监听、.notice-button 样式
- components.d.ts 两条目;crypto-js 依赖全套(env.d.ts 声明/
  package.json/lockfile/optimizeDeps)——唯一消费方是锁屏
- en/zh 孤儿语言键(notice.* / lockScreen.* / topBar.user.lockScreen)
  与 mittBus openLockScreen 事件类型(无发射/订阅方)

grep 零残留;vitest 164 passed;build 通过(主 chunk 358.45→355.84 kB,
crypto-js 出预构建);auto-imports.d.ts 行尾漂移已还原。
CLAUDE.md Phase 4 清理单 6/7 结项(并补记 8/9 随 Task 5E/5D 结项)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 10:43:13 +08:00
浅念 b02326036f refactor: 租户切换器useTenantOptions收拢三页
新建 composables/useTenantOptions.ts:会话/配置/统计三页各自的
tenants/tenantsLoading/tenantsError/loadTenants 拷贝收拢为单一
composable。两种形态:
- 默认(会话/配置页):loadTenants 成功选中首个租户 +
  bootstrapTenantContext()(原两页 onMounted 公共体:超管拉列表/
  租户管理员固定自己/无 slug 防御不动),选中后的 watch 仍留各页
  (重置逻辑页面各异);
- selectFirst: false(统计页):纯下拉数据源,activeSlug 以
  tenantFilter 别名解构('' = 全部租户合并视图),模板零改动。

dashboard 控制台是租户卡片墙(非下拉切换),不在此列。
composable 显式 import vue API——vitest 不跑 unplugin-auto-import。
新增 8 个 composable 测试(mock api/auth store,不装 pinia)。

vitest 164 passed(156+8);build 通过;dts 行尾漂移已还原。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 10:36:30 +08:00
浅念 a50ed866ed perf: ECharts按需收窄
全仓 grep 确认存活消费方只有 views/stats/overview(line/bar/pie 系列
+ tooltip/grid/legend/title 组件)与 hooks/core/useChart(core 自带
的 init/setOption/resize/dispose);art-* 图表库组件(scatter/radar/
k-line 及 dataZoom/toolbox/brush/geo/visualMap/markLine/markPoint)
无任何页面挂载。

echarts.use 收窄为 Bar/Line/Pie + Title/Tooltip/Grid/Legend +
CanvasRenderer。graphic 与类型导出不动(未挂载库组件的 import 仍需
编译通过);组件文件保留,属模板库代码不在本任务删除范围。

构建对比(同机 pnpm build):
- echarts chunk: 767,864 B → 559,737 B(-208 KB / -27.1%;gzip
  251 KB → 187 KB)
- dist 总体积: 3,256,483 B → 2,983,300 B(-273 KB / -8.4%)
(chunk 内残留的 candlestick/radar/scatter 字样为核心 locale 名表
与主题色表,非图表实现。)

vitest 156 passed;build 通过;components.d.ts/auto-imports.d.ts
行尾漂移已还原。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 10:31:54 +08:00
浅念 24902c3c43 feat: breach_rate随迁(多租户--tenant适配)
从 ai-kefu-jc/scripts/breach_rate.py 拷入并适配多租户: CLI 改为
--tenant <slug> 必填, 经 platform.db 门禁(租户须已 bootstrap 注册,
同 import_legacy/archive 纪律)后只读打开 tenants/<slug>.db; 新增
--platform-db/--tenants-dir 覆盖参数(默认 repo 根约定路径)。

其余逻辑与 jc 原版一致: PATTERNS 锚定式匹配(美元符/货币单位多语言/
价格名词前置/交期承诺/号码回显≥10位/邮箱回显), 逐 assistant 轮次
首模式命中即计, 汇总破防率(>10% 启动方案B 输出过滤)。观察漏放侧
偏差——误杀侧不在本脚本口径(人工复核)。

冒烟: 临时库验证 happy path(5 轮 3 中 60%, user 行排除/NULL 内容
守卫/中文标签)与四类门禁拒绝(未注册/库缺文件/platform.db 缺/
schema 未就位), 临时文件已清。全量 pytest 630 passed 2 skipped。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 10:27:41 +08:00
浅念 fff4f27e98 feat: 测试端点限流(每租户5次/15分钟)
- email/test 与 push/test 复用 LoginLimiter 滑动窗模式: (kind, tenant_slug)
  键每租户 15 分钟 5 次真实出站,超限 429——guard 在端点最前(鉴权后),
  被限流的租户连 400 预检也不触发;record 只落在通过全部预检真正出站
  的那次(校验失败/未配置不消耗预算,两端口预算按 kind 互不挤占)
- conftest autouse 复位限流器(跨测试隔离);新增三测: 第 6 次 429+
  不同租户独立+email/push 互不挤占、校验失败不耗预算
- 回归: 后端 630 passed(627+3)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 10:17:52 +08:00
浅念 d734ed6d2a feat: resolver回退链接入platform_settings(三级回退/快照热刷新)
- app/platform/settings_store.py 新模块: lifespan 启动把 platform_settings
  全表快照进进程内存(load_snapshot/get/refresh,workers=1 单进程纪律);
  PUT /api/platform/settings 提交后 refresh 热刷新,回退链即时生效
- config_views email/ai 两组改三级回退: 租户槽位 → 平台设置快照
  (键名对齐平台设置页推荐键 ai.*/smtp.*)→ env settings(env 键名
  不变做最终兜底);push 无平台推荐键保持两级;smtp.port 自由 KV 容错
  归一(数字串转 int,脏值视同未设置落 env)
- conftest autouse 复位快照(resolver 直调测试隔离);新增
  test_platform_settings_fallback 六测(启动装载/三级链/端口容错/
  push 不接线钉死/PUT 即时生效)
- 平台设置页"仅存储"注记移除(CLAUDE.md 与前端页头同步改为已接线)
- 回归: 后端 627 passed(621+6)/ 前端 vitest 156 / build 零错误

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 10:10:52 +08:00
浅念 7808f8a299 docs: 手册审查修正(前缀同键空间表述/WS验证预期)
- .env PUSH_EXTERNAL_KEY_PREFIX 注释纠错: 两租户前缀与各自老项目完全
  相同(同键空间)——这正是切换/回滚不产生重复 UniService 线索的依据;
  原稿写成'与老项目隔离'方向反了。两租户之间互异即可, 勿改。
- WS 验证预期收敛为 HTTP/1.1 101(curl 已强制 --http1.1, 不可能是 HTTP/2),
  模板与手册 §3.5 同步。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 09:52:23 +08:00
浅念 96131ebdec docs: 部署手册(继承jc血泪+切换runbook+备份演练)+ openresty模板
- docs/deploy-production.md: 环境前置(.env 逐项/Compose>=2.24 依据/容器自含
  pip 免装) → 首次部署(build/bootstrap/up/health 分级解读/domains=3 口径) →
  1Panel 反代(Host 透传/WS 单套升级头/client_max_body_size 5m/api public
  放行/include 行检查) → 存量迁移(停容器或 backup API 导出, 禁运行时裸 cp;
  经 data/ 卷喂 import_legacy) → 切换 runbook(隧道+hosts 全功能验证 → 逐域名
  切反代 → 观察一周日检 → 老项目归档; 30 秒回滚预案) → 日常运维(backup API
  备份+季度恢复演练/日志封顶+PII 现状如实记/archive 维护窗口/tag 发版纪律/
  加租户零容器操作/bootstrap 幂等) → 踩坑实录 13 条(jc 五条承继+本项目八条,
  含 Host 头漏传全站 404 与头像 413 两条新增预判)
- deploy/openresty-all-kefu.conf.template: upstream + 租户 server 块(WS 单套
  升级头/XFF/上传体积) + admin 形态 A/B(注释切换) + 1Panel 适配注记(include
  行位置/片段直写 IP/验证重载命令)
- CLAUDE.md: 文档索引落位(手册+模板已存在, 补 Phase 4 计划链接)

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 09:44:28 +08:00
浅念 78755d491b fix: 归档脚本微审修复(fsync/文件名防覆盖/VACUUM容错/导出删除对账)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 09:34:19 +08:00
浅念 3a3292c239 feat: 数据归档脚本(导出/清理/VACUUM/dry-run)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 09:23:42 +08:00
浅念 ac9a4da51d feat: 存量导入脚本(保ID/session/status、pending→failed、幂等、对账报告)
Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 09:00:39 +08:00
浅念 6100b4eb15 fix: P4T1审查修复(platform.db入data卷/tzdata注释/corepack钉版/compose版本注记)
- main.py: PLATFORM_DB 挪到 <repo>/data/platform.db——data/ 是 compose
  bind mount,容器/镜像重建不再丢租户注册表;lifespan 对父目录兜底
  mkdir(冷机 data/ 不存在,sqlite 不建父目录)。bootstrap 脚本 --db
  默认值同步锚定 data/。
- 新测试 test_platform_db_defaults_into_data_dir: 常量形状钉死(回退
  仓库根即红)+ 冷机形态下 lifespan 建库于 data/ 内(全量 603)。
- Dockerfile: corepack 钉实测通过的具体版本 0.36.0(不追 latest,构建
  可复现);tzdata 注释照实改写(trixie slim 实测已自带,安装留作基
  镜像漂移保险)。
- docker-compose: 头注释改准确(tenants/=租户库,data/=platform.db+
  uploads);env_file 注记对象式写法需 Docker Compose >= 2.24。
- 实证: compose down/up 重建容器后宿主 ./data/platform.db 仍在,
  healthcheck healthy,/admin/ 200;docker compose build 复验通过。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 08:42:50 +08:00
浅念 4f38522759 feat: admin生产服务(/admin SPA fallback+health分级) + Docker两阶段构建 + 生产compose
- app/main.py: AdminSPA 纯 ASGI 挂载 /admin(dist 存在=StaticFiles html
  + SPA fallback(非 /admin/api 的 404 回 index.html 200);缺失=503 说明页);
  ADMIN_DIST env 覆盖、请求期现势解析(构建后不重启生效/测试可注入)。
  /health 分级: {status, tenants:[{slug,status,engine_ok}], domains}——
  懒建未就绪 engine_ok=None 不探库;单租户库损坏只 degraded 仍 200,
  不让 healthcheck 杀容器。
- host_middleware: /admin 与 /admin/ 前缀豁免租户解析(平台面;/admin-evil
  仍 404,前缀精确到斜杠)。
- admin: .env.production VITE_BASE_URL=/admin/(产物资源引用与挂载同源,
  单一事实源,不靠构建期 env 注入);package.json 钉 packageManager
  pnpm@10.7.1(corepack 与本地同版本)。
- Dockerfile 两阶段: node:20-alpine 构建 admin/dist(corepack 按清单钉版)
  → python:3.13-slim 只带运行时(app/static/seed_profiles/scripts+dist,
  含 tzdata 使 TZ 生效)。
- docker-compose: 生产编排(8018/env_file 可缺省/TZ/数据 bind mount/
  mem_limit 768m/日志轮转/python urllib healthcheck/restart)。
- .dockerignore 防泄(.env 不进镜像)+ .gitattributes 钉部署文件 LF。
- tests/test_admin_serving.py: 假 dist 夹具 7 例(服务/fallback 边界/
  Host 豁免/缺失降级/health 分级含坏库 degraded)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
2026-10-14 08:22:26 +08:00