190 lines
8.7 KiB
Markdown
190 lines
8.7 KiB
Markdown
# 多租户知识空间平台运行手册
|
|
|
|
## 1. 适用范围与安全边界
|
|
|
|
本手册用于银城与美途作为两个独立 SaaS 租户的知识空间初始化、内容迁移、授权、外部应用联调和回滚。租户、调用应用和知识空间是三层独立边界:内部用户的有效查询范围取“当前租户 + 当前调用应用绑定空间 + 用户/角色授权空间”的交集;外部应用只能访问其所属租户内显式绑定的空间。
|
|
|
|
禁止把集团账号、公司名称、客户端传入的 `tenantId/userId/extPartyId` 当作授权依据。禁止在浏览器、小程序包、日志、工单或文档中保存 API_TOKEN。回滚优先停用应用或解绑空间,不删除知识数据、附件或 OSS 对象。
|
|
|
|
## 2. 初始化前确认
|
|
|
|
### 2.1 确认生产租户 ID
|
|
|
|
先只读查询生产库,不凭公司简称猜租户 ID:
|
|
|
|
```sql
|
|
select tenant_id, company_name, status, del_flag
|
|
from sys_tenant
|
|
where del_flag = '0'
|
|
order by tenant_id;
|
|
```
|
|
|
|
由业务负责人确认银城、美途分别对应的 `tenant_id` 和公司全称,并确认二者不同。执行脚本还会再次查询并打印 `tenant_id:company_name`,操作者必须核对后才继续。
|
|
|
|
### 2.2 备份与迁移
|
|
|
|
先备份数据库,再执行 `backend/script/sql/update/aihr_20260716_knowledge_space_platform_mysql8.sql`。迁移可重复执行,但生产仍应先在结构副本验证。执行后至少核对:
|
|
|
|
```sql
|
|
show tables like 'aihr_knowledge_%';
|
|
show create table aihr_knowledge_info;
|
|
show create table aihr_knowledge_app;
|
|
show create table aihr_knowledge_space_grant;
|
|
```
|
|
|
|
## 3. 幂等初始化
|
|
|
|
先 dry-run,不连接数据库、不输出密码或令牌:
|
|
|
|
```bash
|
|
./scripts/provision-knowledge-platform.sh \
|
|
--silver-tenant-id '<银城租户ID>' \
|
|
--meitu-tenant-id '<美途租户ID>' \
|
|
--dry-run
|
|
```
|
|
|
|
确认输出恰好包含银城 3 个空间、美途 1 个空间、3 个应用及预期绑定后,再实际执行:
|
|
|
|
```bash
|
|
AIHR_DB_HOST='<数据库地址>' \
|
|
AIHR_DB_PORT='3306' \
|
|
AIHR_DB_NAME='ry-vue' \
|
|
AIHR_DB_USER='<账号>' \
|
|
AIHR_DB_PASSWORD='<从安全环境注入>' \
|
|
./scripts/provision-knowledge-platform.sh \
|
|
--silver-tenant-id '<银城租户ID>' \
|
|
--meitu-tenant-id '<美途租户ID>' \
|
|
--confirm
|
|
```
|
|
|
|
不设置 `AIHR_DB_HOST` 时,脚本使用本地 `wygj-mysql` 容器。脚本是幂等 upsert,可重复执行;它不会生成 API_TOKEN,也不会把现有细粒度知识库改名、搬迁或删除。
|
|
|
|
执行后核对:
|
|
|
|
```sql
|
|
select tenant_id, code, name, space_type, sensitivity_level, status
|
|
from aihr_knowledge_info
|
|
where code in ('yc_public_policy','yc_property_sop','yc_management_ops','mt_customer_service')
|
|
order by tenant_id, code;
|
|
|
|
select tenant_id, app_code, auth_type, internal_client_key, status, rate_limit_per_minute
|
|
from aihr_knowledge_app
|
|
where app_code in ('yc_admin','yc_mobile','mt_card_miniapp')
|
|
order by tenant_id, app_code;
|
|
```
|
|
|
|
`mt_card_miniapp` 初始化后必须是 `DISABLED` 且 `token_hash` 为空;银城与美途之间不得存在应用—空间绑定。
|
|
|
|
## 4. 空间、授权与应用管理
|
|
|
|
管理端“知识空间”页面提供空间、主体授权和调用应用管理。空间编码创建后不可修改;停用空间会让检索立即失去该空间,但不删除资料。`MANAGE` 授权可以给用户或角色,`READ` 只决定主体能否读;SESSION 应用与主体授权取交集。
|
|
|
|
外部美途应用的启用顺序固定为:
|
|
|
|
1. 核对只绑定 `mt_customer_service`。
|
|
2. 核对空间只含批准对外发布的内容。
|
|
3. 设置合理的每分钟限流和过期时间。
|
|
4. 在管理端轮换令牌;明文只显示一次。
|
|
5. 立即写入小程序云函数、API 网关或可信后端的密钥系统。
|
|
6. 确认后端联调通过,再把应用状态改为 `ACTIVE`。
|
|
|
|
轮换令牌后旧令牌立即失效。发生泄露或暂停联调时,先把应用改为 `DISABLED`;需要恢复时重新轮换,不复用曾暴露的明文。前端、小程序源码和用户设备绝不能直接持有令牌。
|
|
|
|
## 5. 内容导入与 legacy 空间迁移
|
|
|
|
### 5.1 新内容导入
|
|
|
|
在 SOP 或资料处理页显式选择一个或多个可管理空间。多空间上传只解析一次、复用同一个 OSS 对象,但为每个空间建立独立附件成员关系和检索片段。解绑或停用一个空间不得影响另一个空间的内容。
|
|
|
|
导入后核对:
|
|
|
|
```sql
|
|
select a.tenant_id, k.code, a.doc_id, a.name, a.oss_id, a.status,
|
|
count(f.id) fragment_count
|
|
from aihr_knowledge_attach a
|
|
join aihr_knowledge_info k
|
|
on k.tenant_id = a.tenant_id and k.id = a.knowledge_id
|
|
left join aihr_knowledge_fragment f
|
|
on f.tenant_id = a.tenant_id and f.knowledge_id = a.knowledge_id and f.doc_id = a.doc_id
|
|
group by a.tenant_id, k.code, a.doc_id, a.name, a.oss_id, a.status
|
|
order by a.id desc;
|
|
```
|
|
|
|
空间解绑会先删除当前成员、片段和向量点;只有跨租户附件引用计数为零时才尝试删除 OSS。对象存储删除失败不会恢复已解绑成员,而是留下可审计的孤立对象,按下列查询确认后由独立清理流程处理:
|
|
|
|
```sql
|
|
select o.oss_id, o.tenant_id, o.original_name
|
|
from sys_oss o
|
|
left join aihr_knowledge_attach a
|
|
on a.tenant_id = o.tenant_id and a.oss_id = o.oss_id
|
|
where a.id is null and o.ext1 in ('aihr-knowledge','aihr-knowledge-staging');
|
|
```
|
|
|
|
### 5.2 细粒度 SOP 迁入 `yc_property_sop`
|
|
|
|
现有“投诉处理 SOP、催缴沟通 SOP、报修跟进 SOP”等 `legacy_*` 空间不直接改名。按以下顺序执行:
|
|
|
|
1. 业务负责人导出现有空间的文件清单,逐项标记目标空间、密级、版本日期、维护人和是否允许复用。
|
|
2. 通过多空间导入或 OSS 成员复用把批准内容加入 `yc_property_sop`,保留原 legacy 成员关系。
|
|
3. 对新空间至少运行 10 个标准问题,逐题核对答案、文件标题、引用片段和空间编码。
|
|
4. 核对新应用只绑定新空间,legacy 空间不向新应用授权。
|
|
5. 业务确认后把不再使用的 legacy 空间改为 `DISABLED`,观察查询日志一个完整业务周期。
|
|
6. 若出现缺失,重新启用 legacy 空间或恢复应用绑定;不要搬回附件、删除片段或清理 OSS。
|
|
|
|
## 6. 查询、日志与限流观察
|
|
|
|
内部统一入口为 `POST /api/knowledge/query`,外部入口为 `POST /api/open/knowledge/query`。外部请求使用 `Authorization: Bearer <API_TOKEN>`。查询日志只保存问题哈希、有效空间、来源类型、状态、耗时和提示版本,不保存完整问题或令牌。
|
|
|
|
```sql
|
|
select tenant_id, app_id, status, source_types, count(*) calls,
|
|
round(avg(latency_ms)) avg_latency_ms, max(create_time) last_time
|
|
from aihr_knowledge_query_log
|
|
group by tenant_id, app_id, status, source_types
|
|
order by last_time desc;
|
|
```
|
|
|
|
重点观察 `REJECTED`、`FAILED`、`NO_EVIDENCE`、连续 `429` 和异常高耗时。外部应用的限流依赖 Redis;Redis 不可用时外部查询应失败关闭并返回服务不可用,不能绕过限流继续调用。
|
|
|
|
## 7. 验证与发布闸门
|
|
|
|
自动合同测试:
|
|
|
|
```bash
|
|
bash scripts/tests/provision-knowledge-platform.test.sh
|
|
node --test scripts/tests/knowledge-platform-security.test.mjs
|
|
```
|
|
|
|
真实环境验证器从环境变量读取令牌,绝不写入命令脚本或仓库:
|
|
|
|
```bash
|
|
AIHR_BASE_URL='https://wygj-api.localhost' \
|
|
AIHR_SILVER_ADMIN_TOKEN='<管理端登录令牌>' \
|
|
AIHR_SILVER_EMPLOYEE_TOKEN='<员工登录令牌>' \
|
|
AIHR_SILVER_SUPERVISOR_TOKEN='<主管登录令牌>' \
|
|
AIHR_MEITU_APP_TOKEN='<美途应用令牌>' \
|
|
AIHR_MEITU_QUERY='<已确认能命中公开内容的美途标准题>' \
|
|
node scripts/verify-knowledge-platform.mjs
|
|
```
|
|
|
|
在预先导入了同一测试文件到 `yc_public_policy` 与 `yc_property_sop` 的非生产环境,可额外执行破坏性解绑验证;它会删除公共制度空间中的测试成员,因此必须使用专用测试文件:
|
|
|
|
```bash
|
|
AIHR_VERIFY_UNBIND=true \
|
|
AIHR_SHARED_DOC_NAME='<专用测试文件名>' \
|
|
AIHR_SHARED_DOC_QUERY='<测试文件唯一标记>' \
|
|
node scripts/verify-knowledge-platform.mjs
|
|
```
|
|
|
|
只有工程回归、真实 HTTP 正反例、数据库租户归属、Qdrant tenant+knowledge 过滤和每空间标准题都通过,才可标记“联调可用”。生产发布、真实内容负责人/授权矩阵签字和试点样本未完成时,不得标记“线上生效”或“正式试点验收”。
|
|
|
|
## 8. 回滚
|
|
|
|
按影响最小顺序处理:
|
|
|
|
1. 停用 `mt_card_miniapp` 或对应 SESSION 应用。
|
|
2. 解绑错误空间或把有问题的新空间置为 `DISABLED`。
|
|
3. 客户端临时回到兼容 `/api/knowledge/search`,该入口仍经过统一授权服务。
|
|
4. 恢复旧应用绑定或重新启用 legacy 空间。
|
|
|
|
不要删除新表,不删除查询审计,不把附件移动回旧空间,不清理 OSS,不回滚已经写入的稳定空间编码。数据库和静态资源发布仍遵循项目既有备份与发布口径。
|