浅念
|
5813fc91c7
|
feat(admin): 嵌入代码双形态 + shared_widget_domain 平台键
- 后端 GET /api/platform/settings/widget-domain:读平台设置键
shared_widget_domain(settings_store 内存快照,PUT settings 后热刷新
即时可见);platform_user 两种角色可读(超管配置/租户管理员生成嵌入
代码——与 settings CRUD 的 require_super 不同,非密钥无敏感面);
空串/非字符串视同未配置 → null
- config/center 嵌入卡双形态(spec 2026-10-19 §5):域名形态 +
共享域名形态(/t/<slug>/static/widget.js,路径前缀即租户标识);
可用性规则(两料齐双形态/无域名仅共享/共享未配仅域名/都无引导文案)
与生效态回退;data-site 两形态通用
- normalizeSharedDomain 主机名字符集校验(拒引号/尖括号/空格——防
配置侧把恶意字符注入生成的 script src 串)+ buildEmbedCode 纯函数,
vitest 6 例钉位
- 平台设置页新增「共享域名」组(shared_widget_domain 推荐键,表驱动
渲染自动生效);settings API 模块加 getWidgetDomain
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-19 19:24:56 +08:00 |
|
浅念
|
f938118fee
|
feat(limits): 限流器过期键周期清扫(内存上限铁律)
LoginLimiter._fails 与 rate_limit._buckets 只增不删——懒清理只覆盖被
回访的键,扫号换 IP/设备轮换产生的键永不被回访 → 进程长跑缓慢累积。
两处各加 sweep()(全表清「全部时间戳均已出窗」的键,窗沿 <= 与既有
保留判据 t > now - W 同沿),main.lifespan 起周期任务(300s loop)
启动创建/关停取消(cancel 后 await 落地,不留 pending task)。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-19 18:59:22 +08:00 |
|
浅念
|
4f58398ac2
|
feat(auth): 登录限流 IP 取 XFF 末段(防首段轮换伪造)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-19 18:40:47 +08:00 |
|
浅念
|
a1dc1ff7a3
|
feat(chat): 页面级 basePath 引导(路径模式静态面)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-19 18:28:22 +08:00 |
|
浅念
|
0baa9ab2ed
|
feat(widget): 脚本地址自推导 basePath(路径模式端点前缀)
spec 2026-10-19 §4: 路径模式(/t/<slug>/static/widget.js)下从 script.src
剥尾推导 basePath,brand/avatar 三分支/WS 四处端点构造统一加前缀;
Host 模式 indexOf 命中在 0 → basePath="" 端点零变化。
test_theme_static.py 头像锚定守卫随构造更新(wsBase + basePath + …,
语义不变:绝对锚定 + 禁相对路径)。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-19 18:13:49 +08:00 |
|
浅念
|
3862577143
|
test: 路径模式全链与限流隔离钉位
Task 3:TestPathPrefixRouting 追加 5 用例——
- chat REST 全链(建会话/resume/公开历史,全程 /t/ 前缀 + 未知 Host)
- 限流隔离:同 IP 同设备双租户独立计数(打满 jiancai 30 上限 429,
auto 消息通路仍 200——Task 2 桶键含 slug 的验收钉位)
- _PREFIX_RE.groupindex == {}(TENANT_SLUG_RE 派生捕获组漂移守护)
- WS 停用租户路径模式 1013(Host 未知,1013 只能出自路径分支)
- 双层前缀 /t/a/t/b 仅剥一层(剩余路径无路由 → 路由层 JSON 404)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-19 17:51:46 +08:00 |
|
浅念
|
9b97eafa1c
|
feat(middleware): /t/<slug>/ 路径前缀解析(与 Host 模式共存)
- TenantHostMiddleware 增路径前缀分支:raw_path 直判 slug 段(未编码
[a-z0-9-],%61uto/大写/点号不匹配落 Host 解析);仅带尾斜杠形态剥离;
path 定长切割(保留前缀尾斜杠为剩余路径领头斜杠),raw_path 按解码
path 重编码重算(非长度截断),orig_path 留痕;未知 404/ws 1008、
停用 503/ws 1013 与 Host 模式同语义
- _PREFIX_RE 字符类取自 registry.TENANT_SLUG_RE(掐 ^$ 锚)单一事实源;
tenant_routes 的 SLUG_RE 换源同常量别名 import(删本地定义与 import re)
- 评审折入:registry 空 sites 分支注释纠正为生产可达(DB 源全站点停用
合法状态),test_registry 用例 docstring 同步;conftest ADMIN_PASSWORD
注释补硬编码登录用例警示
- 新增 TestPathPrefixRouting 13 用例(全链/拒绝族/停用/site 覆盖/豁免
优先/direct-ASGI 改写钉位/WS 双例/路径优先)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-19 17:27:01 +08:00 |
|
浅念
|
6fc43c1f1c
|
fix(tests): conftest 钉 ADMIN_PASSWORD 出厂值——测试对本地 .env 封闭
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-19 16:52:36 +08:00 |
|
浅念
|
e08a675363
|
feat(registry): resolve_by_slug 路径模式解析 + TENANT_SLUG_RE 常量上提
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-19 16:36:13 +08:00 |
|
浅念
|
a20d53887d
|
fix: 终审微修(admin no-cache/PII挂账/死配置清理)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-14 14:03:50 +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 |
|
浅念
|
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 |
|
浅念
|
230eb2d86c
|
feat: 统计分析(卡片/漏斗/趋势/分布/推送健康,ECharts)
- admin 统计分析页(views/stats/overview): 指标卡四张(口径文案沿用
仪表盘)/ 漏斗横向条形(有序单色明度阶梯,标注 数量·占上一级%)/
按日趋势双线(窗口内无数据日期前端补零)/ 意向环形(分类三槽固定
指派,色随实体不随筛选)/ 来源·站点·国家 Top10 横向条形(名义类目
统一单色)/ 推送健康表(四状态计数 + duplicated 子集行)
- 筛选一行作用全部图表: 时间档(今天/近7天/近30天/自定义区间,自定义
不完整不发请求并提示)+ 租户切换(超管含"全部"合并选项,停用租户
标注;租户管理员固定自己)
- charts.ts 纯函数层(选项构建 + 双模式主题档),配色经
validate_palette.js 明暗双模式校验(分类/漏斗 ordinal 全过;
意向饼语义红绿组 CVD 硬伤弃用改分类槽)
- statsRange.ts 扩展自定义区间解析(既有仪表盘导出不动);
新增 charts/resolveStatsRange 单测 19 例(vitest 120→139)
- 修复 merge_stats distributions 尾随逗号 1 元组 bug(合并端点曾把
distributions 序列化成 JSON 数组,单租户路径不受累)+ 回归钉子;
后端 595 测试全过
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 22:33:55 +08:00 |
|
浅念
|
bf923d9cf7
|
feat: 配置中心-凭据(邮件推送AI表单/掩码交互/SMTP测试/推送探测端点)
- 后端 POST /tenants/{slug}/email/test:resolve_email_settings 当前配置
真发测试邮件(主题 [all-kefu] SMTP 测试邮件+租户名+UTC+8 时间);
回退后 host/user 仍空 → 400;成败如实返回 {sent, error},密钥不进响应
- 后端 POST /tenants/{slug}/push/test:连通性探测——与 _do_post 同款
连接形态 POST 空 messages 批量(红线:绝不携带线索数据);不可达
reason 分类 dns/timeout/connect(Windows 裸 ConnectError 文案兜底),
auth_ok 三态(2xx 真 / 401·403 假 / 其余 null),单次无重试
- email_service 抽 _smtp_send 共用连接逻辑(_send 契约不变)+
send_test_email(成败+错误串如实返回,不走吞异常 bool)
- 前端 CredsPane:邮件/推送/AI 三组凭据表单(数值/邮箱前端预检 +
后端 400 双层);密钥哨兵交互(__SET__ 占位符/不动保存保持库值/
清除按钮显式清空可撤销);SMTP 测试与推送探测三态内联展示
- 测试:pytest 新增 18(email/test 7 + push/test 11),全量 595 通过;
vitest 新增 20(model 哨兵往返/预检边界 + API 调用形态),107 通过
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 20:55:40 +08:00 |
|
浅念
|
f640889f22
|
feat: 仪表盘(租户卡片墙/平台总览/时间切换)+ 顺手:409契约锁与死代码
- 仪表盘视图:超管=平台总览四指标卡(/api/platform/stats 合并视图)+
租户卡片墙(逐租户 ?tenant= 下钻,含停用租户);租户管理员=自己
指标卡(/tenants/{slug}/stats,slug 取登录态);口径文案照
stats.py docstring(线索=留资三选一/成功率分母0显—等)
- 时间范围快捷切换(今天/近7天/近30天)→ from/to 本地日期串;
utils/statsRange.ts 纯函数 + epoch 防快速切换过期响应竞写
- 空数据态:无租户 ElEmpty / 单租户零数据自然显 0 与 —
- api/stats.ts 补 fetchPlatformStats/fetchTenantStats;tenants.ts 补
fetchTenantList(卡片墙枚举,其余仍留 Task 6)
- vitest +11(statsRange 6 + stats API 5,总 36)
- 顺手1:test_auth must_change 409 测试补 detail 断言,锁死前后端
契约文案(client.ts MUST_CHANGE_DETAIL)
- 顺手2:删除 beforeEach.ts 的 isUnauthorizedError 死分支与 ApiStatus
import(模板 isHttpError 判自建 ApiError 恒 false,分支不可达)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 16:59:12 +08:00 |
|
浅念
|
0c25287c19
|
feat: 密钥掩码哨兵(__SET__)四处响应 + 站点管理权限放开租户管理员
- config_routes: push.api_key/ai.api_key/email.smtp.password 掩码助手
(MASKED="__SET__";非空才掩,空串/None 原样)。作用于 GET config、
GET versions/{n}、POST rollback 响应、GET settings(计划四处),并盖
PUT/reset/PUT settings 的写回显——哨兵还原后的库值不经任何响应外泄。
- PUT 哨兵还原: 密钥字段收到 __SET__ → 当前快照原值替换后再写版本
(前端"不改就原样传回");传新值照常覆盖;空串传回仍=清空(既有语义
不变)。settings 同款(密钥名含 key/password/secret,递归嵌套 dict;
设置 key 本身命中也算)。库行/版本历史永远存原值。
- tenant_routes: 站点/域名四端点(POST sites/PATCH sites/POST domains/
DELETE domains)require_super → _tenant_guard;租户生命周期三端点
(POST /tenants/GET 列表/PATCH /tenants/{slug})保持超管专属。
- 测试: 掩码四处响应+落库分离断言(_current_snapshot 直查库)、哨兵
往返/新值/清空/嵌套路径/未设还原 None、settings 标量+嵌套+非密钥
字面量;租户管理员四端点自助(201/200)+他租户 403+生命周期仍 403。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 13:39:23 +08:00 |
|
浅念
|
6839cb94d2
|
fix: 终审修复——站点停用接线/prefix查重补创建reset/默认凭据警示+取舍补录
- I-1 站点停用全链接线: Site 数据类加 status 字段; DB 源 _load_one 与
文件源 read_tenant 均只输出 active 站点(停用站点域名不进 registry
索引 → 该域名 404;全停用=合法运营状态输出空 sites;文件源无 status
键默认 active 兼容)。E2E: PATCH 站点 disabled → 其域名 404、复启用
恢复;源级直测两源过滤。
- I-3 prefix 跨租户查重补两口: db.other_push_prefixes 共用助手
(MAX(version) 逐租户当前前缀,排除自身);创建向导(出厂档案前缀被占
→ 400 提示改 blank/改占用方)与 reset push(重置回出厂撞车 → 400 提示
走 PUT)接入;PUT 原有查重改用同一助手。rollback 维持豁免(历史不可变
语义优先,取舍清单记档)。既有测试第二租户改 blank profile 避撞。
- I-4 默认凭据警示: lifespan 启动检测 ADMIN_PASSWORD 仍为 Settings 字段
默认值(非硬编码第二份,防双源漂移)→ logger.warning 醒目提示;
CLAUDE.md Phase 4 部署记档补 ADMIN_PASSWORD 生产要求。
- I-2/M-2 取舍补录: 密钥掩码未实现(GET config/settings 明文返回
api_key/smtp 密码,Phase 3 前须定 __SET__ 哨兵方案);站点管理权限现为
仅超管(Phase 3 对接时决策放开或改 spec);取舍清单第 2 条同步刷新
(rollback 现为唯一豁免口)。
全量回归: 571 passed(基线 566 + 新增 5)。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 12:40:21 +08:00 |
|
浅念
|
7d16ae6318
|
feat: 生产装配切换DbTenantSource + bootstrap脚本(超管/两租户幂等导入)
- app/main.py: lifespan registry 装配按 env TENANT_SOURCE 切换(db|file,
默认 db)——db 走 TenantRegistry(DbTenantSource(platform_engine)) +
schema 就绪后 async load_all;file 回退旧 load_from_dir。空 platform.db
冷启动不炸:显式预检 tenants 表(非捕 ValueError——坏数据同样抛
ValueError,一揽子吞会把数据损坏静默成空平台),空表保持空注册表
(域名全 404 直到 bootstrap 导入),清扫循环对空 runtimes() 安全。
非法值在创建任何 engine 前显性炸。conftest 预置缝优先于 env 装配,
既有 558 测试零改动全绿。
- scripts/bootstrap_platform.py: init(schema+超管,env/.env 凭据,空表
才建)+ 出厂档案幂等导入(已存在 slug 跳过;FileTenantSource.read_tenant
同构快照 → Tenant+sites+domains+版本1,版本走 write_config_version 单一
路径;域名 _normalize_host 归一)。不建租户管理员——导入是存量迁移
形态,租户管理员按需走后台创建向导补。CLI 照 extract_config.py 的
argparse 风格(--db/--profiles/--seed)。
- tests/test_bootstrap_script.py: 幂等两遍零变化(行数/版本数逐项断言)、
超管 env 凭据、未知档案显性炸、bootstrap→DbTenantSource→registry 两租户
resolve 冒烟(jc 蓝/17 条/ai-kefu-jc,auto 橙/13 条/ai-kefu,es 覆盖层)、
TENANT_SOURCE 三态装配(db 空/库冷启动、file 回退、非法值炸)。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 12:05:42 +08:00 |
|
浅念
|
71e11c317f
|
refactor: config_views 单入口 + 0语义统一 + FakeAI 收敛(清理单#1#2#3)
- #3 六个消费视图 resolver 收拢 app/platform/config_views(单一定义点):
resolve_email/push/ai_settings ← 各服务文件, resolve_contact_flags/
context_seed_map ← conversation, name_to_region_extras ← manager
__init__ 内联取值(or None 语义原样)——函数体逐字搬入,服务层 import 之,
旧定义删;Phase 3 编辑器/试金石与该模块对接
- #2 限流 0 语义统一: conn_limiter.try_acquire 的 limit 与 chat_rest 的
rate_limit_per_hour 取值同款——0 或负 = 回退出厂默认(与姊妹键一致),
原 conn_limiter 0=全拒改为回退;chat_rest 取值抽 _resolve_rate_limit
纯函数供锚定
- #1 FakeAI 收敛进 conftest(超集: extract/evaluate/eval_calls),四份拷贝
删(test_lead_email_trigger/test_cc_integration/test_channel_hygiene/
test_lead_push_wiring——计划记三份,grep 实有四份;push_wiring 经
evaluate 参数注入原本地固定返回值,断言零改动)
全量 558 passed(554 + 新增 4: 单入口/内联等价/两处 0 语义)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 11:45:42 +08:00 |
|
浅念
|
acf5777ff2
|
feat: 统计API(卡片/漏斗/趋势/分布/推送健康,逐库聚合禁ATTACH)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 11:24:30 +08:00 |
|
浅念
|
ec55bc38ab
|
feat: 数据视图API(会话/详情/推送日志/删除,租户scope强制)
查询语义自 jc admin.py 移植,路由多租户化(/api/platform/tenants/{slug}/...):
- runtime 按 slug 取: registry.runtimes() 匹配 + ensure_ready(resolve 需域名,
平台后台只有 slug);未懒建租户首次查询触发建库不炸
- 会话列表: ≥1 消息的会话、created_at 倒序、intent/site(client_info.site)/
日期区间 from-to(边界含,to 日期-only 含全天)筛选,分页 page/page_size≤100,
每行含意向/联系方式/email_sent/IP 归国(ip_service 复用);total 对筛选后
集合计数(修 jc 旧缺陷: 其会话列表 total 不随 intent 变)
- 详情: 元数据+client_info+画像 chips(raw_info 去 _ 前缀键)+消息全量+意向块
- 删除: jc 原序逐表显式删,补齐 lead_push_logs(兑现 FK 声明的 CASCADE,
免孤儿行);不存在 404
- push-logs: load_only 排除 request_payload 大列,payload_size(func.length
服务端算)作省略标记;status/conversation_id 筛选
- 鉴权 _tenant_guard(slug): 他租户 403/未认证 401 有测试钉住;非法筛选值
显性 400(jc 静默忽略)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 11:00:39 +08:00 |
|
浅念
|
a43c654337
|
feat: 头像上传(uuid重命名/魔数校验/2MB/配置版本管线)与三级解析链
- POST /api/platform/tenants/{slug}/brand/avatar(require_tenant):
multipart 收文件,魔数判定类型(\x89PNG/\xff\xd8\xff/RIFF....WEBP,
优先于扩展名——改后缀骗不过,存盘扩展名取自内容)、≤2MB(413,
upload.size 预检免拷贝)、服务端 uuid4 重命名(原始文件名不参与
路径),落 data/uploads/<slug>/(目录懒建,gitignore 已忽略)
- 走 Task 6 配置版本管线(复用 config_routes 内部 helper):读当前
快照 → brand 组只替换 avatar 字段 → validate_group →
write_config_version(comment=头像上传) → registry_reload 热生效
- /api/public/avatar 三级解析链:uploads → seed 资产 → 静态兜底;
Phase 1 文件名穿越防线(拒 / \ . ..)扩到 uploads 段
- registry.uploads_root:自 data_dir.parent 派生(生产=<repo>/data/
uploads;测试注入 tmp data_dir 时自动落 tmp 内,隔离免污染)
- 新依赖 python-multipart(multipart 表单解析)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 10:35:41 +08:00 |
|
浅念
|
7502176190
|
feat: 配置API(分组校验管线/整份版本/回滚/重置出厂/试金石/平台设置)
- config_validation.validate_group: 九组校验管线(类型/键 allowlist/数值
范围/prompts 大小上限 50KB·100KB/wall 全量交 compile_wall/push.prefix
跨租户查重 spec E1),错误清单中文带字段路径
- config_routes: GET/PUT config(整组替换原样入版本,MAX+1,热 reload)/
reset(按 Tenant.profile 取出厂档案组)/versions 列表·详情/rollback
(旧版复制为新版本,历史不可变)/wall/test 试金石(逐句判定,不落库
不 bump)/settings 平台设置 CRUD(仅超管,resolver 接线归 Phase 3)
- db.write_config_version: 版本写入公共路径(创建向导与配置 API 单一
事实源);Tenant 落 profile 列(重置出厂按它取对应档案)
- _profile_snapshot/_blankify 迁 tenant_source(两路由模块共用);
db_source_app/super_client 夹具收拢 conftest(两测试文件共用)
- 测试: 519 → 537 全绿
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 10:07:40 +08:00 |
|
浅念
|
ec2e17d5e3
|
feat: 租户管理API(创建向导消费出厂档案/blank保留jc墙/域名/停用/slug不可变)
POST /api/platform/tenants: profile ∈ {auto,jiancai,blank}——首版快照复用
FileTenantSource(seed).read_tenant(profile).snapshot(Task 4 审查指定);
blank=jiancai 档案 _blankify 去身份组但保留 wall/prompts(compile_wall/
PromptProvider 的硬要求)。建 Tenant+main 站点+版本1+租户管理员
(must_change_password=True),创建后 registry_reload(upsert)立即可用。
站点 CRUD(brand_overlay 整字典赋值,M-2a)/域名绑定解绑(全局唯一,
撞车 400 带现有归属)/PATCH 租户(name/status;slug 不可变 400;停用走
reload 路径 dispose 引擎)。列表/详情管理员概要显式挑字段,凭据永不外泄。
鉴权: 写操作+列表 require_super;GET 详情放宽 require_tenant(slug)。
测试: db_source_app 夹具(registry 用 DbTenantSource 生产形态指向临时
platform.db,跨循环纪律: 直查走独立 NullPool 连接),16 项全绿,全量 519。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 09:20:28 +08:00 |
|
浅念
|
1bd341c21a
|
fix: 数据源审查小修(from_config 类型守卫/PROMPTS_KEYS 消重/契约措辞)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 09:05:09 +08:00 |
|
浅念
|
c7fd533320
|
feat: TenantSource 抽象——File源(测试/档案)与DB源(生产),registry 数据源可切换+reload upsert
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 08:50:16 +08:00 |
|
浅念
|
386b5eb90a
|
feat: /api/platform 豁免租户解析(认证守护)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 08:32:55 +08:00 |
|
浅念
|
c5e8dd6ded
|
fix: 认证审查修复(角色依赖连锁409门/停用租户token取舍注记/公共面整理)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 08:29:01 +08:00 |
|
浅念
|
f49e8e92b1
|
feat: 平台认证(scrypt上移/内存token 8h/登录限流/改密/角色依赖/409语义)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 08:18:15 +08:00 |
|
浅念
|
bfcaba5c87
|
fix: platform.db 前瞻加固(bootstrap竞态/哈希版本化/json_valid CHECK/测试补空/凭据列警示)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 08:08:22 +08:00 |
|
浅念
|
2d62108c73
|
feat: platform.db 模型与超管引导(WAL/scrypt/幂等bootstrap)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 07:57:15 +08:00 |
|
浅念
|
9ad02a778f
|
fix: 终审修复——墙执行侧接租户管道(端到端回归锁)+seed补email组+措辞与死依赖清理
C-1(必须修): 墙的执行侧没接租户管道——runtime.compiled_wall 全库只有
AIService 的 $DEFLECTION_POOL 一处消费,conversation.py 执行侧全走模块级
DEFAULT_WALL(jiancai 出厂),auto 租户会话实际跑的是 jc 墙。修复:
- manager 构造时 self._wall = runtime.compiled_wall(与 AIService 同源);
- 6 处过滤调用(violates_boundary/no_contact_value/asks_contact 的句内
与 pending 尾巴两路)、CC 墙模板/替换句、no_contact 收尾选择、
pivot/deflection、兜底句、contact_ask 触发日志判定全部传 wall=self._wall;
- _build_context_reminder/_contact_completion_note/_cc_confirm_note/
_cc_script/_cc_wall_template/_lang_note_for 加 wall=None 尾参
(None = 模块级默认墙,旧测试直调语义不变;流式侧 _contact_completion_note
双胞调用同传 wall,写回与注入不漂移);
- 模块级 DEFAULT_WALL 视图常量(BOUNDARY_TRIGGER_RE/_CC_*/_EMAIL_NOTE_* 等)
保留——boundary_filter 出厂默认与旧测试锚定,boundary_filter 模块级
DEFAULT_WALL 照旧,conversation 会话流内一律租户墙;
- 端到端回归锁 tests/test_wall_execution_tenant.py(两租户真 runtime +
脚本化假 AI): jc 独有 [€£] pattern 句在 jiancai 拦截替换(收尾=jc
pivots 池)/auto 放行逐字流出;同一邮箱违规句两租户各自精确收到自己
no_contact["web"](12 hours vs replies fast!);contact_ask 提醒注入
各自墙文案互不渗漏。已验证模拟旧 DEFAULT_WALL 行为时三测全败。
I-1: 两租户 seed 补 email 组(以 brand_values.json 实际值为准:
auto=notify_email 环境值,jiancai=品牌邮箱——其 notify_email 记录是
notify@example.com 占位): auto {sender_name: XYH, notify_emails:
[18339827479@163.com]}, jiancai {sender_name: HESUPIPE, notify_emails:
[hesu@hesuu.com]};seed 存裸名,From 头渲染时外层再包【】。补测
test_seed_tenants_ship_email_group: env NOTIFY_EMAIL patch 成异值证明
seed 槽胜出。
M-1/M-2: README/CLAUDE.md "platform.db 热加载"改为"文件级 registry_reload
热加载(Phase 2 升级为 platform.db)";requirements.txt 删 alembic
(全库零引用,grep 实证唯一命中即该行)。
M-3/M-4(挂账): CLAUDE.md Phase 2 清理单补两项——/health 分级健康
(Phase 4 部署批次)、PromptProvider.from_dir FileNotFoundError 带路径上下文。
全量回归: 463 passed(459 基线 + 4 新增),根目录与 tests/ 子目录同数。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-13 00:18:54 +08:00 |
|
浅念
|
3d6064dc14
|
docs: 上游吸收审查修补(注释纠偏/上游标点恢复/交叉引用闭合)
- test_lead_push_cc: 两处"双钉"注释与模块头改为如实的跨文件互补分工
(常量同源钉本文件,字节级措辞钉 test_lead_push_service.py /
test_email_rendering.py)
- chat_rest: _server_ip/_merge_client_info docstring 与调用点注释恢复
上游半角标点原文(逐字同步,便于将来 diff 式跟上游)
- chat.py WS 自报注释补 REST 侧交叉引用,闭合悬空不对称说明
全量回归 459 passed(不变)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 23:44:02 +08:00 |
|
浅念
|
d1aed8e722
|
feat: 吸收上游 7 个测试文件断言与 placeholder 配置化对齐
上游 ai-kefu → phase1 吸收(Task 11 unit 12):
- 拷入 7 个测试文件,import/夹具按目标库重锚(app.engine.* / conftest
async_db+build_jiancai_runtime / seed_profiles 提示词锚点)
- 补实现(同步自上游): chat_rest 服务端可信 IP(_server_ip/
_merge_client_info,直连场景自报假 IP 不再原样落库);widget.js 与
chat.js 的 data-placeholder 读取(叠加 Task 10 管道:data-* > brand >
中性兜底,tests/test_placeholder_static.py 守卫)
- 断言重锚以 jc 主线为准: ev.contact_info 存裸号+等待尾注(e164 走
_cc 派生)、source 值 fallback/customer_stated 口径、推送标注键
号码补全说明、prompt 静态锚按租户(seed_profiles)双测
- 全量回归 459 passed(基线 421 + 吸收 38)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 23:19:02 +08:00 |
|
浅念
|
7697673a3b
|
fix: 品牌下发审查修复(esc统一/语料中性化/穿越加固/反向断言动态化)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 22:52:08 +08:00 |
|
浅念
|
bbc7bc520e
|
feat: brand 白名单下发(站点覆盖/租户头像/CORS) + widget/chat 客户端 key 租户化 + 会话站点标
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 22:26:15 +08:00 |
|
浅念
|
49e2b476f5
|
fix: 配置接线审查修复(push数值哨兵化/恒真测试修正/哨兵防漂移/种子映射消双路径)
Important-1: push 数值字段(timeout/max_attempts/retry_backoff_base)
出厂默认改 None 哨兵(与 ai.model 同款),resolve_push_settings 对 None
回退 env——根治 truthy 出厂默认永久遮住 env 覆盖;恒真测试修正(env 数值
patch 成 7.5/5/2.0 与出厂区分)+租户显式数值优先断言;ai.provider 遮
env 的边界记入 docstring。Minor-2: 出厂 model 哨兵与 DEFAULT_CONFIG
一致性测试 + defaults.py 双源注释(model/rate_limit_per_hour)。
Minor-4: allowed_seed_keys → context_seed_map(返回映射,单一取值路径)。
Minor-6/7/3/8: WS 配置冻结时机注释/name_to_region 查表序注释改准确/
chat_rest limit 0 语义注释/resolver None 路径仅供测试注释。404 全绿。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 21:57:57 +08:00 |
|
浅念
|
32b582aac8
|
feat: 服务层配置接线——email/push/rate_limit/AI凭据/行为开关/映射表/种子键
Task 9: 服务层对全局 settings 的业务引用清零,每个 DEFAULT_CONFIG 组
都有真实消费方。resolve_*_settings(email/push/ai)以空槽回退 env
(平台默认层);contact 行为开关/种子白名单/国名扩表/限流上限经
manager 的 runtime.config 接线。收口: lead_push session_factory 必填、
config.py 死代码清理、PromptProvider frozen、no_contact 视图直取、
AIService wall 参数定型 CompiledWall。403 测试全绿(389+14)。
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 21:37:48 +08:00 |
|
浅念
|
8453d3cc56
|
test: conn_limiter 差异覆盖与导入清理
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 21:05:54 +08:00 |
|
浅念
|
54a65ed7da
|
feat: WS 每 IP 并发连接上限(默认10,(租户,IP) 键,finally 释放)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 20:54:28 +08:00 |
|
浅念
|
fd0f49870c
|
fix: Host中间件审查修复(本地开发文档/顺序守护测试/ws断连分支/夹具清理)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 20:47:01 +08:00 |
|
浅念
|
eaa5bf7e51
|
feat: Host 中间件租户路由(纯ASGI覆盖WS/未知404/停用503暂停页/health豁免)
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 20:30:30 +08:00 |
|
浅念
|
1824bb1590
|
test: PromptProvider 审查修复(组装缝断言/占位符约定文档与glob守护/边界注记)
- I-1: test_company_facts 捕获完整 prompt 的用例补话术池注入断言
("- EN:"/"- ZH:" 分组行在场)——守 AIService 组装缝,防 Task 9
重接提示词线时静默丢池
- I-2: seed_profiles/README.md 落档 $DEFLECTION_POOL 占位符约定
(缺失 = 话术池静默不注入);test_prompt_provider 占位符防漂移改
glob 遍历 seed_profiles/*/prompts/system.md,第三租户自动纳管
(空 glob 显性兜底,防假守护)
- Minor-1 注记: _format_deflection_pool docstring 记已知边界——条目
含引号/换行暂不转义,Phase 2 编辑器批次处理
- Minor-5: test_provider_loads_from_tenant_dir 删恒真 or 侧,改单一
明确断言;registry 加载期显性失败清单补 prompts 读取失败
(FileNotFoundError 说明);conftest build_jiancai_runtime 注明
data_dir 仅占位、从不 ensure_ready
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 20:16:40 +08:00 |
|
浅念
|
e34378257f
|
feat: PromptProvider 化 + $DEFLECTION_POOL 单一事实源注入 + runtime 必填化
- PromptProvider(app/engine/services/ai_service.py): 租户提示词四件套
from_dir 加载;build_system 把 system.md 的 $DEFLECTION_POOL 占位符替换为
wall.json deflections 话术池(按语言分组一行,EN/ZH/ES)再拼事实卡;
extractor/evaluator 的 $existing_info/$messages/$profile/$recent_messages
替换逻辑自 AIService 原样搬入(行为等价);删模块级 import 时读文件的
PROMPTS_DIR 与四个常量,保留 DEFAULT_PROVIDER(jiancai 出厂,__file__ 锚定)
- 两租户 system.md「三类请求的处理」第2条的迂回话术枚举 → $DEFLECTION_POOL
占位符(保留段落说明文字),话术只存 wall.json 一份,改一处两边同步变
- TenantRuntime 加 prompts 字段(加载期 from_dir(seed_dir/prompts));
ConversationManager 的 runtime 转必填(keyword-only),默认 AIService 用
runtime.prompts + compiled_wall.deflections 组装
- app/engine/prompts/ 删除(grep 无代码消费方,jiancai 出厂由
seed_profiles/jiancai/prompts 承接);test_company_facts/
test_system_prompt_dual_contact 的 cwd 相对路径改 Path(__file__) 锚定,
test_extractor_evaluator_prompts 断言对象改 DEFAULT_PROVIDER(语义等价)
- 新增 tests/test_prompt_provider.py(14 用例): 加载/注入/格式/占位符防漂移/
extractor-evaluator 组装/registry 接线/runtime 必填/池线过两墙
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 19:54:47 +08:00 |
|
浅念
|
20dddc151e
|
fix: 装配切换审查修复(启动异常路径韧性/清扫隔离/文案与夹具卫生)
- main.lifespan: 预热+清扫挪进 try,finally dispose_all 覆盖启动半途
失败(幂等于更少引擎,堵 engine 泄漏);清扫循环体 per-tenant
try/except + logger.exception 后继续——一个租户坏库不炸平台启动,
resolve/load_from_dir 保持 fail-fast
- routes/runtime.py: RuntimeError 文案补 registry_reload dispose 旧
runtime 成因;TenantRuntime 注解挪 TYPE_CHECKING(engine 包运行期
零 import platform)
- conftest client: teardown 置空 app.state.registry(关残留窗);
rmtree 先正常删,失败 warnings.warn 留痕后再 ignore_errors 兜底
Co-Authored-By: Claude Code <noreply@anthropic.com>
|
2026-10-12 19:37:51 +08:00 |
|