合规与风险
本页是一篇完整方案指南:以 compliance 插件(com.auraboot.compliance,命名空间 compliance)为例,从用户场景一路讲到开发实施和典型错误。它是 config 型插件——6 个 model、49 条命令、14 个页面加 1 个看板全部是 DSL JSON 声明,没有一行后端 Java;下面每个标识符你都能在插件里 grep 到、对运行实例调得通。
合规域的标识符有一个容易踩的不对称:命名空间是
compliance,但 model 前缀、命令前缀、权限模块都缩写成cmp。model 是cmp_risk、命令是cmp:assess_risk、权限是cmp.risk.manage——不要写成cmpl_*或compliance:*。
1. 用户场景
一家做 SaaS 的公司要拿 SOC 2,同时受 GDPR 约束、内部还跑 ISO 27001。合规负责人的日常:
- 把一个合规框架(SOC 2 / ISO 27001 / GDPR…)拆成一批控制措施,逐条落实、验证;
- 对流程、系统、供应商识别风险,评估可能性 × 影响,做缓解或接受,最后关闭;
- 每个控制要留证据(日志、截图、配置、政策文档),证据要被审核、会过期;
- 按框架排审计(内部 / 外部 / 抽查),记录范围、发现项、跟进;
- 维护政策文档,带版本和生效状态。
合规管理员、审计员、普通查看者看到的数据和能做的操作各不相同。
2. 需求痛点
- 证据散落、事后凑不齐:控制是不是真的执行过、证据在哪、有没有过期,平时记在 Excel 和邮件里,审计师来要的时候临时翻。
- 风险无受控流转:风险从「识别」到「关闭」靠人记状态,没有强制的状态机,跳步、漏评估查不出来。
- 操作无授权无审计:谁批准了哪份证据、谁关闭了哪条风险,没有结构化记录;给外部审计师开账号,权限要么开太大、要么靠人盯。
- 集成困难:想让自动化规则或 AI 助手帮着「列出逾期未验证的控制」「起草发现项」,却没有可被程序调用的统一入口。
这些都不是「再加一张表」能解决的,而是受控状态变更 + 可索引审计的问题。
3. 产品方案
在 AuraBoot 里,每一个合规动作都是一条命令,走统一的 命令管道:
- 风险详情页的「评估风险」按钮调用
cmp:assess_risk,而不是裸写PUT /api/cmp_risk;命令在管道里统一鉴权 → 校验状态机 → 执行 → 审计 → 发事件。 - 状态流转用声明式的
state_transition:cmp:assess_risk只允许从identified走到assessed,跳步直接被管道拒绝。控制、审计、证据、政策、框架都是这种状态机。 - 同一条命令既是 UI 按钮的目标,也能被自动化规则、BPM 步骤、AI agent 调用——每条命令都带
cmd_risk_level和agent_hint,告诉 agent 它能做什么、风险多大。 - 命令管道本身产出结构化审计记录(谁、何时、权限评估、字段前后差异)。合规插件不"合成"证据,它索引管道本来就产出的东西。
4. 功能设计
4.1 数据模型(6 个)
| Model | 用途 | 关键状态值(字典) |
|---|---|---|
cmp_framework | 合规框架(SOC 2 / ISO 27001 / GDPR / HIPAA / PCI DSS / CCPA / 其他) | cmp_framework_status:planning → in_progress → certified → expired |
cmp_control | 框架下的控制措施 | cmp_control_status:not_started → in_progress → implemented → verified(另有 non_compliant) |
cmp_risk | 风险登记 | cmp_risk_status:identified → assessed → mitigated / accepted → closed |
cmp_audit | 审计记录(关联框架) | cmp_audit_status:scheduled → in_progress → completed → follow_up |
cmp_evidence | 控制证据 | cmp_evidence_status:pending_review → approved / rejected → expired |
cmp_policy | 政策文档(带版本) | cmp_policy_status:draft → active → archived |
风险用 5×5 矩阵评分:可能性字典 cmp_risk_likelihood(rare / unlikely / possible / likely / almost_certain)× 影响字典 cmp_risk_impact(negligible / minor / moderate / major / catastrophic)。风险分类 cmp_risk_category 的合法值是 data_breach / system_failure / insider_threat / vendor_risk / regulatory / operational(注意是 vendor_risk,不是 vendor)。
4.2 命令与状态机
命令命名 cmp:<动词>_<名词>,全插件 49 条。每个域有一套相似的命令:create / update / delete(带 preconditions)/ detail / list,加上各自的状态流转。代表性命令:
| 命令 | 作用 |
|---|---|
cmp:create_risk / cmp:assess_risk / cmp:mitigate_risk / cmp:accept_risk / cmp:close_risk | 风险全生命周期 |
cmp:create_control / cmp:start_control / cmp:implement_control / cmp:verify_control / cmp:flag_non_compliant | 控制实施与验证 |
cmp:create_audit / cmp:start_audit / cmp:complete_audit / cmp:followup_audit | 审计周期 |
cmp:create_evidence / cmp:approve_evidence / cmp:reject_evidence / cmp:expire_evidence | 证据审核 |
cmp:create_policy / cmp:activate_policy / cmp:archive_policy | 政策生效 |
cmp:create_framework / cmp:start_framework / cmp:certify_framework / cmp:expire_framework | 框架认证 |
每条命令都是一段声明。例如 cmp:assess_risk(config/commands/cmp_risk.json)的真实定义:
{
"code": "cmp:assess_risk",
"displayName:zh-CN": "评估风险",
"displayName:en": "Assess Risk",
"type": "state_transition",
"modelCode": "cmp_risk",
"stateField": "cmp_risk_status",
"fromStates": ["identified"],
"toState": "assessed",
"permissions": ["cmp.risk.manage"],
"agent_hint": "Transition risk from identified to assessed.",
"cmd_risk_level": "L1"
}读出来的设计信息:这是一条 state_transition,把 cmp_risk_status 从 identified 推到 assessed,只有 fromStates 里的来源状态才允许执行(在 mitigated 上点「评估」会被管道拒绝);要求 cmp.risk.manage 权限,风险级 L1,并通过 agent_hint 告诉 agent 它能做什么。
create 类命令则用 autoSetFields 自动生成编码并钉初始状态——例如 cmp:create_risk 用 "cmp_risk_code": { "strategy": "auto_generate", "pattern": "RISK-{yyyyMMdd}-{seq}" } 生成风险编号,用 "cmp_risk_status": { "strategy": "fixed_value", "value": "identified" } 把新建风险钉在 identified,新记录从此进入状态机。delete 类命令带 preconditions(如删除风险要求 cmp_risk_status IN [identified]),拦截误删已进入流程的记录。
4.3 权限与角色
12 个权限码(<模块>.<资源>.<动作>,module 都是 compliance,每资源 manage + read):
cmp.framework.manage cmp.framework.read
cmp.control.manage cmp.control.read
cmp.risk.manage cmp.risk.read
cmp.audit.manage cmp.audit.read
cmp.evidence.manage cmp.evidence.read
cmp.policy.manage cmp.policy.read
3 个角色:
cmp_admin(合规管理员)—— 全部 12 个权限。cmp_auditor(合规审计员)—— 所有资源read+ 审计与证据的manage(cmp.audit.manage/cmp.evidence.manage),正好对应「能跑审计、能审核证据,但不改框架和控制定义」。cmp_viewer(合规查看者)—— 只读 6 个read。
要做「外部审计师——只读」这种临时角色,组合 6 个 .read 权限即可;数据可见范围进一步用平台的权限五层模型(RBAC + 组织域 + ReBAC + ABAC + 字段级)收窄,这部分是平台底座能力,不在本插件配置里。
4.4 页面
14 个页面 + 1 个看板:
- 每个 model 的
list/form(cmp_*_list/cmp_*_form),框架和控制额外有detail页(cmp_framework_detail/cmp_control_detail)。 cmp_dashboard看板,消费 4 个命名查询:cmp_dashboard_kpi(总框架数 / 已认证 / 控制覆盖率 / 未关闭风险 / 90 天内待审计 / 生效政策)、cmp_control_coverage(控制按状态分组)、cmp_risk_matrix(风险按可能性 × 影响分布)、cmp_upcoming_audits(90 天内到期框架)。
5. 具体开发与实施
先掌握基础。本插件没有任何后端 Java,全靠平台的几个核心契约。动手前请先读:Model 与 Field · Command · 命令管道 · Permission · 插件清单 · 纯配置 Plugin · Page Designer。
落地一个像 compliance 这样的 config 插件,步骤是:
- 定义 model 与字段 ——
config/models.json+config/fields/,字段类型用平台dataType(string/integer/enum/decimal/date…)。cmp_framework等都是modelType: entity。详见 Model 与 Field。 - 声明命令 —— 每个 model 一个
config/commands/<model>.json(如cmp_risk.json),状态流转用type: state_transition+stateField+fromStates/toState,新建用type: create+autoSetFields,并在permissions绑权限码。详见 Command。 - 配字典 ——
config/dicts.json,每个状态字段对应一个静态字典(cmp_risk_status等),命令里toState的取值必须落在字典里。 - 配 model-field binding ——
config/bindings/,并在resourceDirs注册(见「典型错误」)。 - 设计页面 ——
config/pages/,列表 / 表单 / 详情用 Page Designer 出 DSL;看板放config/dashboards/,数据来自config/named-queries.json。 - 权限、角色、菜单 ——
config/permissions.json/roles.json/menus.json。 - 打包导入 —— 用
auraCLI 的import-directory-sync(参数是目录 path)或平台导入接口;校验返回success:true才算导入成功。plugin.json的provides列出对外契约(6 个 model + 6 个 create 命令 + 4 个 query + 看板),导入器据此做引用校验。详见 插件清单。
6. 常见配置
- 多框架共享控制:控制通过
cmp_ctrl_framework_id关联框架。一个 MFA 控制可以同时服务 SOC 2 与 ISO 27001——按需各建一条控制并分别引用,或在控制描述里标注覆盖的多框架条款。 - 证据过期提醒:证据有
cmp_ev_valid_until,到期用自动化规则触发cmp:expire_evidence把状态推到expired,看板的cmp_dashboard_kpi控制覆盖率随之下降,提示需要重新取证。 - 审计排程:框架的
cmp_fw_next_audit_date驱动cmp_upcoming_audits命名查询(90 天内到期);到期前用cmp:create_audit(初始状态scheduled)起一个审计,再cmp:start_audit→cmp:complete_audit。 - 暴露给 AI agent:只读 / 低风险命令(
cmp:list_risks、cmp:list_controls,cmd_risk_level: L0)适合让 agent 自由调用做汇总;delete类是L4、状态推进类是L2,靠cmd_risk_level让 agent 接入面知道哪些动作需要人确认。详见 Agent 就绪度。
7. 典型错误
- 命令码用点号:写成
cmp.risk.assess跑不通——真实是冒号 + 动词_名词:cmp:assess_risk。点号cmp.risk.manage是权限码,不是命令码,两者别混。 - 前缀写错:model 是
cmp_risk(不是cmpl_risk),命令前缀是cmp:(不是compliance:)。命名空间叫compliance,但 model / 命令 / 权限模块都缩写成cmp。 - 臆造不存在的 model / 命令:插件只有 6 个 model,没有
cmp_sod_policy这类职责分离专用模型,也没有cmp:audit_case_close之类命令。关闭审计实际走cmp:complete_audit(in_progress → completed)。配置前先 grepplugin.json的provides。 - 绕过命令直接改表:直接 UPDATE
mt_cmp_risk.cmp_risk_status会跳过状态机校验和审计记录,导致风险无凭据地跳步、审计链断裂。一切状态变更都走命令。 - 状态机跳步:在
mitigated的风险上点「评估」会被拒——cmp:assess_risk的fromStates只含identified。这是设计,不是 bug。 - bindingRules 写进 commands.json 内联:不会被导入;必须独立
bindingRules.json(本插件该文件是[])并在resourceDirs注册,否则报[S-EXT-HANDLER] references unregistered handler。详见 纯配置 Plugin。 - 命令执行 payload 结构:字段放在
{ "payload": { ... }, "operationType": ... },目标记录用targetRecordId(不是recordId)——放错位会出现「执行成功却字段为空」的迷惑性报错。