Files
Agent-System/.doc/remediation/2026-09-11-production-ready-workflow-governance-plan.md
weichenandCursor 511864bad0 docs(ops): scaffold doc taxonomy and relocate audit/remediation
Establish .doc/{status,audit,remediation,archive} structure with README
maps, migrate 15 root audit/remediation docs, and add redirect stubs.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-13 02:50:23 +00:00

49 KiB
Raw Permalink Blame History

Chat Agent System 发布级账户、权限与工作流治理改进方案

1. 执行摘要

当前系统已经具备良好的业务原型基础:登录/注册、项目、项目成员表、受控文档三权流转、工作流运行、文档血缘、系统设置弹窗和用户设置弹窗均已有不同程度的实现;近期还补上了统一 API 登录中间件、Goose 数据库迁移、生产镜像中的前端构建,以及数据库不可用时的生产失败关闭。这些能力应保留并演进,而不是推倒重来。1 2 3

系统目前仍不适合直接作为多人生产协作产品发布。关键问题已经从“有没有功能”转变为“谁是权威、配置何时生效、运行状态能否被绕过”:

  • 用户、密码、登录令牌和认证配置仍保存在 Go 进程内存中,重启即变化,令牌没有持久化、过期、轮换和全端撤销闭环。4
  • 角色定义、权限矩阵、人员扩展资料、项目成员编辑与大量交付物状态仍由浏览器 localStorage 保存;当前后端管理员判断仍硬编码为 role-admin。5 6
  • 工作流目录是 Go 代码中的三个固定定义,每个定义只有一个 stage_key/task_key,还不是管理员可编辑、可发布、多阶段、多文档的工作流模型。7
  • 新项目默认立即激活 main;现有工作流控件会直接切换 active 指针,甚至在版本冲突后自动刷新重试,没有“配置—预览—二次确认—冻结—结束”的完整生命周期。8 9
  • 项目成员角色当前混用了“创建人、编制人、审核人、批准人、查阅者”。编制/审核/批准本质上是每份文档的职责,不应作为一个人在整个项目中的单一角色。10
  • 项目类型仍主要是自由文本 device_type,前端阶段键固定为 V0.1/V0.5/V1.0,无法自然表达非医疗纯软件项目或其他生命周期。11

建议把目标系统定义为一个“受控的项目工作流平台”,核心由五层组成:

账户主体 ── 组织/系统角色 ── 项目成员关系
                              │
                              ▼
不可变工作流版本 ──> 项目工作流实例 ──> 阶段实例 ──> 文档任务实例
                              │                         │
                              ├─ 对话参与策略           └─ 编制/审核/批准职责
                              ├─ 文档可见策略
                              └─ 阶段推进门禁 + 审计 + 通知

最重要的产品决策是:

  1. 取消任意身份切换:生产包中删除 DevRoleSwitcher 和“模拟账号切换”;登录身份只能来自服务端会话。测试身份切换只保留在不随产品发布的测试夹具中。
  2. 角色不等于文档职责:角色回答“这个人通常能做什么”;项目成员关系回答“这个人是否属于这个项目”;文档职责回答“这个人在这份文档中是编制、审核还是批准”。三者必须分表、分权限、分审计。
  3. 工作流采用版本化模板:管理员编辑的是草稿版本,发布后不可原地修改。项目激活时复制一个完整快照,后续修改全局模板不得改变正在运行的项目。
  4. 同一项目最多一个运行中的工作流:不能“切换”正在运行的工作流,只能在其完成或受控终止后选择新的工作流。
  5. 激活即冻结:阶段开关、文档任务开关、模板版本、文档三权与参与策略在激活前配置;激活后普通路径不可修改。确需变更时走“受控变更单”,而不是直接改字段。
  6. 阶段不自动推进:所有启用且必需的文档任务完成批准、无阻断性 stale/开放变更后,系统生成一次去重的“可推进”建议,主动通知项目创建者;由创建者确认后才原子进入下一阶段。
  7. 项目分类与合规范围分离:不要只设 is_medical=true/false。至少拆为“产品域”和“合规配置”。纯软件可能是非医疗软件,也可能是医疗器械软件;两者不能由“是不是软件”推断。

2. 需求重述与边界

2.1 三类设置

系统应形成三个边界清晰的设置入口:

入口 可进入者 管理对象 不应包含
用户设置 当前登录用户 本人资料、安全、通知、界面偏好、活动会话 角色提升、项目权限、他人账号
项目设置 项目创建者 项目成员、待激活工作流、阶段/文档开关、文档三权、激活/结束、通知 全局角色、全局模板原件、系统安全策略
系统设置 具备相应系统管理权限者 账户、角色、权限、工作流设计、模板库、项目类型/合规配置、审计和安全策略 以管理员身份直接替项目创建者完成日常业务决策

“系统管理员能看一切”不应成为默认业务规则。管理员需要处理平台配置,但项目私密资料和个人私密文档应遵守独立的数据访问策略。必要的运维介入应使用带理由、再认证、限时和全量审计的 break-glass 流程。

2.2 关键术语

术语 建议定义
账户 唯一自然人的登录主体,不可在前端任意切换
角色 一组可复用权限,可以是系统范围或项目范围
项目成员 用户与项目之间的关系,含状态和项目角色绑定
文档职责 某个用户对某个文档任务实例承担 author/reviewer/approver
工作流定义 管理员维护的逻辑标识,如 medical_device_development
工作流版本 已发布且不可变的完整流程快照,如 v3
项目工作流实例 某项目基于某个已发布版本创建的实际运行实例
阶段实例 项目工作流中的一个可推进单元
文档任务实例 阶段中的具体交付任务,连接模板、文档记录与三权职责

3. 当前实现评估

3.1 值得保留的基础

