33 KiB
title, type, date, status, artifact_contract, product_contract_source, execution
| title | type | date | status | artifact_contract | product_contract_source | execution |
|---|---|---|---|---|---|---|
| 文档编制人兼任审核批准 - Plan | feat | 2026-09-17 | planned | ce-unified-plan/v1 | ce-plan-bootstrap | code |
文档编制人兼任审核批准 - Plan
Goal Capsule
在系统管理员授权后,项目创建者可以为项目工作流中的每份文档单独启用「编制人兼任审核、批准」,只选择一位编制人即可完成该文档的全部人工职责。
本次交付为设计方案,尚未授权业务实现。已确认的需求是两级授权和逐文档配置。R9(激活前配置/激活后冻结)与 R10(关总开关后存量按冻结继续、不提供紧急熔断)已于 2026-09-17 审核批准,并补强 Heal 三入口投影稳定性为硬性验收项。实现与发布须分别提供源码、数据库、真实产品 PI 和浏览器证据。
基线为本地 dev@adb48c8,2026-09-17 源码核查;不代表正在运行的镜像已具备本能力。远端已 fetch,本地 dev 领先 origin/dev 44 个提交、落后 0。本方案不修改正式工作流定义,不将兼任等同于免审批。
Product Contract
Summary
新增管理员总开关,默认关闭;新增逐文档职责模式,默认沿用当前规则。创建者开启某份文档的兼任模式后,只填写编制人,审核人与批准人由服务端派生为同一人。仍执行送审、审核和批准,保留每一步身份、意见和时间。
Problem Frame
当前系统仅允许可选文档三职全空或三职完整指定,且完整指定时要求三人不同。用户需要小团队或个人也能执行完整的文档治理流程,并由管理员控制这一例外是否可用。
当前权限、文档人员投影和前端角色识别使用不同数据路径。因此仅放宽三职分离校验不足以支持本需求,还必须保证配置、生成、查看、修改、审批和阶段推进使用同一份职责来源。
Requirements
权限与配置
- R1. 仅系统管理员可开启或关闭系统级「允许编制人兼任审核、批准」权限,默认关闭。
- R2. 仅权威项目创建者可为自己创建的项目逐文档选择兼任模式;普通成员、项目角色管理员和其他项目创建者不能设置。系统管理员如果不是该项目创建者,也不因此获得逐文档配置权。
- R3. 每份文档独立选择,管理员开启总权限不自动修改任何项目或文档;新文档、新实例和复制产生的文档默认不继承兼任授权。
- R4. 兼任文档必须指定一名有效、在任的项目成员为编制人;可以不是创建者。审核与批准由该人承担,不能再指定其他审核人或批准人。
审批与可见性
- R5. 兼任模式属于纳入人工审批:保留送审→审核→批准三个动作、现有内容锁和驳回要求;不得生成完成后自动批准或通过阶段门禁。
- R6. 未开启兼任的文档继续遵守当前三职分离与可选免审批规则;必需文档不得借兼任模式省去编制人或审批。
- R7. 设置页、冻结快照、文档详情、操作按钮、签署展示与日志一致显示兼任关系;同一个人能在正确状态执行对应职责动作。
- R8. 兼任不授予系统管理员、创建者或其他成员代审权,也不扩大跨项目读取、非当前阶段写入和已结束实例写入权限。
生命周期与持久化(已审核批准,2026-09-17)
- R9. 首期仅在工作流激活前配置;激活时冻结该文档模式和职责,运行中的实例不直接改规划。已激活的存量项目不自动转换。若用户要求运行中转换,必须先扩展本方案的受控职责变更单元,不可悄悄放开现有 PUT。
- R10. 管理员关闭总开关后,禁止新启用、保存仍含兼任的规划和激活兼任规划;允许清除兼任后保存。已激活的兼任实例按冻结授权继续执行,历史日志不变。界面必须解释该开关是「授权新配置」,不是紧急停用所有存量审批;本期不提供针对已激活实例的紧急撤销/熔断能力。
- R11. 模式、编制人、授权依据、配置版本及各步骤日志需持久化,刷新、重登和服务重启不得丢失。
- R12. 编制人离任或账号停用后,不得继续执行三项职责;阻断尚未完成动作并展示原因,不自动找替代人,不重写历史签署。
Permission Matrix
| 操作 | 系统管理员但非项目创建者 | 当前项目创建者 | 普通项目成员 | 其他项目用户 |
|---|---|---|---|---|
| 修改系统总开关 | 允许 | 仅同时为系统管理员时 | 禁止 | 禁止 |
| 查看本项目可用模式 | 沿用当前项目读取权限 | 允许 | 沿用项目读取权限 | 禁止 |
| 规划期逐文档启停兼任 | 禁止 | 总开关开启才可启用;可关闭 | 禁止 | 禁止 |
| 指定编制人 | 禁止 | 规划期按 R4 | 禁止 | 禁止 |
| 送审、审核、批准 | 仅自己是该文档指定职责人时 | 同左 | 同左 | 禁止 |
| 已激活实例直接改职责 | 禁止 | 禁止(R9) | 禁止 | 禁止 |
Mode Matrix
「文档启用」「纳入人工审批」「编制人兼任」是不同含义,不能复用一个开关。
| 文档状态/配置 | 输入 | 有效职责 | 审批与门禁 |
|---|---|---|---|
| 文档禁用 | 不设置职责 | 无 | 沿用 skipped_disabled |
| 可选文档免审批 | 三职全空,兼任关闭 | none | 沿用既有免审批规则 |
| 标准人工审批 | 三职齐全且三人不同 | full | 保留正常人工审批 |
| 兼任人工审批 | 兼任开启,仅编制人 A | author_only;有效三职为 A/A/A | 与标准审批同样要求最终批准 |
| 未开兼任却只填 A | 缺审核和批准 | partial | 拒绝 |
| 标准模式填 A/A/A | 三职同人 | 非法 | 继续拒绝职责分离违规 |
| 兼任开启但无 A | 缺编制人 | 非法 | 拒绝 |
| 兼任开启又填不同审核人 B | 矛盾输入 | 非法 | 拒绝,不能静默吞掉 B |
User Flows
- 管理员进入「系统管理台→系统设置→工作流治理」,开启总授权;页面显示保存结果、修改人和修改时间。
- 创建者进入项目设置,展开某个阶段,在文档行开启「由编制人兼任审核、批准」。只保留编制人选择器,其余两项显示「同编制人(自动承担)」。其他文档保持原配置。
- 保存并预览:摘要列出标准审批、兼任审批、免审批的份数,列出每份兼任文档及编制人。确认后冻结。
- 编制人完成内容后送审,在审核中以审核人身份确认,在批准中以批准人身份确认;日志展示同一人对应三个职责,而非三个虚构人员。
- 页面刷新、重新进入项目后仍显示同样配置;最终批准后才按现有阻塞条件满足阶段门禁。
Scope Boundaries
本期覆盖所有通过项目工作流实例管理的文档,不针对某个任务名写白名单;freeform 文档与未绑定工作流的旧文档不提供此开关。不新增批量全选、不改项目成员全局 document_duty 为多角色,不自动改已发布工作流模板或历史签署。
生命周期口径(已审核批准,2026-09-17): R9 首期仅激活前配置、激活后冻结职责;R10 关闭总开关后禁止新启用/保存仍含兼任的规划/激活兼任规划,已激活实例按冻结授权继续执行。总开关是「授权新配置」,不提供已激活实例的紧急撤销/熔断能力;若业务需要合规级紧急止损,应作为独立后续方案,不在本期 Definition of Done 范围内。
Planning Contract
Current Implementation Evidence
以下为源码确认事实,不是运行验收结果。
| 位置 / 符号 | 当前行为 | 对本需求的影响 |
|---|---|---|
internal/projectinstance/types.go:DocTaskPlan / DocDuty |
仅 enabled、approval_configurable 和三职 ID,无逐文档兼任标记 | 增加显式职责模式 |
internal/projectinstance/duty_mode.go |
none/partial/full;partial 拒绝;三职重复报 SEPARATION_OF_DUTY_VIOLATION | 不能只填作者或仅关闭分离校验 |
internal/projectinstance/validator.go:validateActivationPlan / previewSummary |
激活至少 countFullDutyDocs>0;预览统计 full/none | 必须把合法兼任计为受治理文档 |
internal/projectinstance/service.go |
创建者可保存/预览/激活;active 后 ErrPlanFrozen;已有 revision、plan hash、token | 复用规划流程,补全授权版本和事务检查 |
internal/projectworkflow/service.go:IsProjectCreator |
权威项目创建者检查 | 不使用 UI 当前角色或项目 manager 代替 |
internal/projectinstance/store.go:sync 子实例逻辑 |
从规划写 project_doc_task_instances 和三职 assignment | 兼任需派生三项实际职责,不能只存作者而漏审批归属 |
internal/projectinstance/duty_action.go / stage_access.go / gate.go |
按动作校验单一职责;阶段可见性有 full 判定;门禁依赖 approved | 校验与阶段可见性都需认识新模式 |
internal/sysadmin/settings.go / store.go |
白名单设置、DB 持久化;无该 key;只记录最后修改人时间 | 可复用管理入口,新增策略消费与历史审计 |
internal/server/admin_system_handlers.go |
所有系统设置写入 requireSystemAdmin | 复用该入口,不开放管理列表给普通成员 |
internal/docduty/store.go:HealProjectDocuments |
按项目成员默认职责扫描并回填所有 task_key 非空文档 | 可能覆盖逐文档三职,必须区分实例绑定与旧默认 |
internal/bizdev/service.go / internal/docgov/project_docs.go |
生成后、列表读取时调用 HealProjectDocuments | 重开页面即可触发回填,必须验证刷新后仍一致 |
internal/docduty/revoke.go |
成员职责变化撤销审核/批准槽位,随后参与 heal | 不能把项目默认职责变化误当成逐文档兼任变更 |
internal/server/handlers.go:三个 DocGov 决议 handler |
使用登录身份及动作固定 author/reviewer/approver;先执行工作流鉴权 | 服务端已有按动作身份模型,应保留 |
internal/docgov/state_machine.go |
drafting/reviewing/approving/approved;检查对应职责 ID;无额外三人不同判断 | 复用状态机,测试身份一致和锁定边界 |
web/src/lib/currentDocRole.ts |
author 命中后立即返回,不支持同时三职 | A/A/A 会一直被当成 author |
web/src/lib/docGovActionVisibility.ts / DocGovActionBar.tsx |
按单一 currentRole 显示送审/审核/批准 | 必须改为动作能力或多职责判断 |
web/src/lib/projectSettingsDuties.ts / ProjectSettingsModal.tsx |
重复服务端 full/none 校验,人工审批默认要求至少三人 | 单成员兼任会被前端提前挡住 |
deploy/postgres/goose/00017_2026-09-12-project-workflow-instances.sql |
assignment 唯一键是任务实例+职责,无跨职责用户唯一限制 | 同一用户可有三条职责记录,不必拆用户身份 |
deploy/postgres/goose/00049_2026-09-17-system-settings.sql |
system_settings 已存在 | 采用增量迁移,不重建设置机制 |
相关历史边界参见 .doc/test-reports/2026-09-14-governance-action-level-authz-test-report.md 与 .doc/test-reports/2026-09-14-workflow-plan-409-frozen-and-optional-duties-test-report.md。它们说明已有验收意图,本次未重跑其测试。
IDE 所列 rdev 设计、short-term 和 backlog 当前位于 feature/rdev-template-depth 的独立工作区,不在本方案 dev 基线;已读取作兼容输入。rdev 的关闭文档/N/A、阶段前置、任务键命名空间化保持原语义。本方案按实例+阶段+任务身份绑定;待 rdev 合入后增加对应回归,不宣称其已在 dev 发布。
Key Technical Decisions
- KTD1. 新增
duty_policy,值为separated/author_only,属于 DocTaskPlan 的逐文档配置。缺省按 separated 解读;none/partial/full 仍是职责完整度,不能把「免审批」和「兼任」混为一谈。统一提供按任务解析模式、有效职责、是否受治理的领域能力;原 ClassifyDocDuty 保留给旧调用,治理调用迁到新解析器。(R3–R6) - KTD2. 配置快照保存用户意图:author_only 的 duties 规范形式只含 author_user_id。服务端通过唯一解析器派生有效 A/A/A,写三条 document_duty_assignments,并投影到 document_records 的三个 ID/名称。读接口区分配置职责与有效职责,客户端不得把有效 A/A/A 原样误写成标准配置。(R4、R11)
- KTD3. 新设置 key 建议
workflow.allow_author_only_approval,类型严格 bool,默认 false,无环境变量绕过,保存无需重启。projectinstance 通过窄的策略读取接口消费,由 app 装配注入;不从领域服务调用 HTTP,不让 projectinstance 成为 sysadmin 设置表的第二写入 owner。(R1) - KTD4. 配置写入、预览和激活都复核总授权;真正激活必须在事务内对授权版本复核,并与关闭总开关串行化。token 绑定 plan hash、项目/规划版本、授权 revision。总开关 false→true 后旧 token 仍作废,不能以「当前又是 true」放行。(R10、R11)
- KTD5. 实例绑定文档的职责权威是冻结 DocTaskPlan,经解析生成 assignments 和文档投影。项目成员 document_duty 只供旧无实例文档的默认分配。heal/revoke/生成/通知不得再次用项目默认人员覆盖实例文档。(R3、R7、R12)
- KTD6. 运行时按具体动作检查有效职责和当前在任状态;状态机仍按 author/reviewer/approver 记录实际动作角色。前端采用服务端动作能力集驱动按钮,可同时拥有多个职责,保留 viewer fail-closed,不新增一个可以绕过所有检查的万能角色。(R5、R7、R8)
- KTD7. 遵守 R9 的冻结边界;未知 mode、缺失授权来源或绑定不唯一时拒绝写动作。历史缺字段只代表旧 separated,不自动解释为兼任;不能全库 A/A/A 回填。(R6、R9、R11)
Data Model
以下是设计契约,字段落位按 owner 边界实现,不是现有字段清单。
| 数据 | 建议新增/扩展 | 用途与兼容 |
|---|---|---|
| system_settings | 目标 key;monotonic revision(默认 0) | 总权限 CAS、token 失效;目标行在迁移时初始化 false,避免无行锁问题 |
| 系统设置审计 | 仅本策略必需的 before/after、revision、actor、时间、request ID | 与设置更新同一事务提交;不把整站审计改造扩大到本期 |
| DocTaskPlan JSON | duty_policy,可选且旧值缺省 separated | 逐文档意图,纳入 plan hash;兼容 old hash 的序列化须有固定样本 |
| workflow instance 授权快照 | policy key、revision、允许状态、activated_by/at | 记录激活时获准的依据;由服务端生成,拒绝客户端伪造 |
| activation token | policy revision(新字段或令牌存储的版本化元数据) | 防预览后管理员撤销授权;旧 token 含兼任无 revision 必须重新预览 |
| document_records | doc_task_instance_id 可空外键 | 对新实例创建文档强制绑定;旧文档仅唯一匹配才回填,不修改历史职责 |
| document_duty_assignments | 复用三角色,兼任三行 user_id 相同 | 无需放宽角色唯一约束;author 必须有效且正数 |
| 文档视图 | duty_policy、effective_duties、allowed_actions、blocked_reason | 以服务端计算值展示;读参数不能切换权限 |
| 文档审计 details | duty_policy、instance/task ID、授权 revision | 送审/审核/批准均记录真人身份及该次 action role |
不预占 Goose 序号:实施时根据 dev 与并行 rdev 分支最新迁移取下一个空闲序号。迁移需覆盖 PG store 与 memStore 的字段 round-trip。兼容旧数据时禁止把 NULL 改成 0 外键。
High-Level Technical Design
职责解析链:
flowchart TB
A[管理员总授权] --> B[创建者逐文档配置]
B --> C[保存与预览校验]
C --> D[事务内复核授权并激活]
D --> E[冻结实例配置与授权依据]
E --> F[统一解析有效三职]
F --> G[职责表与文档人员投影]
F --> H[动作鉴权和阶段可见性]
H --> I[前端能力与操作按钮]
G --> J[文档状态机与审计]
兼任保留原审批状态机:
stateDiagram-v2
drafting --> reviewing: A以编制身份送审
reviewing --> approving: A以审核身份通过
reviewing --> drafting: A审核驳回并填写原因
approving --> approved: A以批准身份通过
approving --> drafting: A批准驳回
approving --> reviewing: 现有配置允许时退回审核
新授权和冻结授权的判断路径:
flowchart TB
A[请求] --> B{规划配置或激活?}
B -->|是| C{权威创建者且planning?}
C -->|否| X[拒绝]
C -->|是| D{含author_only?}
D -->|否| E[原职责规则]
D -->|是| F{总授权有效且版本一致?}
F -->|否| X
F -->|是| G[检查作者与输入一致性]
B -->|运行时动作| H[查冻结策略及实例任务绑定]
H --> I[检查成员有效性 当前阶段 状态和租约]
I --> J[按动作职责执行]
激活事务与设置撤销都以策略行锁形成先后顺序,再按统一顺序获取项目职责锁和实例相关行锁。策略 owner 提供事务兼容读取/锁定适配;不能照搬在事务外重查布尔值的方式。原则:关闭先提交则激活失败;激活先提交则成为 R10 中可继续的存量实例。并行成员移除与激活也必须在同一项目职责锁语义下判定,不能在事务开始前检查后直接信任。
API Contract
| 接口 | 变更 | 服务端强制条件 |
|---|---|---|
GET/PUT /api/v1/admin/system/settings[/{key}] |
注册总开关;目标 key 增加 expected_revision,返回新 revision | requireSystemAdmin;严格拒绝 null、字符串布尔;审计与值同事务 |
GET /api/v1/projects/{id}/settings |
返回精简 governance_policy capability、revision 与 blocked_reason | 保留项目访问校验;不泄露其他系统设置 |
PUT /api/v1/projects/{id}/workflow-plan |
每个文档可传 duty_policy;兼任只传 author ID;沿用规划版本 | 创建者、planning、总授权、有效成员、输入无矛盾 |
| 激活 preview / activate 现有接口 | 预览分列兼任文档;token 绑定策略 revision | 保存成功不等于已获激活授权;提交时重新事务校验 |
| 文档详情和项目文档列表 | 返回模式、有效三职与允许动作 | 统一来源;任务身份、实例身份须匹配 |
| docgov 送审/审核/批准接口 | URL不变,增加模式审计上下文 | 登录用户+对应 action,不信任请求的 user_id/user_name |
建议新增错误码:AUTHOR_ONLY_POLICY_DISABLED(403)、AUTHOR_ONLY_POLICY_CHANGED(409)、AUTHOR_ONLY_AUTHOR_REQUIRED / AUTHOR_ONLY_DUTY_CONFLICT / UNKNOWN_DUTY_POLICY(400 validation issue)、DUTY_BINDING_AMBIGUOUS(409)、DUTY_ASSIGNEE_INACTIVE(403)。总权限存储不可用返回 503;缺失目标配置采用默认关闭,但数据库故障不能伪装成正常缺项。保留已有 PLAN_FROZEN、PLAN_REVISION_CONFLICT 与 SEPARATION_OF_DUTY_VIOLATION。
author_only 写入审核/批准 ID:省略或 0 为规范输入;若为与作者相同的正数,可规范化为省略以兼容回显,但若不同则拒绝。关闭兼任时清除派生审核/批准,要求重新选择符合分离规则的人员;旧选择可仅作为未保存草稿提示,不自动恢复为真实授权。
UX Details
系统设置开关说明写明 R10,并展示预计受影响的待激活兼任文档数量及存量继续执行说明。保存失败保留用户输入和错误,不在本地假装开启成功。多管理员同时修改返回版本冲突,不自动覆盖。
项目设置按文档行提供兼任选项;总权限关闭时禁用并解释来源;非创建者只读。兼任只能在文档已启用且纳入人工审批时选择。兼任文档仅需一位成员;混合方案只要仍存在标准人工审批文档,才继续提示至少三位有效人员。
总开关在页面打开期间被关闭时,保存失败展示定位到文档的原因,提供关闭兼任选项;不丢弃整份未保存规划,不自动重试激活。预览和冻结视图同时展示「角色指派数」和「实际人数」,避免 A/A/A 被误认为三个人。
文档正文签署区显示真实姓名及兼任标记,但未发生审核/批准时不得显示签署时间或声称已通过。按钮随状态变化,审阅阶段即使当前人也是作者也不能编辑锁定正文;驳回后恢复编辑。查看/认领按当前状态或明确动作记录相应角色,不能打开一次页面就伪造三次履责。
Risks and Compatibility
- 回填覆盖(硬性门禁,非偶然安全):
HealProjectDocuments/ApplySlotRevocations与ConfigSnapshot是独立职责写路径,当前不区分实例绑定文档。实现必须在 heal/revoke 增加「实例绑定文档跳过项目默认覆盖」显式分支,禁止依赖「只填缺失槽位、碰巧不覆盖」的偶然安全。U3 必须对三入口(文档生成、列表 GET、成员变更)及 author 被误判非在任时的 healSlot 分别证明投影不变;未通过不得开放 UI。 - 历史身份混淆: 不以 project_id+task_key 跨实例盲绑;旧文档匹配多实例则保持原记录并报可定位问题。新生成文档必须携带 task instance ID,无法绑定应停止受控写入。
- 成员退出: runtime 复核在任资格覆盖 author_only;保留冻结快照用于历史展示。普通成员默认职责改变不得影响冻结文档;真实退出/停用应阻断动作。暂不新增运行中换人 UI。
- 并发审批: 同一人可打开多个标签,服务端仍需保证状态比较/版本检查;重复请求不能重复创建批准事件、版本封存或推进通知。延迟到达的审核请求不能作用于后续修订版本。
- 通知与事件: 审核待办发给同一人是有效业务,不可因发送者=接收者一概过滤。按事件+接收者去重,不把审核与批准两项待办合并成一个动作。
- 回滚: 关闭开关只停止新配置,不能安全地把已存在兼任实例交给完全不识别新模式的旧二进制。上线后若需回退代码,保留模式识别与冻结策略读取兼容补丁;不得通过清空审核/批准人员回滚。
- 总开关非紧急熔断(R10): 关闭总授权不会阻断已激活兼任实例的剩余送审/审核/批准。界面与运维说明必须写明这一点,避免被误解为「关总开关=紧急止损」。存量紧急撤销不在本期范围。
Implementation Units
U1. 策略存储与总授权
目标:提供管理员可写、项目治理可可靠消费的总授权。覆盖 R1、R10、R11,采用 KTD3、KTD4。
文件:internal/sysadmin/settings.go、store.go、internal/server/admin_system_handlers.go、internal/app/ 装配、增量 Goose 迁移;必要时新增 sysadmin 内的策略审计存储文件。
实现重点:默认关闭;严格 bool;目标设置 revision 与 CAS;事务内审计;窄接口可参与激活事务。仅本 key 要求的新协议不破坏其他设置键调用。
测试场景:管理员开关成功;普通用户伪造 PUT 被拒;null/字符串拒绝;DB断开不放行;并发修改只一个版本成功;审计写失败时设置回滚;重启读回。
U2. 逐文档模式、规划校验与激活
依赖 U1。覆盖 R2–R6、R9–R11,采用 KTD1、KTD2、KTD4、KTD7。
文件:internal/projectinstance/{types,duty_mode,validator,service,store,hash,tx,errors}.go、internal/server/project_settings_handlers.go。
实现重点:新增模式解析;所有 full-only 分支改为正确的受治理判断;保存、预览、激活一致;任务禁用/免审批清除模式;有效成员检查;规划 hash/授权 revision 和确认 token 一致。保存快照与提升 plan revision 应原子化,失败不能留下可读取的新规划配旧版本。
测试场景:一位成员、至少一份合法兼任文档可激活;只填作者但未开模式仍拒绝;混合 full/none/author_only;其他项目创建者、非创建者管理员拒绝;修改总授权后旧 token 拒绝;激活与撤销并发的两种提交顺序;旧 separated snapshot/hash 兼容。
U3. 文档绑定与职责投影一致性
依赖 U2;这是开放 UI 前的必要门禁。覆盖 R3、R4、R7、R11、R12,采用 KTD2、KTD5。
文件:internal/docduty/{store,resolve,revoke}.go、internal/docgov/{types,engine,project_docs,repository}.go、internal/bizdev/service.go、internal/projectinstance/store.go、任务执行请求与 app 适配、增量迁移。
实现重点:新文档绑定具体任务实例;受治理实例职责优先;统一有效职责映射用于创建、读取、heal、memStore;legacy fallback 仅在明确无实例时可用。HealBinding/healSlot/ApplySlotRevocations 对已绑定 doc_task_instance_id 的文档必须显式跳过项目默认覆盖,不得因 author 被误判非在任而重新分配默认人。旧已批准文档不因新功能读取被改写签署人员。
测试场景:同项目两份兼任文档由不同作者承担;第三份标准审批三人;第四份 none;反复 GET/成员默认角色调整/重启后四份职责均不串;未知或歧义绑定阻断;旧无实例文档仍按既有规则;NULL外键正常。硬性投影稳定性(开放 UI 前门禁): 已激活 author_only 文档在以下三入口触发 HealProjectDocuments 后,document_records 与 assignments 投影必须保持 A/A/A——(1) 仅刷新文档列表(ListWorkflowDocumentsByProject);(2) 文档生成完成(bizdev);(3) 成员变更后 heal。另测:author 被误判为非在任成员时,healSlot 不得把审核/批准槽位改写为项目默认人;真实离任仍按 R12 阻断写动作且不自动替人。
U4. 动作鉴权、文档状态机与事件
依赖 U3。覆盖 R5、R7、R8、R12,采用 KTD6。
文件:internal/projectinstance/{duty_action,document_access,stage_access,gate}.go、internal/server/{stage_access_helpers,handlers,document_revision_access}.go、internal/app/docflow/、internal/docgov/、相关通知订阅与审计视图。
实现重点:有效三职与在任状态统一判定;三个动作使用不同 action role;归档/修订账本与事件沿用既有事务机制;审核、批准不能跳状态,租约和内容 hash 不因同人而失效。Audit details 增加模式及来源。
测试场景:A顺序三动作成功且三份日志身份真实;其他成员/创建者/管理员越权失败;作者退出后全部写动作拒绝;审核中改正文失败;驳回原因必填;跨标签重复批准只产生一次有效终态事件;审批针对旧版本内容被拒;阶段直到最终批准才可推进。
U5. 系统设置与逐文档 UI
依赖 U1、U2,可与 U3/U4 开发隔离进行,联调必须等待后端完整。覆盖 R1–R4、R7、R9–R11。
文件:web/src/components/admin/console/sections/SettingsSection.tsx、web/src/components/project/ProjectSettingsModal.tsx、web/src/lib/projectSettingsDuties.ts、web/src/types/projectSettings.ts、web/src/api/projectSettings.ts。
实现重点:按 UX Details 配置、错误定位、人数要求、预览和冻结展示;策略 capability 来自项目 settings,而非向普通用户开放 admin settings。文档模式在不同阶段展开折叠后不串行。
测试场景:单成员可配置兼任;混合标准模式仍提示三人要求;非创建者只读;系统开关关闭时禁用及保存失败保留草稿;切换文档、刷新、重新登录后模式不变;已激活项目仍冻结。
U6. 多职责动作展示和真实闭环验收
依赖 U3–U5。覆盖 R5–R8、R11、R12,采用 KTD6。
文件:web/src/lib/{currentDocRole,docGovActionVisibility,controlledDocHydrate,deliverableSync}.ts、web/src/components/doc/DocGovActionBar.tsx、web/src/App.tsx、文档 API/types、相关 UI/PG/真实 PI 测试与报告。
实现重点:消费服务端动作能力,多职责不再被 author-first 短路;认领、提案、修订、按钮与日志一致;受控文档不按名字提权。证明刷新及重启保持一致后再开启真实项目配置。
测试场景:真实产品 PI 生成→A打开文档→送审→审核→批准→版本/日志→阶段门禁;标准和免审批文档并存;不同用户负例;两标签并发、刷新重开、重启;rdev 合入后复验 rd_ 文档及旧键兼容,不改 N/A 行为。
Verification Contract
本方案阶段未运行业务测试,以下为实现阶段必须提交的证据。
| 层级 | 覆盖 | 通过标准 |
|---|---|---|
| Go 单元 | 策略值、模式解析、权限矩阵、状态、门禁、hash | 所有模式边界及错误路径可重复验证 |
| PostgreSQL 集成 | 设置审计原子性、并发撤销/激活、成员退出、三职责落库、投影绑定;HealProjectDocuments 三入口对实例绑定 author_only 文档投影不变 | 实际事务交错结果符合 KTD4;失败不留下半成品;列表 GET/生成/成员变更均不得覆盖冻结 A/A/A |
| 前端单元/构建 | 单成员配置、双层开关、多职责按钮、错误恢复 | 测试与构建通过,无同人只见作者按钮 |
| HTTP 负例 | 修改请求身份、跨项目、非创建者、未知模式、关闭总授权 | 服务端拒绝,不能依赖隐藏按钮 |
| 浏览器 E2E | 管理员开关→创建者逐文档设置→A全部动作→其他人被拒 | 真页面操作、日志可见;无 API 直写替代关键步骤 |
| 产品 PI E2E | 正式生成及既有修订/租约流程 | 使用仓库要求的真实产品 PI + MiniMax;stub 仅作前期定位 |
| 持久化 | 刷新、重开、重登、服务重启 | 模式、职责、审核状态、版本和审计一致 |
| 回归 | 既有 full/none、标准三人分离、freeform、legacy、终止实例 | 原有权限和生命周期边界不退化 |
实现时执行 PROJECT 规定的 go vet ./...、go test -short ./...、前端 npm test 与 npm run build,以及使用隔离测试库的 PG 集成和明确启用的真实 PI 测试。不得把 skip 当 pass。共享容器重建验证必须在主仓占 CURRENT 集成槽位后执行;worktree 不启停共享容器。
重点验收样例:
- AE1(R1–R4):管理员开启后,创建者在文档甲选择 A,在文档乙选择 B;甲/乙有效三职分别为 A/A/A、B/B/B,互不影响。
- AE2(R5–R8):A只能按状态依次送审、审核、批准;未批准前门禁阻塞;另一个管理员无该文档职责仍被拒。
- AE3(R6):总开关开启但文档未勾选,A/A/A仍拒绝;三职空仅对原来允许免审批的文档合法。
- AE4(R10、R11):预览后总开关关闭再打开,旧 token 409;已先完成激活的实例刷新后仍可按冻结策略办理。关闭总开关不得阻断已激活实例的剩余审批动作(非紧急熔断)。
- AE5(R7、R11):项目成员默认审核人改为 C 后,读取兼任文档仍显示 A/A/A,不改历史签署;列表、正文及按钮一致。
- AE5a(R7、KTD5):已激活 author_only 文档在仅刷新文档列表(触发
ListWorkflowDocumentsByProject→HealProjectDocuments)后,投影仍为 A/A/A,不被项目默认职责覆盖。 - AE5b(R7、KTD5):文档生成完成与成员变更后 heal 两入口分别复测 AE5a;author 被误判为非在任时,healSlot 不得把审核/批准槽位改写为项目默认人。
- AE6(R12):A离任后保持历史名字,但所有新动作拒绝,不能被 heal 自动替换或按名字回退提权。
Definition of Done
- R9、R10 的生命周期口径经过用户审核(2026-09-17):批准「激活前配置 + 激活后冻结」与「关总开关仅停新配置、存量按冻结继续」;明确总开关不提供存量紧急熔断,该能力如需另立方案。Heal 三入口投影稳定性已升为 U3/Verification 硬性验收项。
- U1–U6 全部完成且证据覆盖对应需求;管理员和创建者两个权限层级均在服务端生效。(short-term U1–U6 均为
done;U6 报告回链) - 配置、快照、assignments、document_records、前端、审计在同一任务身份下对齐。(U2–U4 + U6 闭环证据;规范存储仅 Author + 有效 A/A/A 投影)
- 单成员兼任完整链与三人标准链均通过;不得只提交设置页截图。(U4 矩阵 + U6 HTTP/浏览器证据;标准分离回归见 U4/U2 单测)
- PostgreSQL、真实产品 PI、浏览器、重启与跨用户负例分别标明结果及限制;AE5a/AE5b 必须有证据。(U3:
TestHealProjectDocuments_SkipsDutyLocked_PG等 duty_locked 过滤;U6:既有 PI 生成文档 + Playwright 徽标 + lizhuguan 403。限制:U6 未单独跑「刷新/重登/重启」专轮,依赖 schema 持久化与 rebuild 后复测) .doc/test-reports/有验收报告并回链任务和 FEATURE-MATRIX;无新增已确认发布 blocker 才保持 gap-matrix 原结论。(U6 报告;变更提案 HTTP 另记 audit,不升为发布 blocker)- 发布先迁移与部署识别新模式的服务,再开放总授权;默认 off,试点后扩面。推送、dev集成与环境晋升状态分别报告。(dev 已合入并 rebuild:
merge: feature/document-author-only-plan@09a9921,healthschema_version=52,总开关默认 off。未做:push origin/dev、test/main 晋升、开放总授权试点——需另授)