feat(compliance): add content compliance detection across tenant, ops, and clients
Implements the Revision 8/9 compliance design: tenant + ops backends, ops-web content-safety pages, admin-web editor/publish gate integration, desktop publish block surfacing, and supporting migrations / shared types / config plumbing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -40,7 +40,7 @@
|
||||
|
||||
### 2.1 V1 包含
|
||||
|
||||
- ops 平台维护的全局词库、策略、租户级覆盖
|
||||
- ops 平台维护的全局词库和全局策略
|
||||
- 租户自维护的白名单(豁免)、黑名单(自家敏感词)
|
||||
- 词典精确匹配 + 正则匹配 + 可选 LLM 语义兜底(开关控制)
|
||||
- 编辑器手动一键检测、发布器入口拦截、纯文本 API 三种调用入口
|
||||
@@ -193,7 +193,7 @@ CREATE TABLE compliance_dictionaries (
|
||||
CREATE TABLE compliance_dictionary_terms (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
dictionary_id BIGINT NOT NULL REFERENCES compliance_dictionaries(id) ON DELETE CASCADE,
|
||||
match_type VARCHAR(16) NOT NULL, -- exact | regex | semantic_keyword
|
||||
match_type VARCHAR(16) NOT NULL, -- exact | regex
|
||||
pattern TEXT NOT NULL,
|
||||
level_override VARCHAR(16), -- 该词单独覆盖等级
|
||||
hint TEXT, -- 命中后给用户的修改建议
|
||||
@@ -214,18 +214,16 @@ CREATE TABLE compliance_dictionary_versions (
|
||||
UNIQUE(dictionary_id, version)
|
||||
);
|
||||
|
||||
-- 平台默认策略(全局开关)
|
||||
-- 平台默认策略(全局单例)
|
||||
CREATE TABLE compliance_policies (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
scope VARCHAR(16) NOT NULL, -- 'global' or 'tenant_override'
|
||||
tenant_id BIGINT, -- scope=tenant_override 时填
|
||||
id BIGINT PRIMARY KEY DEFAULT 1,
|
||||
enforcement_mode VARCHAR(16) NOT NULL, -- mandatory | advisory | disabled
|
||||
enabled_dictionaries JSONB NOT NULL, -- [{"code":"ad_law_extreme","level_floor":"high","rollout_percent":100}]
|
||||
llm_judge_enabled BOOLEAN NOT NULL DEFAULT FALSE,
|
||||
llm_categories JSONB, -- ["politics","medical_claim"]
|
||||
updated_by BIGINT,
|
||||
updated_at TIMESTAMPTZ NOT NULL,
|
||||
UNIQUE(scope, tenant_id)
|
||||
CONSTRAINT ck_compliance_policy_singleton CHECK (id = 1)
|
||||
);
|
||||
```
|
||||
|
||||
@@ -396,11 +394,8 @@ func (s *ComplianceService) GateForPublish(ctx context.Context, articleID, versi
|
||||
config.compliance.enabled = false
|
||||
│ ↓ 全站短路(kill-switch,运维专用)
|
||||
│
|
||||
└─ ops.compliance_policies(scope=global).enforcement_mode = disabled
|
||||
│ ↓ 默认关闭,但词库管理 UI 仍可访问
|
||||
│
|
||||
└─ ops.compliance_policies(scope=tenant_override).enforcement_mode = disabled
|
||||
↓ 仅该租户关闭
|
||||
└─ ops.compliance_policies(id=1).enforcement_mode = disabled
|
||||
↓ 默认关闭,但词库管理 UI 仍可访问
|
||||
```
|
||||
|
||||
前端也要感知运行时状态:编辑器进入时调一次 `GET /api/compliance/runtime-status`,返回 `{enabled, mode, llm_enabled, dict_versions}`,**引擎关闭时按钮直接隐藏(不是置灰)**,避免空跑误导用户。
|
||||
@@ -435,7 +430,6 @@ config.compliance.enabled = false
|
||||
| POST | `/api/ops/compliance/dictionaries/:id/publish` | 词库版本发布(bump version + 写 versions 快照) |
|
||||
| POST | `/api/ops/compliance/dictionaries/:id/rollback` | 回滚到指定版本 |
|
||||
| GET / PUT | `/api/ops/compliance/policy/global` | 全局策略:强制 / 自愿 / 关闭、启用哪些词库 |
|
||||
| GET / PUT | `/api/ops/compliance/policy/tenants/:tenantId` | 租户级覆盖 |
|
||||
| GET | `/api/ops/compliance/stats` | 命中分布、拦截率、误报率(来自 ack 数据) |
|
||||
| GET | `/api/ops/compliance/records` | 全局检测记录搜索 |
|
||||
|
||||
@@ -473,7 +467,6 @@ apps/ops-web/src/views/compliance/
|
||||
├── CompliancePolicyView.vue # 全局策略:模式开关 + 启用词库勾选
|
||||
├── ComplianceDictionariesView.vue # 词库列表(含版本 / 启用 / 导入)
|
||||
├── ComplianceDictionaryEditView.vue # 词条 CRUD + CSV 导入
|
||||
├── ComplianceTenantOverrideView.vue # 租户级覆盖
|
||||
├── ComplianceRecordsView.vue # 全局检测记录、误报率
|
||||
└── ComplianceStatsView.vue # 命中 Top 词、拦截率、按租户分布
|
||||
```
|
||||
@@ -519,7 +512,7 @@ apps/ops-web/src/views/compliance/
|
||||
| **富文本不踩坑** | 检测**只看纯文本**,但保留 dom_path 用于回写高亮;图片 OCR、链接落地页 V1 不做(前置说明)。 |
|
||||
| **性能预算** | 编辑器手动按钮:纯词典 + 正则 P99 ≤ 50ms;含 LLM ≤ 1.5s。发布拦截:纯词典 + 正则 P99 ≤ 30ms(不含 LLM,LLM 异步进 review 队列),总闸超时由 `cfg.Compliance.PublishGateTimeout` 控制。 |
|
||||
| **可观测** | 给 [`server/internal/shared/middleware`](../server/internal/shared/middleware) 加埋点:每次 check 的 `duration_ms / hit_count / level / source / dict_version` 进 metrics;ops 侧拉曲线。 |
|
||||
| **审计日志** | 写词库、改策略、租户覆盖等管理操作通过现有 `auditlog.AsyncWriter`([`server/internal/shared/auditlog/async.go`](../server/internal/shared/auditlog/async.go))记录。 |
|
||||
| **审计日志** | 写词库、改策略等管理操作通过现有 `auditlog.AsyncWriter`([`server/internal/shared/auditlog/async.go`](../server/internal/shared/auditlog/async.go))记录。 |
|
||||
| **隐私** | check_records 默认只存命中片段(`matched_text`,截断 ≤ 50 字符)和偏移;全文不入审计。LLM 调用走现有 LLM client 的脱敏链路。 |
|
||||
| **极限词库种子** | V1 ops 预装:①《广告法》极限词约 200 条 ② 政治敏感词(公开版) ③ 涉黄涉暴 ④ 通用违禁。提供 CSV 模板,运营可自行扩。种子数据走数据库迁移落地,避免运维额外操作。 |
|
||||
| **kill-switch 可观测** | 配置短路时仍 emit 一条 metric `compliance_skipped_total{reason="config_disabled"}`,便于运维通过监控确认 kill-switch 已经生效。 |
|
||||
|
||||
Reference in New Issue
Block a user