现有能力 评价 后续用法
统一 API 认证中间件 已覆盖非公开 /api 路由,方向正确 改接持久化会话,继续作为统一入口
project_members 已有项目成员关系和 owner 回填 扩展角色绑定、成员管理 API 和成员状态
document_records 已有状态、锁定、版本、三权和审计字段 关联 document_task_instance,逐步去除冗余姓名字段
DocGov 状态机 已有编制、审核、批准、驳回基础 增加职责分离、电子签名/再认证和阶段门禁事件
project_workflows/workflow_runs 已有项目工作流、运行和激活审计雏形 升级为定义版本 + 项目实例 + 阶段实例模型
文档血缘/stale 已能表达上下游版本变化 纳入阶段完成条件和变更影响评估
Goose 迁移与前端生产构建 近期已补齐基本链路 加迁移兼容测试、回滚预案和镜像验收
互动卡片/提醒类型 前端已有确认与提醒数据结构 用于“阶段可推进”和“工作流激活确认”

3.2 必须纠正的结构性问题

第一,当前 RBAC 主要在前端执行。DEFAULT_ROLES 和 hasPermission 用于隐藏按钮、过滤文档,但服务端没有同构的角色/权限表和统一策略决策。浏览器过滤只能改善体验,不能构成安全边界。OWASP 建议默认拒绝,并在每个请求上重新验证用户对具体资源和动作的权限。12

第二,现有 ProjectWorkflowSwitcher 的语义是“切换当前焦点”,而目标语义是“运行中的流程互斥”。当前控件点击后直接调用激活 API,遇到乐观锁冲突还会自动用最新版本重试;对高影响业务操作,这会掩盖“另一个操作者刚刚改变了项目”的事实。冲突应该展示差异并要求用户重新确认,而不是静默覆盖。9

第三,现有项目工作流唯一约束是 (project_id, workflow_key),无法表示同一项目先后运行同一流程两次,也没有数据库约束保证“每个项目最多一个 active”。应保留历史实例,以 instance_no 或独立实例 ID 区分,并用部分唯一索引约束活动态。

第四,现有文档记录已支持三权,但项目成员 UI 又把成员角色设成 author/reviewer/approver,导致一个人加入项目时就被迫成为所有文档的某一职责。这会阻碍不同文档采用不同责任人,也无法表达 QA 同时参与多个文档但只批准其中一份。

4. 目标权限模型

4.1 RBAC + 项目关系 + 工作流属性

只用 RBAC 无法表达“BD 在商务阶段可对话,进入研发阶段后不可对话且不可看研发文档”。建议采用组合策略:

允许 = 已认证
   AND 账户有效
   AND 具备基础动作权限
   AND 是该项目的有效成员(或合规的系统级例外)
   AND 当前工作流/阶段允许其项目角色参与
   AND 目标文档可见策略允许
   AND 当前状态允许该动作
   AND 未违反职责分离约束

任一条件未知或没有匹配规则时拒绝。RBAC 适合降低组织权限管理成本,但阶段、对象归属、文档责任人和状态属于属性/关系条件,需要与 ABAC/ReBAC 组合。NIST 的 RBAC 模型明确区分用户、角色、权限、操作和对象,也支持职责分离约束;NIST 对 RBAC 加属性的研究同样说明二者结合更适合动态条件。13 14

4.2 角色分层

层级 示例 作用域 建议
系统角色 系统管理员、用户管理员、工作流管理员、安全审计员 全系统 内置角色至少保留一个不可删除的超级管理员,但可编辑角色不得靠前端标志保护
业务/项目角色 BD、产品经理、研发、测试、法规、QA、项目观察者 某项目 用户可在不同项目承担不同角色;可从组织默认角色复制后由项目创建者调整
文档职责 编制、审核、批准 单个文档任务实例 必须指派到具体用户,不等于项目角色

建议允许一个用户绑定多个角色,但权限计算不是简单无条件求并集。若两个角色触发静态或动态职责分离冲突,应阻止绑定或阻止同一会话中的冲突动作。例如,同一文档默认不得由同一人同时编制和批准;如小团队必须例外,工作流版本需显式允许,并要求理由和额外审计。

4.3 权限键建议

权限键使用稳定动作,不把具体角色名编码进代码:

权限域 建议权限
系统 system.settings.view、system.audit.view、system.security.manage
用户 users.view、users.create、users.edit、users.disable、users.reset_password
角色 roles.view、roles.create、roles.edit、roles.delete、roles.assign
工作流模板 workflow_defs.view、workflow_defs.create、workflow_defs.edit_draft、workflow_defs.publish、workflow_defs.retire
项目 projects.create、projects.view、projects.edit、projects.members.manage、projects.workflow.configure、projects.workflow.activate、projects.workflow.terminate、projects.stage.advance
工作流参与 workflow.chat.send、workflow.chat.view、workflow.task.run、workflow.progress.view
文档 documents.view、documents.edit、documents.submit_review、documents.review、documents.approve、documents.export、documents.visibility.manage
模板文件 templates.upload、templates.download、templates.publish、templates.retire

项目创建者的专属能力不应仅靠一个通用 permission。服务端应同时校验 projects.creator_user_id == principal.user_id。系统管理员若需替代操作,只能走单独的 break-glass API,不能复用普通项目设置接口。

4.4 阶段策略示例

角色 商务阶段对话 商务文档 研发阶段对话 研发文档 审批动作
项目创建者 是 是 是 是 仅被指派时;阶段推进始终由其确认
BD 是 按文档规则 否 否 仅商务文档且被指派时
产品经理 可选 按规则 是 需求类与被授权文档 被指派时
研发 否/可选 默认否 是 是 被指派时
测试 否 默认否 是 测试及依赖文档 被指派时
法规/QA 可选 合规文档 是 合规与质量文档 被指派时
审计员 否 只读 否 只读 否

“否”必须在服务端同时作用于列表、详情、搜索、导出、附件下载、SSE、对话发送、RAG 上下文组装和 Agent 工具读取,不能只隐藏 UI。

5. 账户与身份治理

5.1 去掉任意身份切换

发布版本应:

  • 删除 DevRoleSwitcher 的产品入口;
  • 删除 UserProjectRightsModal 中的快速模拟账号切换;
  • 删除前端本地认证 fallback、内置明文测试账户和 X-User-ID 发送逻辑;
  • CI 检查生产 bundle 不包含种子密码、测试用户列表、allowDevSwitch 或模拟切换文案;
  • E2E 测试通过独立测试登录接口、数据库 fixture 或浏览器多上下文完成,不在产品 UI 留后门。

如果未来确实需要客服“代用户查看”,应作为独立的 impersonation/break-glass 功能:管理员再认证、填写工单与理由、限时、只读优先、页面持续红色提示、用户可见审计、禁止电子签名和批准。首个可发布版本建议不做。

5.2 持久化账户与会话

建议新增:

表 关键字段
users username、display_name、email、status、department、employee_id、locale、timezone、created_at、updated_at
user_credentials user_id、password_hash、password_changed_at、failed_count、locked_until、mfa_state
auth_sessions id、token_hash、user_id、created_at、last_seen_at、idle_expires_at、absolute_expires_at、revoked_at、ip_hash、user_agent
password_reset_tokens token_hash、user_id、expires_at、used_at
user_role_bindings user_id、role_id、scope_type、scope_id、valid_from、valid_until、assigned_by

令牌仅以哈希形式持久化。浏览器优先使用 HttpOnly + Secure + SameSite Cookie;如果继续使用 Bearer token,也必须有短期访问令牌、刷新/轮换、撤销和 XSS 风险控制。NIST 已在 2025 年发布 SP 800-63B-4,替代旧版数字身份认证指南;账户安全设计应以新版为基线,而不是继续依赖永久内存 token。15

5.3 用户设置

用户设置建议分为四页:

  1. 个人资料:头像、姓名展示、邮箱、电话、语言、时区;员工号、部门和职位为组织受控字段,只读或需管理员审批。
  2. 安全:修改密码、MFA、已登录设备、注销其他设备、最近登录与安全事件。
  3. 通知:待审核、待批准、阶段可推进、文档 stale、任务失败的站内/邮件策略及免打扰时间。
  4. 偏好:主题、默认输出格式、沟通风格、自定义指令;明确哪些偏好会进入 Agent 上下文。

高风险变更如密码、MFA、主邮箱和电子批准应要求近期认证。账号被禁用、密码重置或角色收回时,相关会话立即撤销并使权限缓存失效。

6. 系统设置的信息架构

系统设置不宜继续放在单个 980px 模态框内。建议改为有独立路由和权限保护的管理中心:/admin/*。

页面 核心能力
概览 服务健康、待审批用户、失败工作流、存储/队列、近期安全事件
用户与账户 创建、编辑、启停、邀请、重置密码、撤销会话、批量导入、角色绑定
角色与权限 角色增删改、权限矩阵、作用域、职责分离、受影响用户预览
工作流设计器 草稿创建、阶段排序、文档任务、参与策略、门禁、校验、测试、发布、退役
模板库 上传、预览、变量、版本、哈希、扫描状态、被哪些工作流引用
项目类型与合规 产品域、合规配置、字段 schema、可用工作流、默认策略
通知与自动化 事件模板、渠道、提醒频率、升级规则、去重规则
审计日志 用户/权限/工作流/模板/项目变更查询与导出
安全与会话 注册策略、密码/MFA、会话时限、CORS、上传上限、保留期

角色删除必须先做影响分析。若仍有用户或工作流策略引用,默认不允许删除,只允许停用/归档或迁移绑定。内置超级管理员角色不可删除、不可清空关键权限;系统必须始终至少有一个有效超级管理员账户。

7. 工作流定义与版本管理

7.1 定义结构

WorkflowDefinition (稳定业务标识)
  └─ WorkflowVersion (draft | published | retired,发布后不可变)
       ├─ StageDefinition [有序]
       │    ├─ DocumentTaskDefinition [0..N]
       │    │    ├─ TemplateVersion
       │    │    ├─ default duties / eligible roles
       │    │    └─ visibility / participation policy
       │    └─ entry/exit gate
       └─ workflow-level participation / completion policy

首期建议只支持线性阶段,拖拽排序即可。不要一开始引入任意 DAG、循环和复杂表达式;但表结构可以预留 transition_rules。线性模型已经满足“本阶段文档全部批准后,由创建者确认进入下一阶段”。

7.2 工作流版本状态

状态 可编辑 可用于新项目 可影响已激活项目
draft 是 否 否
published 否 是 否,项目只引用固定版本
retired 否 否 已运行实例继续按原快照执行

编辑已发布版本时实际执行“复制为新草稿”。发布前执行确定性校验:键唯一、阶段顺序连续、至少一个启用阶段、阶段至少有文档任务或显式人工门禁、模板均为可用版本、变量 schema 完整、权限策略有兜底、三权候选角色存在、无不可达节点、无角色死锁。

7.3 文档模板

模板不是直接覆盖文件,而是版本化资产:

  • 上传后生成 CAS blob、SHA-256、MIME/扩展名、大小、上传人和扫描状态;
  • 只允许业务所需格式,如 DOCX、XLSX、PPTX、Markdown;宏文档默认拒绝;
  • 经过扩展名、MIME、文件签名、大小、解压后大小、恶意文件扫描/隔离后才能标记 ready;
  • 发布的工作流只能引用 ready 模板版本;
  • 模板更新创建新版本,不改变历史项目实例;
  • 变量采用白名单 schema,如 project.name、project.owner.name,未知变量阻止发布。

OWASP 对上传的建议包括扩展名白名单、不要信任客户端 Content-Type、应用生成存储名、限制大小、仅授权用户上传、放在 Web 根目录外并进行恶意文件扫描;模板上传应按此设计。16

8. 项目类型与合规配置

8.1 不使用单一“医疗/非医疗”开关

建议拆为两个维度:

维度 示例 用途
product_domain medical_device、non_medical_software、hardware_general、service 决定项目字段、推荐工作流和术语
compliance_profile nmpa_device、eu_mdr、fda_qmsr、internal_qms、none 决定法规步骤、必需文档、签名和审计强度

“纯软件”不能自动等同“无需法规”。非医疗 SaaS 可以选择 none;SaMD 则仍属于医疗器械域并选择对应市场合规配置。创建项目时以向导明确询问产品用途、目标市场和是否用于诊断/治疗等,由用户确认分类及理由,系统只提供建议。

FDA 的 QMSR 已于 2026 年 2 月 2 日生效,并将 ISO 13485:2016 纳入美国医疗器械质量体系框架;因此医疗项目的默认工作流与合规配置应可版本化,不应把旧法规口径写死在 Agent prompt 中。17 ISO 官方也说明 ISO 13485 面向医疗器械质量管理,并强调法规要求和风险管理;它不适合无差别施加给所有非医疗软件项目。18

8.2 首批项目类型建议

医疗器械研发建议阶段:商务摸底 → 需求与法规策划 → 设计开发 → 设计验证/确认 → 设计转移/发布。文档清单由所选市场、器械类型与组织 QMS 决定。

非医疗纯软件建议阶段:机会与范围 → 产品需求 → 架构与计划 → 实现 → 测试与验收 → 发布复盘。默认无法规检索步骤,可包含 SRS、架构设计、测试计划、发布清单、用户文档;若选择 internal_qms,仍可要求评审、批准和审计。

项目类型只负责推荐和约束可选工作流,不直接生成项目实例。这样未来可增加科研、咨询、硬件或组合产品,而无需修改 projects 表的大量专用字段。

9. 项目设置与激活冻结

9.1 项目设置页面

仅项目创建者可进入普通项目设置。页面建议分为:

  1. 基本信息:名称、编号、产品域、合规配置、目标市场;工作流激活后影响流程的字段冻结,修改需受控变更。
  2. 成员与项目角色:邀请、移出、项目角色绑定;不能在这里把成员设为全项目 author/reviewer/approver。
  3. 工作流配置:从与项目类型兼容的已发布版本中选择一个待激活工作流。
  4. 阶段与文档:激活前开关可选阶段/文档,查看依赖和影响;必需节点不可关闭。
  5. 责任分配:逐文档指派编制/审核/批准,实时验证角色资格与职责分离。
  6. 激活与结束:预览快照、风险提示、二次确认;运行中只展示状态和受控操作。
  7. 项目审计:成员、配置、激活、推进、终止和职责变更记录。

9.2 激活流程

新项目不应默认激活 main,而应处于 planning。推荐交互:

选择工作流版本
  → 配置阶段/文档开关
  → 指派每份启用文档的三权
  → 系统校验
  → 生成只读预览与 plan_hash
  → 用户二次确认
  → 单事务创建实例/快照/首阶段/文档任务/审计

激活确认弹窗应明确展示:工作流名称和版本、启用阶段数、启用/关闭文档数、三权缺口、激活后哪些配置会冻结、当前参与者权限将如何变化。用户勾选“我理解激活后不能直接修改”并再次点击确认。

服务端不能只信任 confirmed=true。建议 POST /activation-preview 返回短期 confirmation_token + plan_hash + expected_project_version;真正激活时必须三者一致。若期间成员、责任人、模板或项目配置变化,返回 409 和差异摘要,要求重新预览确认。

9.3 工作流实例状态机

planning ──activate──> active
   │                    ├─> awaiting_stage_confirmation ──advance──> active
   │                    ├─> completed
   │                    └─> termination_requested ──confirm──> terminated
   └─delete draft

数据库增加部分唯一约束:一个项目在 active/awaiting_stage_confirmation/termination_requested 中最多有一个实例。新的工作流只有在前一个实例为 completed 或 terminated 后才能选择和激活。

正常“结束”与异常“终止”必须区分:

  • completed:所有启用阶段按门禁完成;
  • terminated:创建者因范围取消等原因提前结束,必须填写原因,保留已有文档和历史;
  • paused 可作为后续版本能力,首期不建议增加以免模糊“是否仍占用 active 槽位”。

9.4 配置冻结与受控变更

激活后以下内容冻结:工作流版本、阶段和文档启用状态、模板版本、基线参与策略、文档三权。首期可严格禁止修改。

第二阶段再提供 workflow_change_requests:创建者提出变更 → 系统分析影响 → 相关批准人确认 → 创建新配置 revision → 使受影响下游文档 stale。即使通过变更单,也不应回写全局工作流版本。

10. 阶段、文档与主动推进

10.1 阶段状态机

pending → active → ready_to_advance → completed
             │              │
             └─ blocked <───┘

阶段进入 ready_to_advance 的确定性条件:

  • 所有 enabled=true && required=true 的文档任务均为 approved;
  • 没有运行中的 Agent/task run;
  • 没有阻断性开放批注、变更提案或 stale 文档;
  • 阶段专用 exit gate 通过;
  • 下一阶段至少有一个有效参与者,避免推进后无人能工作。

可选文档如果启用,也建议默认纳入阶段门禁;工作流管理员可以把某文档配置为 blocking=false,但发布时需要解释用途。阶段开关关闭时,其文档节点自动关闭并记录在项目快照中。启用阶段若关闭全部文档,必须有 manual_gate=true,否则激活校验失败。

10.2 文档任务状态

文档任务实例与文档正文分离:任务状态负责“是否启用、负责人是谁、是否完成”,document_records 继续负责正文版本和受控生命周期。

disabled(仅激活前可选)
enabled: template → drafting → reviewing → approving → approved
                         ↑          │            │
                         └─ rejected┴────────────┘
approved --upstream changed--> stale(阻止阶段推进,直到评估或新版本批准)

三权规则:

  • 编制人可编辑并提交审核,不能批准自己的版本;
  • 审核人只能在 reviewing 决定通过/驳回;
  • 批准人只能在审核通过的固定内容哈希上批准;
  • 审核或批准动作记录 user、role binding、时间、内容哈希、意见和认证上下文;
  • 责任人被禁用/移出项目时,任务进入 assignment_blocked,不能继续流转;
  • 更换责任人属于受控事件,不覆盖历史签署信息。

若系统承载受法规要求约束的电子记录/签名,应先做适用性评估。21 CFR 11.10 对闭合系统强调授权访问、按许可顺序执行、权限检查、记录保护和带时间戳审计轨迹;因此这里推荐的服务端状态机、不可覆盖审计和固定内容哈希不仅是产品体验要求,也是更稳妥的合规架构基础。19 这不等于仅靠实现这些功能就自动达到 Part 11 合规,仍需结合组织程序、验证、培训、留存和适用法规完成独立评估。FDA 指南也建议基于对产品质量、安全和记录完整性的风险评估确定控制强度。20

10.3 主动询问创建者

当状态首次满足推进条件时,由事务 Outbox 写入 stage.ready_to_advance 事件。通知服务创建一条去重的待办和互动卡片:

“研发输入阶段的 4/4 个必需文档已批准,没有阻断项。是否进入‘设计开发’阶段?推进后 BD 将失去本工作流对话与研发文档访问权限。”

卡片提供:查看完成清单、查看权限变化、暂不推进、确认推进。确认接口再次实时校验条件和 expected_stage_version;若已有文档被撤回、stale 或成员发生变化,拒绝推进并列出差异。

提醒去重键可为 (stage_instance_id, readiness_revision)。首次立即站内提醒,24 小时未处理再次提醒,超过组织配置阈值可升级给项目创建者本人或指定项目监督人,但绝不自动推进。

10.4 阶段切换时的权限变化

阶段推进和权限生效在同一数据库事务中完成。以 BD 为例:

  • 事务提交前仍按商务阶段策略工作;
  • 提交后新的对话发送、文档列表、详情、下载、搜索、引用和 Agent 上下文读取立即按研发阶段策略拒绝;
  • 已打开页面下一次 API/SSE 校验时收到权限变化事件并转为只读/关闭;
  • 是否还能查看历史商务阶段记录由工作流策略单独配置,不与研发文档权限混在一起;
  • 默认建议允许 BD 查看自己参与的已结束商务阶段记录,但不能查看研发阶段消息和文档。

为此,聊天会话/消息必须绑定 workflow_instance_id 和 stage_instance_id。否则只有项目级 session,系统无法安全区分同一项目中商务与研发阶段的对话可见性。

11. 推荐数据模型

11.1 核心表

表 关键字段与说明
roles id、code、name、scope_type、status、is_system、version
permissions key、resource_type、action、risk_level
role_permissions role_id、permission_id、effect;首期只支持 allow,未匹配即 deny
role_bindings user_id、role_id、scope_type、scope_id、有效期、assigned_by
role_constraints SoD、互斥角色、作用域限制
workflow_definitions id、key、name、status、latest_published_version
workflow_versions workflow_id、version、status、schema_version、published_by/at、definition_hash
workflow_stage_defs workflow_version_id、key、name、position、optional、manual_gate、entry/exit_rule
workflow_doc_task_defs stage_def_id、key、title、template_version_id、required、blocking、default_enabled
workflow_access_policies target_type/id、project_role_id、action、effect
template_assets logical key、name、status
template_versions asset_id、version、blob_sha256、mime、size、scan_status、variable_schema
project_types key、name、product_domain、field_schema、status
compliance_profiles key、name、ruleset_version、status
project_type_workflows project_type_id、workflow_id、compliance_profile_id、recommended/allowed
project_workflow_instances project_id、workflow_version_id、instance_no、status、config_revision、created_by
project_stage_instances workflow_instance_id、stage_def_id、position、enabled、status、version
project_doc_task_instances stage_instance_id、doc_task_def_id、enabled、blocking、status、document_id
document_duty_assignments doc_task_instance_id、duty、user_id、assigned_by、valid_from/to
stage_advance_requests stage_instance_id、readiness_revision、status、requested_at、decided_by/at、reason
workflow_change_requests instance_id、from_revision、patch、impact、status、decisions
notifications user_id、event_id、type、status、dedupe_key、read_at、acted_at
audit_events actor、action、resource、before/after hash、reason、request_id、occurred_at

11.2 关键约束

CREATE UNIQUE INDEX uq_one_live_workflow_per_project
ON project_workflow_instances(project_id)
WHERE status IN ('active', 'awaiting_stage_confirmation', 'termination_requested');

CREATE UNIQUE INDEX uq_doc_duty_once
ON document_duty_assignments(doc_task_instance_id, duty)
WHERE valid_to IS NULL;

CREATE UNIQUE INDEX uq_stage_advance_revision
ON stage_advance_requests(stage_instance_id, readiness_revision);

此外应使用外键和 CHECK/触发器或领域事务确保:已发布版本不可更新;激活实例至少有一个启用阶段;一个实例最多一个 active stage;文档任务只能引用本实例阶段;批准动作绑定的内容哈希等于当前待批准版本。

11.3 现有表迁移映射

现有对象 迁移方式
projects.active_workflow_key 过渡期作为缓存字段,最终由 live instance 派生;不再作为唯一事实源
project_workflows 回填成 project_workflow_instances;已有 active 记录生成 legacy snapshot
workflow_runs 增加 instance/stage/task 外键,保留 run_id 与 input manifest
document_records.task_key/stage 回填关联 project_doc_task_instances;保留只读兼容字段一版
document_records.author/reviewer/approver 回填 document_duty_assignments;姓名字段只用于历史展示,不再鉴权
project_members.project_role 从单字符串迁移到 role_bindings;owner 单独保留创建人关系
前端 localStorage roles/projects/deliverables 首次升级只读取并提示导入;服务端确认成功后停止作为权威源

12. API 与领域服务

12.1 建议领域服务

  • IdentityService:账户、凭据、会话、MFA、撤销;
  • AuthorizationService:集中计算 Decision{allowed, reason_code, policy_version};
  • RoleService:角色版本、绑定、影响分析和职责分离;
  • WorkflowDefinitionService:草稿、校验、发布、退役;
  • ProjectWorkflowService:配置预览、激活、推进、完成、终止、受控变更;
  • DocumentTaskService:任务实例、三权指派、DocGov 联动;
  • NotificationService:Outbox 消费、去重、提醒与升级;
  • AuditService:不可覆盖审计事件、查询、导出和留存。

12.2 主要 API

GET/POST/PATCH        /api/v1/admin/users
POST                  /api/v1/admin/users/{id}/revoke-sessions
GET/POST/PATCH/DELETE /api/v1/admin/roles
GET/POST               /api/v1/admin/workflows
POST                   /api/v1/admin/workflows/{id}/versions/{v}/validate
POST                   /api/v1/admin/workflows/{id}/versions/{v}/publish
POST                   /api/v1/admin/templates
GET/POST/PATCH         /api/v1/admin/project-types

GET/PATCH              /api/v1/me
POST                   /api/v1/me/password
GET/DELETE              /api/v1/me/sessions
PATCH                  /api/v1/me/preferences

GET                    /api/v1/projects/{id}/settings
PUT                    /api/v1/projects/{id}/workflow-plan
POST                   /api/v1/projects/{id}/activation-preview
POST                   /api/v1/projects/{id}/workflow-instances/activate
POST                   /api/v1/workflow-instances/{id}/stages/{stage}/advance
POST                   /api/v1/workflow-instances/{id}/complete
POST                   /api/v1/workflow-instances/{id}/terminate-preview
POST                   /api/v1/workflow-instances/{id}/terminate
PUT                    /api/v1/document-tasks/{id}/duties

所有写操作带 Idempotency-Key 和 expected_version。错误使用稳定代码,如 WORKFLOW_ALREADY_ACTIVE、PLAN_CHANGED_RECONFIRM、STAGE_GATE_NOT_READY、ROLE_NOT_ELIGIBLE、SEPARATION_OF_DUTY_VIOLATION、WORKFLOW_ACCESS_DENIED。

12.3 服务端授权位置

路由中间件只解决“是否登录”;对象级授权必须在领域入口再做。所有项目、会话、消息、文档、附件、搜索、导出、任务和 SSE API 都调用同一个 AuthorizationService。不允许 handler 自行散落 if role == ...,也不允许相信请求体中的 user/role/project ownership。

13. UI 交互方案

13.1 主工作台

  • 顶部展示固定登录用户,不提供身份下拉切换;
  • 项目标题旁显示当前工作流、阶段和状态,不再展示可随点随切的三个按钮;
  • 有权限且无运行中工作流时显示“配置工作流”;运行中显示“查看流程”;
  • 对当前阶段无参与权的用户,输入框禁用并说明原因;不能仅靠禁用,发送接口也返回 403;
  • 右栏只加载服务端已授权的文档,避免先取全量再在浏览器过滤;
  • 创建者看到“待我确认”角标和阶段推进卡片。

13.2 工作流设计器

建议三栏布局:左侧阶段树,中间阶段/文档配置,右侧属性和权限策略。顶部固定展示 草稿/已发布/已退役、版本号、校验结果和发布按钮。发布操作弹出变更摘要:新增/删除阶段、模板变化、角色访问变化、与上一版本兼容性。

13.3 项目工作流配置器

采用向导而不是大表单:选择 → 裁剪阶段 → 裁剪文档 → 指派职责 → 权限影响 → 校验 → 激活确认。所有关闭项显示影响,例如“关闭《法规路径评估》会使 FDA QMSR 合规配置不完整”,对合规配置定义的必需项则直接禁止关闭。

14. 生产发布基线

本方案的业务功能不能脱离发布工程。近期代码已补上统一认证中间件、数据库迁移调用和前端多阶段镜像,但仍至少需要完成以下发布阻断项:

  1. 持久化认证:替换 MemoryStore 和进程内 token;生产不创建固定密码种子用户。
  2. 服务端 RBAC/ABAC:把角色、权限、策略和项目成员修改迁入数据库/API,前端只消费 capabilities。
  3. 会话安全:过期、轮换、撤销、登录限速、失败锁定、MFA、敏感动作再认证。
  4. 上传安全:请求硬上限、配额、类型/签名检查、扫描、隔离、Web 根外存储。
  5. 审计完整性:用户/角色/策略/模板/工作流/阶段/签署/导出都进入只追加审计;日志访问也审计。OWASP 建议记录用户管理、权限变更、管理操作、导入导出和文件上传,并保护日志不被未授权修改或删除。21
  6. 网络安全:移除 Access-Control-Allow-Origin: *,使用允许域名;TLS、HSTS、CSP、frame/referrer 等由网关和应用共同设置。22
  7. 持久异步任务:task run/event、worker lease、重启恢复、Outbox;只能在文档与事件落库成功后发布终态。
  8. 机密管理:生产拒绝默认密码,密钥不进入镜像/前端/日志,使用 Secret 管理并轮换。
  9. 备份与恢复:数据库、CAS、审计、模板版本一致性备份;实际演练 RPO/RTO。
  10. 验证与发布证据:需求—设计—测试追溯、迁移报告、权限负例、性能、安全扫描、SBOM、部署/回滚记录。

15. 分阶段实施路线

Phase 0:决策冻结与安全止血(3–5 天)

  • 冻结新的本地状态功能;明确服务端为唯一权威;
  • 从生产 UI 删除任意身份切换和模拟入口;
  • 定稿角色、权限、项目成员、文档职责术语;
  • 关闭生产默认账号/密码、宽 CORS 和本地认证 fallback;
  • 编制所有现有 API 的资源—动作—条件矩阵。

完成门禁:生产 bundle 不含切换入口/种子密码;匿名 API 401;跨项目、跨阶段、跨文档负例 403。

Phase 1:账户与授权权威化(2 周)

  • 持久化 users/credentials/sessions/roles/permissions/bindings;
  • 实现统一 AuthorizationService;
  • 把系统设置中的用户和角色操作改成真实 API;
  • 建立项目成员 CRUD 与项目角色绑定;
  • 前端不再从 localStorage 判定权限,后端返回 capabilities。

完成门禁:重启后账户、角色、会话策略仍在;禁用账户立即失效;每个资源动作均有允许/拒绝测试。

Phase 2:工作流设计器与模板库(2–3 周)

  • 建立工作流定义/版本/阶段/文档/策略表;
  • 管理端完成草稿、校验、发布、退役;
  • 模板上传、扫描、版本和预览;
  • 建立医疗器械与非医疗纯软件两套首批工作流;
  • 旧静态 catalog 作为 bootstrap seed,运行时改读数据库缓存。

完成门禁:已发布版本不可变;旧项目不受新版本影响;非法/死锁工作流不能发布。

Phase 3:项目配置、冻结和阶段门禁(2–3 周)

  • 项目设置独立页面;
  • planning、activation preview、二次确认、单活动实例约束;
  • 阶段/文档开关和三权分配;
  • 文档批准驱动 readiness,创建者确认推进;
  • 阶段级聊天、文档、搜索和 Agent 上下文权限。

完成门禁:运行中不能选择其他工作流;激活后不能直接改开关/职责;BD 进入研发阶段后无法通过任何接口访问研发内容。

Phase 4:可靠任务、审计与通知(2 周)

  • 持久化任务和事件、重连/重启恢复;
  • Outbox 通知、推进卡片、去重和升级;
  • 审计日志防篡改、查询和导出;
  • stale、责任人失效和配置变更成为正式阻断项。

Phase 5:生产验收与灰度(2 周)

  • 空库/旧库升级双测,备份恢复演练;
  • 完整权限矩阵、并发、幂等、故障注入、上传和渗透测试;
  • 医疗/非医疗两套黄金项目 E2E;
  • test 环境稳定运行一个发布周期,随后灰度 main。

按熟悉现有代码的 3–4 人团队估算,发布级闭环约 8–12 周。若只有 1–2 人,应先交付 Phase 0–1 的安全账户/RBAC,再做工作流设计器,不建议把所有能力压缩进一次大改。

16. 验收测试矩阵

16.1 身份与权限

  • 用户不能在 UI、请求头、请求体或 localStorage 中更换自己的身份;
  • 修改 URL 中 project/workflow/stage/doc/run ID 不会越权;
  • 角色权限变更后旧会话在下一请求即使用新策略;
  • 角色删除前能列出用户、项目和工作流策略引用;
  • 至少一个超级管理员保护有效,普通管理员不能删除最后一个;
  • 同一文档的 author 与 approver 默认不能为同一用户。

16.2 工作流定义

  • 草稿可编辑,已发布版本任何更新均被拒绝;
  • 模板新版本不改变已激活项目的哈希;
  • 零阶段、重复键、无模板、未知角色、无可参与人员、不可达阶段无法发布;
  • 退役版本不能用于新项目,但旧实例可继续。

16.3 项目实例

  • 新项目初始无 active 工作流;
  • 两个并发激活请求最多一个成功;
  • 激活预览后配置变化会要求重新确认;
  • active 工作流存在时,选择另一个返回 409;
  • completed/terminated 后可新建下一实例;
  • 激活后关闭阶段/文档、替换模板或直接换责任人均被拒绝。

16.4 阶段与文档

  • 任一必需文档未批准、stale、有阻断提案或任务运行中时不能推进;
  • 最后一份必需文档批准只产生一个推进待办;
  • 创建者确认时条件已变化则不推进;
  • 推进事务失败时阶段和权限均保持旧状态;
  • BD 在研发阶段的对话、列表、详情、搜索、下载、导出、SSE 和 Agent 工具读取均为拒绝;
  • 文档批准绑定内容哈希,批准后内容变化会产生新版本并重新走审核。

16.5 发布与恢复

  • 应用/worker/数据库短暂故障不会产生两个终态或丢失推进通知;
  • 数据库和 CAS 能从备份恢复到一致点;
  • 审计可重建用户、权限、模板、工作流、阶段和签署变更顺序;
  • 医疗项目启用所选合规配置的必需节点,非医疗软件不被强制加载法规步骤;
  • 生产镜像、配置和数据库没有默认密码或测试身份入口。

17. 建议优先创建的研发 Epic

Epic 目标 依赖 优先级
IAM-01 持久化账户与会话 替换内存用户/token,支持撤销与过期 DB P0
AUTHZ-01 权限策略服务 服务端 RBAC + 项目/阶段/文档条件 IAM-01 P0
UI-01 移除身份模拟与本地权威状态 生产 fail closed,权限来自服务端 IAM-01/AUTHZ-01 P0
ROLE-01 角色与权限管理 API 管理端真实持久化、影响分析、绑定 AUTHZ-01 P0
WFDEF-01 工作流版本模型 定义、阶段、文档、策略、发布 ROLE-01 P1
TMPL-01 安全模板库 上传、扫描、版本、变量 schema WFDEF-01 P1
PTYPE-01 项目类型/合规配置 医疗与非医疗首批模型 WFDEF-01 P1
WFINST-01 项目配置与激活冻结 planning、preview、单活、快照 WFDEF-01/TMPL-01 P1
DOC-01 文档任务与三权解耦 文档任务实例、职责分离、DocGov 接入 WFINST-01 P1
STAGE-01 阶段门禁与推进 readiness、创建者确认、权限原子变化 DOC-01/AUTHZ-01 P1
NOTIFY-01 主动提醒 Outbox、待办、互动卡片、去重升级 STAGE-01 P1
RELEASE-01 发布验收 CI、迁移、恢复、安全、灰度 全部 P0/P1

18. 最终建议

这次改造不应被理解为“给现有设置弹窗再加几个 Tab”。真正需要建立的是一条不可绕过的权威链:固定登录主体 → 服务端角色与项目关系 → 已发布工作流版本 → 项目冻结快照 → 阶段与文档状态机 → 责任人签署 → 创建者推进 → 全程审计。

建议先完成账户和授权权威化,再建设工作流设计器。否则管理员即使能在页面上创建角色和流程,服务端仍无法可靠执行这些策略,功能越丰富,越权和状态不一致的风险越大。工作流首期采用线性阶段、单活动实例、激活后严格冻结,是在可用性、实现复杂度和受控性之间最稳妥的平衡。

对医疗器械项目,应通过合规配置逐步提高控制强度,并保留适用性评估、版本、审计和签署证据;对非医疗纯软件项目,应复用同一工作流引擎,但允许选择 compliance_profile=none,避免把法规流程硬编码进产品域。这样系统才能从当前的医疗器械业务原型,演进为可发布、可扩展、可审计的通用项目工作流平台。

Sources


  1. 仓库源码,internal/server/auth_middleware.go,统一保护非公开 API;internal/db/migrate.go,Goose 迁移执行,访问于 2026-09-11。 ↩︎

  2. 仓库源码,deploy/app/Dockerfile,包含 Node 前端构建与 web/dist 复制,访问于 2026-09-11。 ↩︎

  3. 仓库源码,internal/bizdev/service.go,数据库连接、迁移及生产失败关闭逻辑,访问于 2026-09-11。 ↩︎

  4. 仓库源码,internal/auth/store.go 与 internal/auth/service.go,内存用户存储与进程内 token,访问于 2026-09-11。 ↩︎

  5. 仓库源码,web/src/App.tsx 与 web/src/data/storage.ts,角色、人员、项目和交付物的浏览器持久化,访问于 2026-09-11。 ↩︎

  6. 仓库源码,internal/server/auth_handlers.go,管理员接口以 role-admin 硬编码判断;web/src/components/admin/AdminSettingsModal.tsx,角色权限编辑主要调用前端状态,访问于 2026-09-11。 ↩︎

  7. 仓库源码,internal/projectworkflow/catalog.go,三个静态工作流及单一 stage/task 定义,访问于 2026-09-11。 ↩︎

  8. 仓库源码,internal/projectworkflow/service.go 与 deploy/postgres/goose/00010_2026-09-11-project-workflows-and-lineage.sql,新项目默认 main 及当前切换模型,访问于 2026-09-11。 ↩︎

  9. 仓库源码,web/src/components/workflow/ProjectWorkflowSwitcher.tsx,直接切换及冲突后自动重试行为,访问于 2026-09-11。 ↩︎

  10. 仓库源码,web/src/types/workbench.ts 与 web/src/components/project/ProjectMembersModal.tsx,项目成员角色与文档职责混用,访问于 2026-09-11。 ↩︎

  11. 仓库源码,web/src/types/workbench.ts 与 internal/projectworkflow/types.go,固定阶段枚举和自由文本设备类型,访问于 2026-09-11。 ↩︎

  12. OWASP Cheat Sheet Series, “Authorization Cheat Sheet,” 访问于 2026-09-11。 ↩︎

  13. NIST, “Role Based Access Control,” 含 INCITS 359 RBAC 模型说明,更新于 2026-03-04。 ↩︎

  14. NIST, Kuhn, Coyne, Weil, “Adding Attributes to Role-Based Access Control,” 2010。 ↩︎

  15. NIST, “SP 800-63B-4: Digital Identity Guidelines — Authentication and Authenticator Management,” 2025-07。 ↩︎

  16. OWASP Cheat Sheet Series, “File Upload Cheat Sheet,” 访问于 2026-09-11。 ↩︎

  17. U.S. FDA, “Quality Management System Regulation (QMSR),” 更新于 2026-02-02。 ↩︎

  18. ISO, “ISO 13485:2016 — Medical devices — Quality management systems — Requirements for regulatory purposes,” 2016,2025 年复审确认。 ↩︎

  19. Electronic Code of Federal Regulations, “21 CFR § 11.10 — Controls for closed systems,” 访问于 2026-09-11。 ↩︎

  20. U.S. FDA, “Part 11, Electronic Records; Electronic Signatures — Scope and Application,” 2003-09,访问于 2026-09-11。 ↩︎

  21. OWASP Cheat Sheet Series, “Logging Cheat Sheet,” 访问于 2026-09-11。 ↩︎

  22. 仓库源码,internal/server/server.go,当前 CORS 允许任意来源,访问于 2026-09-11。 ↩︎