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>
This commit is contained in:
@@ -1,684 +1,3 @@
|
||||
# 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]
|
||||
|
||||
建议把目标系统定义为一个“受控的项目工作流平台”,核心由五层组成:
|
||||
|
||||
```text
|
||||
账户主体 ── 组织/系统角色 ── 项目成员关系
|
||||
│
|
||||
▼
|
||||
不可变工作流版本 ──> 项目工作流实例 ──> 阶段实例 ──> 文档任务实例
|
||||
│ │
|
||||
├─ 对话参与策略 └─ 编制/审核/批准职责
|
||||
├─ 文档可见策略
|
||||
└─ 阶段推进门禁 + 审计 + 通知
|
||||
```
|
||||
|
||||
最重要的产品决策是:
|
||||
|
||||
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 在商务阶段可对话,进入研发阶段后不可对话且不可看研发文档”。建议采用组合策略:
|
||||
|
||||
```text
|
||||
允许 = 已认证
|
||||
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 定义结构
|
||||
|
||||
```text
|
||||
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`。推荐交互:
|
||||
|
||||
```text
|
||||
选择工作流版本
|
||||
→ 配置阶段/文档开关
|
||||
→ 指派每份启用文档的三权
|
||||
→ 系统校验
|
||||
→ 生成只读预览与 plan_hash
|
||||
→ 用户二次确认
|
||||
→ 单事务创建实例/快照/首阶段/文档任务/审计
|
||||
```
|
||||
|
||||
激活确认弹窗应明确展示:工作流名称和版本、启用阶段数、启用/关闭文档数、三权缺口、激活后哪些配置会冻结、当前参与者权限将如何变化。用户勾选“我理解激活后不能直接修改”并再次点击确认。
|
||||
|
||||
服务端不能只信任 `confirmed=true`。建议 `POST /activation-preview` 返回短期 `confirmation_token + plan_hash + expected_project_version`;真正激活时必须三者一致。若期间成员、责任人、模板或项目配置变化,返回 409 和差异摘要,要求重新预览确认。
|
||||
|
||||
### 9.3 工作流实例状态机
|
||||
|
||||
```text
|
||||
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 阶段状态机
|
||||
|
||||
```text
|
||||
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` 继续负责正文版本和受控生命周期。
|
||||
|
||||
```text
|
||||
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 关键约束
|
||||
|
||||
```sql
|
||||
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
|
||||
|
||||
```text
|
||||
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`](../internal/server/auth_middleware.go),统一保护非公开 API;[`internal/db/migrate.go`](../internal/db/migrate.go),Goose 迁移执行,访问于 2026-09-11。
|
||||
[^2]: 仓库源码,[`deploy/app/Dockerfile`](../deploy/app/Dockerfile),包含 Node 前端构建与 `web/dist` 复制,访问于 2026-09-11。
|
||||
[^3]: 仓库源码,[`internal/bizdev/service.go`](../internal/bizdev/service.go),数据库连接、迁移及生产失败关闭逻辑,访问于 2026-09-11。
|
||||
[^4]: 仓库源码,[`internal/auth/store.go`](../internal/auth/store.go) 与 [`internal/auth/service.go`](../internal/auth/service.go),内存用户存储与进程内 token,访问于 2026-09-11。
|
||||
[^5]: 仓库源码,[`web/src/App.tsx`](../web/src/App.tsx) 与 [`web/src/data/storage.ts`](../web/src/data/storage.ts),角色、人员、项目和交付物的浏览器持久化,访问于 2026-09-11。
|
||||
[^6]: 仓库源码,[`internal/server/auth_handlers.go`](../internal/server/auth_handlers.go),管理员接口以 `role-admin` 硬编码判断;[`web/src/components/admin/AdminSettingsModal.tsx`](../web/src/components/admin/AdminSettingsModal.tsx),角色权限编辑主要调用前端状态,访问于 2026-09-11。
|
||||
[^7]: 仓库源码,[`internal/projectworkflow/catalog.go`](../internal/projectworkflow/catalog.go),三个静态工作流及单一 stage/task 定义,访问于 2026-09-11。
|
||||
[^8]: 仓库源码,[`internal/projectworkflow/service.go`](../internal/projectworkflow/service.go) 与 [`deploy/postgres/goose/00010_2026-09-11-project-workflows-and-lineage.sql`](../deploy/postgres/goose/00010_2026-09-11-project-workflows-and-lineage.sql),新项目默认 `main` 及当前切换模型,访问于 2026-09-11。
|
||||
[^9]: 仓库源码,[`web/src/components/workflow/ProjectWorkflowSwitcher.tsx`](../web/src/components/workflow/ProjectWorkflowSwitcher.tsx),直接切换及冲突后自动重试行为,访问于 2026-09-11。
|
||||
[^10]: 仓库源码,[`web/src/types/workbench.ts`](../web/src/types/workbench.ts) 与 [`web/src/components/project/ProjectMembersModal.tsx`](../web/src/components/project/ProjectMembersModal.tsx),项目成员角色与文档职责混用,访问于 2026-09-11。
|
||||
[^11]: 仓库源码,[`web/src/types/workbench.ts`](../web/src/types/workbench.ts) 与 [`internal/projectworkflow/types.go`](../internal/projectworkflow/types.go),固定阶段枚举和自由文本设备类型,访问于 2026-09-11。
|
||||
[^12]: OWASP Cheat Sheet Series, “[Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
[^13]: NIST, “[Role Based Access Control](https://csrc.nist.gov/Projects/Role-Based-Access-Control),” 含 INCITS 359 RBAC 模型说明,更新于 2026-03-04。
|
||||
[^14]: NIST, Kuhn, Coyne, Weil, “[Adding Attributes to Role-Based Access Control](https://csrc.nist.gov/files/pubs/journal/2010/06/adding-attributes-to-rolebased-access-control/final/docs/kuhn-coyne-weil-10.pdf),” 2010。
|
||||
[^15]: NIST, “[SP 800-63B-4: Digital Identity Guidelines — Authentication and Authenticator Management](https://csrc.nist.gov/pubs/sp/800/63/B/4/final),” 2025-07。
|
||||
[^16]: OWASP Cheat Sheet Series, “[File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
[^17]: U.S. FDA, “[Quality Management System Regulation (QMSR)](https://www.fda.gov/medical-devices/postmarket-requirements-devices/quality-management-system-regulation-qmsr),” 更新于 2026-02-02。
|
||||
[^18]: ISO, “[ISO 13485:2016 — Medical devices — Quality management systems — Requirements for regulatory purposes](https://www.iso.org/standard/59752.html),” 2016,2025 年复审确认。
|
||||
[^19]: Electronic Code of Federal Regulations, “[21 CFR § 11.10 — Controls for closed systems](https://www.ecfr.gov/current/title-21/chapter-I/subchapter-A/part-11/subpart-B/section-11.10),” 访问于 2026-09-11。
|
||||
[^20]: U.S. FDA, “[Part 11, Electronic Records; Electronic Signatures — Scope and Application](https://www.fda.gov/regulatory-information/search-fda-guidance-documents/part-11-electronic-records-electronic-signatures-scope-and-application),” 2003-09,访问于 2026-09-11。
|
||||
[^21]: OWASP Cheat Sheet Series, “[Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
[^22]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go),当前 CORS 允许任意来源,访问于 2026-09-11。
|
||||
本文档已迁至 [remediation/2026-09-11-production-ready-workflow-governance-plan.md](remediation/2026-09-11-production-ready-workflow-governance-plan.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,268 +1,3 @@
|
||||
# Chat Agent System 功能缺陷深度审计与整改方案
|
||||
# 已迁移
|
||||
|
||||
## 执行摘要
|
||||
|
||||
系统已经具备较完整的业务原型:多轮对话、意图识别、项目工作流、智能体小队、RAG、受控文档、自由文档、长任务流、聊天历史、摘要与导出等模块均有代码和测试资产。架构方向也基本正确:对话、项目协调、执行三层分离,确定性权限和状态转换应由服务端控制。[^1]
|
||||
|
||||
但当前版本不应按“多人生产协作系统”发布。核心原因不是功能数量不足,而是四条基础链路尚未闭环:
|
||||
|
||||
1. **身份与授权链路失守**:大量业务接口不要求登录,或直接信任 `X-User-ID`、查询参数、请求体中的用户与角色;攻击者可伪造身份访问或修改会话、项目、文档、任务和资产。这与系统设计中的多用户隔离目标直接冲突,也属于典型的对象级授权缺失(BOLA/IDOR)。[^2][^3]
|
||||
2. **数据库发布链路失效**:生产 Compose 仅挂载一个明显过时的 `system_init.sql`,而新增能力依赖十余张表和多批迁移;Docker 初始化脚本又只在空数据卷首次启动时执行。当前 dev 实库检查已证实缺少工作流、自由文档等 7 张关键表及消息导出 4 个关键字段。[^4][^5][^6]
|
||||
3. **前端交付链路不完整**:生产应用镜像只编译并复制 Go 二进制,没有构建或复制 `web/dist`;服务端虽然尝试托管 SPA,但容器内没有对应资产,因此按现有 Dockerfile 部署时首页会返回 404。[^7][^8]
|
||||
4. **长任务恢复链路不持久**:任务运行和 SSE 事件只保存在进程内存中,保留时间仅一小时;进程重启后查询、重连、取消均失效。更严重的是,代码先发送 `done` 事件,再执行最终落库;最终落库失败时客户端已经把任务视为成功。[^9]
|
||||
|
||||
综合判断:系统目前处于“功能丰富的集成原型 / dev 验证阶段”,不具备生产发布条件。建议立即冻结外网暴露和 main 发布,将下述 P0 项全部关闭后再进入真实 Agent 联调。
|
||||
|
||||
## 审计范围与证据强度
|
||||
|
||||
本次覆盖 Go 后端、React/Vite 前端、PostgreSQL 初始化与迁移、Docker Compose、PI Agent Runner、知识库、任务状态、文件存储、鉴权/RBAC、测试报告和当前 dev 运行环境。
|
||||
|
||||
证据分为三类:
|
||||
|
||||
- **已证实**:可由源码直接推导,或已通过只读运行态/数据库检查确认。
|
||||
- **高概率风险**:代码配置与权威文档明确冲突,但本轮未执行攻击性验证。
|
||||
- **待联调验证**:需要完整 Go/Node 工具链、真实 Agent 或生产拓扑才能最终判定。
|
||||
|
||||
本轮工作区没有 `go`、`node`、`npm`、`psql` 客户端,因此 `go test ./...`、`go vet ./...`、`npm test`、`npm run build` 均因“命令不存在”未执行,而不是测试失败。通过 Docker 只读检查确认:dev PostgreSQL 与两个 Agent 容器运行,app 容器未创建;test/main 未运行。仓库包含 107 个 Go 测试文件和 44 个前端测试文件,但多个数据库、真实 Agent 和质量评估测试会在环境未配置时跳过。最近测试报告也明确标注真实 PI Agent 端到端验收尚未完成。[^10]
|
||||
|
||||
## 系统能力地图
|
||||
|
||||
| 能力域 | 已有实现 | 当前完整度判断 | 主要缺口 |
|
||||
|---|---|---:|---|
|
||||
| 对话与意图 | 阻塞/流式对话、意图识别、候选动作、卡片交互 | 中 | 核心接口未统一鉴权;客户端可覆盖用户/项目身份 |
|
||||
| 项目工作流 | 项目创建、工作流切换、运行记录、血缘 | 中低 | 数据库基线缺表;项目成员模型缺失;多数读取/运行接口缺对象授权 |
|
||||
| 受控文档 | 编制、审核、批准、驳回、认领、租约、审计 | 中 | 部分状态动作已鉴权,但读取、批注、正文、租约接口仍可伪造身份 |
|
||||
| 自由文档 | 私密、共享、版本、乐观锁、回收站 | 中低 | HTTP 身份完全依赖可伪造 header/query;实际 dev 库缺表 |
|
||||
| 长任务 | 后台 worker、SSE 订阅、取消、完成投影 | 中低 | run/event 内存态;重启不可恢复;完成事件时序错误;无归属校验 |
|
||||
| 文件与材料 | CAS、SHA-256 去重、项目资产自动装配 | 中 | 上传无真正请求上限/内容校验/项目授权;资产清单可匿名枚举 |
|
||||
| RAG/记忆 | embedding、rerank、聊天搜索、摘要、案例检索 | 中 | DB 失败静默转内存;摘要仍为规则型;共享 KB 隔离策略未定 |
|
||||
| 用户与 RBAC | 登录、注册、bcrypt、管理员页面、前端权限矩阵 | 低 | 后端账户内存态、token 无过期、前端本地明文回退、RBAC 主要在 UI |
|
||||
| 部署运维 | dev/test/main Compose、健康检查、日志 | 低 | 生产 schema 错配、前端未打包、迁移无执行器、健康检查恒成功 |
|
||||
| 测试与质量 | 大量单元/集成测试、专项测试报告 | 中 | 无仓库 CI;真实 DB/Agent 测试可跳过;缺安全负例、迁移升级、重启恢复测试 |
|
||||
|
||||
## 缺陷清单与优先级
|
||||
|
||||
### P0:发布阻断项
|
||||
|
||||
| 编号 | 缺陷 | 证据与影响 | 整改目标 |
|
||||
|---|---|---|---|
|
||||
| P0-01 | 服务端身份可伪造,核心 API 普遍缺少授权 | `authenticateUser` 在无 token 时接受任意有效 `X-User-ID`;路由层没有统一鉴权中间件。聊天、任务、上下文、会话、文档读取/批注/正文/租约等处理器直接使用客户端 ID/角色。会导致跨用户读写、冒名审批、越权运行 Agent、数据删除或篡改。[^2][^11] | 所有非公开 API 必须先认证;用户 ID 只来自服务端会话;每次访问按项目成员、对象归属和动作权限授权;默认拒绝。 |
|
||||
| P0-02 | 前端在后端不可用时自动切换为“伪登录” | 浏览器内置管理员和测试账户,密码以明文写入代码/`localStorage`;后端网络错误时可生成本地 token 并继续进入 UI。管理员操作也会静默降级为本地修改。用户会看到“成功”,但服务端未发生任何可信变更。[^12] | 生产构建彻底移除本地认证回退和种子账户;后端不可用必须 fail closed;Demo 模式用独立构建标志、独立域名和醒目标识。 |
|
||||
| P0-03 | 受控文档接口存在任意路径写入面 | 正文保存接口不鉴权,接受客户端 `user_id`、`user_role` 和 `work_dir`;领域层将该目录直接写入文档记录并创建 `<work_dir>/output.md`。具备服务进程权限的任意目录都可能被覆盖或创建。[^13] | 删除 HTTP 层 `work_dir` 覆盖;由服务端根据 doc/run ID 解析规范化工作区;使用 `filepath.Rel`/`os.Root` 等强制限制在数据根目录内;路径拒绝测试覆盖绝对路径、`..`、符号链接。 |
|
||||
| P0-04 | 管理对账接口可匿名操作任意目录 | `/api/v1/admin/workspaces/reconcile` 没有管理员鉴权,直接读取并可能改写客户端指定目录下的 `workspace.json`。[^14] | 仅管理员/内部 job 可调用;请求只接受 run ID,不接受路径;工作区从数据库映射;对账动作写入审计日志。 |
|
||||
| P0-05 | 生产数据库 schema 与代码不兼容 | main 使用 72 行的 `system_init.sql`,只含基础项目/用户/会话/消息/任务表,字段也与当前查询不一致;当前代码依赖 `project_workflows`、`workflow_runs`、`document_lineage`、`freeform_*`、`document_records` 等。main 还使用不带 pgvector 的 `postgres:16-alpine`。[^4][^15] | 建立单一、版本化、可重复执行的迁移链;应用启动前执行迁移并校验目标版本;任何缺表/缺列必须拒绝启动;dev/test/main 使用同一 schema 基线。 |
|
||||
| P0-06 | 现有数据卷不会自动应用新增迁移 | Compose 只挂载初始化脚本,没有迁移执行服务。官方 PostgreSQL 镜像在数据目录非空时跳过 `/docker-entrypoint-initdb.d`,所以修改 init SQL 也无法升级已有卷。当前 dev 实库缺 7 张关键表和 4 个消息字段即为直接证据。[^5][^6] | 引入 `goose`、`golang-migrate` 或等价迁移器;每个版本以事务执行、写版本表、支持向前兼容与回滚预案;发布流水线做空库和旧库升级双测。 |
|
||||
| P0-07 | 生产应用镜像不包含前端 | Dockerfile 没有 Node 构建阶段,最终镜像只复制 `/server`;服务端 SPA 逻辑要求 `web/dist`。Compose 没有单独前端或反向代理服务。[^7][^8] | 增加 Node builder 生成 `web/dist`,再复制进最终镜像;或独立 Nginx 前端服务。镜像验收必须请求 `/`、JS/CSS 静态资源及 SPA 深链接。 |
|
||||
| P0-08 | 数据库不可用会静默退化为内存模式 | `NewService` 的连接/`Ping` 错误被吞掉,随后所有核心服务用 `nil pool` 构造内存实现;健康检查仍固定返回 `status=ok`。生产可能表面存活但所有新数据重启即失。[^16][^17] | prod/test 数据库不可用或 schema 不匹配时拒绝启动;仅显式 `ALLOW_IN_MEMORY=true` 的本地 Demo 可降级;readiness 必须检查 DB、schema、存储和 Runner。 |
|
||||
|
||||
### P1:高风险与核心可靠性项
|
||||
|
||||
| 编号 | 缺陷 | 证据与影响 | 整改目标 |
|
||||
|---|---|---|---|
|
||||
| P1-01 | 长任务与 SSE 事件不持久 | `runs` 和 `events` 存在进程内 map,完成后一小时驱逐;重启后 GET/events/cancel 全部返回 not found。现有 `workflow_runs` 只保存摘要,不能重放事件或恢复 worker。[^9] | 建立 `task_runs`、`task_run_events`、worker lease/heartbeat;SSE 从事件表按序号重放;启动时对 running 任务做恢复/失败对账。 |
|
||||
| P1-02 | `done` 先于最终落库 | worker 在 Finalizer 前发送 `EventDone`;若 Finalizer 失败,客户端已停止订阅,之后的 `finalizing_failed` 不会被看到。[^9] | 执行结果先持久化与投影,事务成功后再发唯一终态事件;终态不可逆且事件/状态一致。 |
|
||||
| P1-03 | 任务查询、订阅和取消无归属校验 | run ID 是时间戳格式,相关处理器不认证、不比较 `record.UserID/ProjectID`。攻击者可观察或取消他人任务。 | run API 全部认证;按项目成员和发起人授权;run ID 改用 CSPRNG UUID/ULID;增加跨用户 403 测试。 |
|
||||
| P1-04 | 缺少项目成员与项目内角色权威模型 | 设计要求用户在不同项目承担不同角色,但数据库没有 `project_members`/角色指派表;`GetProject` 忽略传入的 user ID,项目可见性用“创建人或有会话”等启发式条件;前端组件在本地维护成员与权限。[^18] | 新增项目成员、项目角色、文档责任人、邀请/退出/停用表;所有项目对象访问采用关系型授权(ReBAC/ABAC),前端只展示服务端返回能力。 |
|
||||
| P1-05 | 认证账户与会话只在内存 | 后端每次启动重新生成种子用户;注册、改密、审批和 token 都不持久,token 无绝对/空闲过期,禁用用户的既有 token 也没有统一撤销策略。[^19] | 建立持久化账户/凭据/会话表;token 只存哈希;设置绝对与空闲过期、轮换与全端注销;密码策略、登录限速、失败锁定、审计齐备。 |
|
||||
| P1-06 | 上传和 JSON 请求缺资源上限 | 上传使用 `ParseMultipartForm(64<<20)` 后 `io.ReadAll`;该参数是内存阈值,不是总请求硬上限。未见 `http.MaxBytesReader`,多数 JSON 直接解码。攻击者可消耗内存、临时磁盘、CAS 存储和 Agent 调用成本。[^20] | 全局与端点级 body 上限;流式写 CAS 并计算哈希;白名单扩展、魔数/MIME 复核、文件名长度、配额、恶意文件扫描;用户/IP/项目限速。 |
|
||||
| P1-07 | Mermaid 使用宽松安全模式 | Agent/用户内容会进入 Mermaid,配置为 `securityLevel: 'loose'`,官方说明该模式允许 HTML 和点击功能;最终 SVG 用 `dangerouslySetInnerHTML` 注入。[^21][^22] | 改为 `strict` 或 `sandbox`;禁用点击/HTML label;必要时用可信 SVG sanitizer;增加恶意 Mermaid 回归集。 |
|
||||
| P1-08 | 密钥与本地配置基线不安全 | 当前 `.env` 权限为 `664`,关键密码命中仓库已知默认值;代码、示例和前端也包含默认管理员/测试密码。生产校验只拦截部分默认值。 | 立即轮换全部已知默认密码和 API key;`.env` 设为 `600`;生产使用 Docker secrets/Vault;构建和启动阶段拒绝任意默认/低强度密钥。 |
|
||||
| P1-09 | CORS 和传输边界过宽 | 全局 `Access-Control-Allow-Origin: *`,还允许伪身份 header;main 默认把 app 绑定 `0.0.0.0`,Compose 内没有 TLS/反向代理/安全响应头。[^23] | 明确允许域名;删除身份 header;入口网关终止 TLS,设置 HSTS/CSP/frame/referrer 等;Runner 仅内部网络且使用服务间认证。 |
|
||||
| P1-10 | Agent Runner 缺服务间认证与租户隔离 | Runner HTTP 接口可执行带 read/write/edit/web 工具的 Agent,只依赖 Docker 网络隔离;workspace 虽做路径归一化,但请求没有签名/token,所有任务共享同一容器环境和密钥。 | mTLS 或短期签名 token;每任务容器/沙箱、只读基础镜像、最小工具和网络 allowlist;工作区/密钥按租户隔离;输出文件做大小和路径校验。 |
|
||||
|
||||
### P2:能力完善项
|
||||
|
||||
1. **语义摘要仍未完成**:backlog 已明确当前摘要需替换为语义摘要;应加入事实引用、增量摘要、质量评估和失败回退。[^24]
|
||||
2. **报价输入与复核不足**:报价模块缺输入范围校验和轻量复核;对于商务决策应建立金额、税率、汇率、数量和审批阈值的确定性规则。[^24]
|
||||
3. **小队降级和 trace 并发缺陷**:非关键步骤不能安全降级,并行 trace 序号需要原子化;应统一 step 状态机、幂等键和事件序号。[^24]
|
||||
4. **数据留存、加密与删除策略缺失**:聊天、材料、Agent trace 可能包含客户和医疗器械研发敏感信息;需要数据分级、字段加密、保留期、合法删除、备份清除和访问审计。[^24]
|
||||
5. **共享知识库污染面未界定**:三环境共享 KB 是有意设计,但测试/开发写入、索引版本和法规生效版本可能污染生产检索;至少应只读发布、索引版本化和环境指针隔离。
|
||||
6. **可观测性不足**:已有结构化 `slog`,但缺少统一指标、分布式 trace、SLO、告警和审计防篡改;错误处理中大量忽略 DB 写入错误,事故时难以确认权威状态。
|
||||
7. **API 契约与错误模型不统一**:同时存在纯文本错误、不同 JSON 字段、200/202 混用;应提供 OpenAPI、稳定错误码、版本策略和契约测试。
|
||||
8. **会话/项目缓存生命周期不受控**:服务端 session map 缺容量与租户配额;长时间运行可能积累内存,并在多副本部署时出现状态不一致。
|
||||
|
||||
## 关键根因
|
||||
|
||||
这些缺陷并非彼此独立,主要来自五个系统性根因:
|
||||
|
||||
1. **Demo 与生产路径未隔离**:内存 fallback、本地认证、种子账户、默认项目都进入同一生产代码路径。
|
||||
2. **权限在 UI 和领域方法之间零散实现**:没有统一的认证中间件、授权策略服务和对象归属查询,导致新增端点很容易漏检。
|
||||
3. **缺少单一数据库演进机制**:init SQL、独立 migrations、dev 实库、main 初始化文件四套状态并存,没有 schema version 门禁。
|
||||
4. **异步任务没有 durable state machine**:内存 observer 被当作持久化事件系统使用,执行、投影、通知之间没有事务/Outbox 边界。
|
||||
5. **测试偏功能正向路径**:单元测试丰富,但发布级测试没有强制覆盖真实数据库升级、进程重启、跨用户负例、容器镜像和真实 Agent。
|
||||
|
||||
## 目标整改架构
|
||||
|
||||
```text
|
||||
Browser
|
||||
│ HTTPS + HttpOnly/Secure/SameSite cookie
|
||||
▼
|
||||
API Gateway / Go API
|
||||
├─ Authentication middleware
|
||||
├─ Authorization policy (user × project × object × action)
|
||||
├─ Request limits / rate limits / audit
|
||||
│
|
||||
├──────── PostgreSQL (single migration chain)
|
||||
│ ├─ users / sessions / project_members
|
||||
│ ├─ documents / versions / audit
|
||||
│ └─ task_runs / task_run_events / outbox
|
||||
│
|
||||
├──────── CAS (bounded, scanned, tenant-scoped)
|
||||
│
|
||||
└──────── Agent Dispatcher ── signed request ── isolated Runner
|
||||
└─ per-run workspace sandbox
|
||||
```
|
||||
|
||||
服务端必须成为唯一权威源:浏览器不能声明“我是谁”“我在项目里是什么角色”“我可以写哪个目录”;它只能提交资源标识和业务意图。身份来自会话,成员关系和权限来自数据库,工作区来自服务端映射,终态来自持久化状态机。
|
||||
|
||||
## 分阶段整改计划
|
||||
|
||||
### 阶段 0:立即止血(0–2 天)
|
||||
|
||||
| 动作 | 负责人建议 | 验收 |
|
||||
|---|---|---|
|
||||
| 暂停 main 发布和公网入口;dev 仅绑定本机/VPN | 运维 | 外部网络无法访问 app/Runner |
|
||||
| 轮换 `.env` 中默认密码及现有 API key;权限改为 600 | 运维/安全 | secret scan 无已知默认值;非属主不可读 |
|
||||
| 生产关闭注册;移除前端快速管理员登录入口和本地认证 fallback | 前端/后端 | 断开后端后登录明确失败,不能进入工作台 |
|
||||
| 临时禁用未鉴权的文档正文、租约、对账、任务取消端点 | 后端 | 匿名请求全部 401;普通用户访问管理端点 403 |
|
||||
| 导出现有 dev 数据库并做可恢复备份 | DBA | 完成一次隔离环境恢复演练 |
|
||||
|
||||
### 阶段 1:身份、授权与输入边界(3–7 天)
|
||||
|
||||
1. 实现全局认证中间件,白名单只保留 health、login、按策略开放的 register 和静态资源。
|
||||
2. 删除所有业务路径中的 `X-User-ID`、请求体 `user_id/user_role/user_name` 信任;内部调用使用不可伪造的 request context principal。
|
||||
3. 新建 `project_members(project_id,user_id,role,status,...)`、会话归属、资产归属和任务归属授权函数。
|
||||
4. 为每个端点定义权限矩阵:资源、动作、允许主体、对象条件、审计级别。
|
||||
5. 路径只接受逻辑 ID,禁止客户端传绝对/相对目录;使用统一 `WorkspaceResolver` 和根目录约束。
|
||||
6. 加入请求大小、上传类型、配额、Agent 并发和登录限速。
|
||||
|
||||
阶段门禁:匿名/跨用户/跨项目/伪角色/路径穿越/超大 body 全套负例测试必须通过。OWASP 建议默认拒绝并在每个请求验证权限;仅依赖客户端提供的对象 ID 不足以保护资源。[^3][^25]
|
||||
|
||||
### 阶段 2:数据库和交付可重复(第 2 周)
|
||||
|
||||
1. 从当前代码反向生成权威 schema 清单,将所有迁移排序并纳入统一工具。
|
||||
2. 为现有 dev 卷补齐缺失表/字段;先备份,再 dry-run,再迁移,再做行数/约束/索引核验。
|
||||
3. 废弃 `system_init.sql` 与 `context_init.sql` 的双轨演进:空库也通过同一迁移链创建。
|
||||
4. 应用启动时校验 schema version;prod 不允许内存 fallback。
|
||||
5. 增加前端 builder 或独立静态站点镜像,做 SBOM、依赖扫描、镜像非 root、只读根文件系统评估。
|
||||
6. 创建 CI:格式化、lint、Go test/race/vet、前端 test/build、迁移测试、容器 smoke、secret scan、依赖扫描。
|
||||
|
||||
阶段门禁:空库部署、从当前 dev schema 升级、回滚演练、首页/静态资源/API/健康检查全部通过;main 与 test schema checksum 一致。
|
||||
|
||||
### 阶段 3:长任务可靠性与一致性(第 3 周)
|
||||
|
||||
1. 将 `task_runs` 和 `task_run_events` 持久化,事件序号使用数据库唯一约束。
|
||||
2. 用 worker lease + heartbeat 识别孤儿任务;进程启动后按策略恢复、重试或标记中断。
|
||||
3. 使用事务 + Outbox:成果、文档版本、workflow run、聊天消息和终态事件要么一致成功,要么可重试。
|
||||
4. 调整事件顺序:`finalize committed` 后才能发布 `done/quality_failed`。
|
||||
5. 取消接口幂等;Runner 取消结果必须回写并可审计。
|
||||
6. 增加多副本和滚动重启测试。
|
||||
|
||||
阶段门禁:执行中重启 app、断开 SSE、重复提交、Finalize 故障、Runner 超时、取消竞态六类故障注入均不会产生假成功或丢任务。
|
||||
|
||||
### 阶段 4:安全渲染、Agent 隔离和数据治理(第 4–5 周)
|
||||
|
||||
1. Mermaid 切换 `strict`/`sandbox`,对 Markdown、SVG、链接、附件预览执行统一内容安全策略。
|
||||
2. Runner 增加服务间认证、每任务沙箱、网络 allowlist、资源配额和出站审计。
|
||||
3. 建立数据分级、保留期、导出审批、加密、删除与备份清除流程。
|
||||
4. 共享 KB 改成不可变索引版本;生产仅绑定已批准版本,dev/test 使用独立别名或命名空间。
|
||||
5. 将所有 ignored DB errors 转为可观测、可重试或明确失败。
|
||||
|
||||
### 阶段 5:功能质量与正式验收(第 6 周)
|
||||
|
||||
1. 完成真实 PI Agent + 模型全链路测试,覆盖材料上传、检索、多人对话、文档编制、审核、批准、导出和重启恢复。
|
||||
2. 完成报价输入校验、语义摘要、小队降级、trace 原子序号等现有 backlog。
|
||||
3. 建立黄金数据集:意图识别、RAG 引用正确性、幻觉率、文档质量、权限负例。
|
||||
4. 定义 SLO:API 可用性、首字节时间、任务成功率、恢复时间、错误预算、检索质量和单位任务成本。
|
||||
5. test 环境连续稳定运行至少一个发布周期,再按分支准入规则进入 main。
|
||||
|
||||
## 建议的数据模型增量
|
||||
|
||||
| 表/对象 | 核心字段 | 用途 |
|
||||
|---|---|---|
|
||||
| `auth_users` 或扩展 `users` | username、password_hash、status、password_changed_at | 持久化认证主体 |
|
||||
| `auth_sessions` | token_hash、user_id、idle_expires_at、absolute_expires_at、revoked_at | 服务端会话治理 |
|
||||
| `project_members` | project_id、user_id、project_role、status、joined_at | 项目关系授权 |
|
||||
| `task_runs` | run_id、owner、project、status、lease、attempt、idempotency_key | durable task SSOT |
|
||||
| `task_run_events` | run_id、seq、type、payload、created_at | SSE 重放与审计 |
|
||||
| `outbox_events` | aggregate、event_type、payload、published_at | 事务后可靠通知 |
|
||||
| `schema_migrations` | version、checksum、applied_at、duration | 数据库版本门禁 |
|
||||
| `security_audit_events` | actor、action、resource、decision、request_id、ip | 授权与安全审计 |
|
||||
|
||||
## 发布验收清单
|
||||
|
||||
### 安全门禁
|
||||
|
||||
- 无 token 的所有业务 API 返回 401;权限不足返回 403,且不泄露对象是否存在。
|
||||
- 修改任意 path/query/body/header 中的用户、项目、会话、文档、run ID 均不能越权。
|
||||
- 禁止 `X-User-ID` 作为公网身份;管理员 token 具备过期、撤销和审计。
|
||||
- `../`、绝对路径、符号链接逃逸、超大 body、伪 MIME、恶意 Mermaid 全部被拒绝。
|
||||
- 前端断网不会创建本地管理员或伪成功状态。
|
||||
|
||||
### 数据与任务门禁
|
||||
|
||||
- 空数据库与旧版数据库均可自动迁移至同一版本,失败时应用不接流量。
|
||||
- app 重启后会话、账号、工作流、自由文档、任务和 SSE 重放仍然有效。
|
||||
- 任务只出现一个终态;`done` 必须意味着文档、消息、workflow run 均已提交。
|
||||
- 数据库断开时 readiness 失败,不得无提示切换内存态。
|
||||
|
||||
### 交付与运维门禁
|
||||
|
||||
- 应用镜像可直接返回 SPA 首页、哈希静态资源和深链接。
|
||||
- main 不包含默认密码;Secret 不进入镜像、日志、前端 bundle 或 Git。
|
||||
- CI 产出测试报告、覆盖率、SBOM、漏洞/secret 扫描和迁移报告。
|
||||
- test/main 采用相同镜像 digest,仅配置和数据不同。
|
||||
- 备份经过实际恢复;明确 RPO/RTO、值班告警和回滚步骤。
|
||||
|
||||
## 建议的首批整改任务拆分
|
||||
|
||||
| Issue | 工作量估计 | 依赖 | 完成定义 |
|
||||
|---|---:|---|---|
|
||||
| SEC-001 统一认证中间件,删除 `X-User-ID` 信任 | 2–3 人日 | 无 | 全路由认证清单 + 401 测试 |
|
||||
| SEC-002 项目/对象授权策略与 `project_members` | 4–6 人日 | SEC-001、DB migration | 跨用户/跨项目矩阵测试全绿 |
|
||||
| SEC-003 路径沙箱与对账接口收口 | 2 人日 | SEC-001 | 任意路径/符号链接测试全绿 |
|
||||
| SEC-004 移除前端本地认证和明文账户 | 1–2 人日 | SEC-001 | 断网 fail closed;bundle 无默认凭据 |
|
||||
| DB-001 统一迁移链和 schema version 门禁 | 4–6 人日 | 备份 | 空库/旧库升级 CI 全绿 |
|
||||
| DEP-001 前端生产镜像与容器 smoke | 2 人日 | 无 | `/`、assets、深链接、API 全绿 |
|
||||
| RUN-001 持久化 task runs/events | 5–8 人日 | DB-001 | 重启后查询/重放/取消有效 |
|
||||
| RUN-002 Finalize/Outbox/终态时序 | 3–5 人日 | RUN-001 | Finalize 故障不再发送 done |
|
||||
| OPS-001 readiness、metrics、alerts、structured audit | 3–5 人日 | DB-001 | 故障注入触发正确健康状态与告警 |
|
||||
| QA-001 CI 与发布安全/故障回归套件 | 5–8 人日 | 上述各项 | main 合并必须经过门禁 |
|
||||
|
||||
以上估算适用于熟悉现有代码的 2–3 人小组,不包含真实模型质量调优时间。建议先完成 SEC-001/003/004、DB-001、DEP-001,再并行推进 SEC-002 与 RUN-001。
|
||||
|
||||
## 结论
|
||||
|
||||
本系统“功能设计”并不贫乏,真正的短板是权威边界和工程闭环。当前已有的智能体、工作流、文档治理和测试资产值得保留,但必须把 Demo 便利性从生产链路剥离,把身份、项目关系、数据库版本、任务终态和工作区路径全部收回服务端控制。
|
||||
|
||||
整改成功的判据不是“页面能操作”或“单测通过”,而是:任意客户端参数都不能改变身份与权限;任意重启都不能丢失权威状态;任意发布都能从已知 schema 可重复升级;任意终态都与数据库和用户界面一致。完成全部 P0 和 P1 后,系统才适合进入真实多人 test 环境长期运行。
|
||||
|
||||
## Sources
|
||||
|
||||
[^1]: 仓库架构设计,《[项目对话与任务协同系统——架构设计文档](./system-design/architecture-design.md)》,§3.1–3.3,访问于 2026-09-11。
|
||||
[^2]: 仓库源码,[`internal/server/auth_handlers.go`](../internal/server/auth_handlers.go#L13-L42);[`internal/server/server.go`](../internal/server/server.go#L91-L188),访问于 2026-09-11。
|
||||
[^3]: OWASP, “[API1:2023 Broken Object Level Authorization](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/),” 2023。
|
||||
[^4]: 仓库部署基线,[`docker-compose.main.yml`](../docker-compose.main.yml#L11-L24);[`deploy/postgres/system_init.sql`](../deploy/postgres/system_init.sql#L1-L72),访问于 2026-09-11。
|
||||
[^5]: Docker Docs, “[PostgreSQL specific guide — Initialization scripts](https://docs.docker.com/guides/postgresql/),” 访问于 2026-09-11。
|
||||
[^6]: 运行态只读检查:`shuimu-context-pg-dev/agent_system_dev`;缺少 `project_workflows`、`workflow_runs`、`workflow_activation_audits`、`document_lineage`、`freeform_documents`、`freeform_document_versions`、`document_access_audit`,且 `chat_messages` 缺 `content_kind`、`export_policy`、`content_revision`、`content_sha256`,检查于 2026-09-11。
|
||||
[^7]: 仓库镜像定义,[`deploy/app/Dockerfile`](../deploy/app/Dockerfile#L1-L34),访问于 2026-09-11。
|
||||
[^8]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go#L192-L244) 的 SPA 文件查找逻辑,访问于 2026-09-11。
|
||||
[^9]: 仓库源码,[`internal/taskrun/manager.go`](../internal/taskrun/manager.go#L28-L73)(内存与保留期);同文件 [L200-L220](../internal/taskrun/manager.go#L200-L220)(done 先于 finalize),访问于 2026-09-11。
|
||||
[^10]: 仓库测试报告,《[Chat Agent 全链路修复整改测试报告](./test-reports/2026-09-11-chat-agent-remediation-test-report.md)》§6–7;《[聊天回合幂等与项目切换隔离测试报告](./test-reports/2026-09-11-chat-turn-idempotency-test-report.md)》§5.3,访问于 2026-09-11。
|
||||
[^11]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L101-L268)、[L325-L439](../internal/server/handlers.go#L325-L439)、[L648-L838](../internal/server/handlers.go#L648-L838)、[L886-L994](../internal/server/handlers.go#L886-L994),访问于 2026-09-11。
|
||||
[^12]: 仓库前端源码,[`web/src/api/auth.ts`](../web/src/api/auth.ts#L25-L185)、[L187-L540](../web/src/api/auth.ts#L187-L540),访问于 2026-09-11。
|
||||
[^13]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L886-L923);[`internal/docgov/lease.go`](../internal/docgov/lease.go#L285-L338),访问于 2026-09-11。
|
||||
[^14]: 仓库源码,[`internal/server/reconcile_handlers.go`](../internal/server/reconcile_handlers.go#L10-L24);[`internal/squad/reconcile.go`](../internal/squad/reconcile.go#L25-L64),访问于 2026-09-11。
|
||||
[^15]: 仓库当前开发基线,[`deploy/postgres/context_init.sql`](../deploy/postgres/context_init.sql#L1-L360) 及 [`deploy/postgres/migrations/`](../deploy/postgres/migrations/),访问于 2026-09-11。
|
||||
[^16]: 仓库源码,[`internal/bizdev/service.go`](../internal/bizdev/service.go#L40-L76),访问于 2026-09-11。
|
||||
[^17]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L74-L83),访问于 2026-09-11。
|
||||
[^18]: 仓库源码,[`internal/projectworkflow/service.go`](../internal/projectworkflow/service.go#L69-L106);[`internal/projectworkflow/store.go`](../internal/projectworkflow/store.go#L145-L177);前端 [`web/src/engine/rbac.ts`](../web/src/engine/rbac.ts),访问于 2026-09-11。
|
||||
[^19]: 仓库源码,[`internal/auth/store.go`](../internal/auth/store.go#L20-L101);[`internal/auth/service.go`](../internal/auth/service.go#L43-L113)、[L192-L226](../internal/auth/service.go#L192-L226),访问于 2026-09-11。
|
||||
[^20]: 仓库源码,[`internal/server/asset_handlers.go`](../internal/server/asset_handlers.go#L20-L79);Go 官方文档,[`net/http.MaxBytesReader`](https://pkg.go.dev/net/http#MaxBytesReader),访问于 2026-09-11。
|
||||
[^21]: 仓库前端源码,[`web/src/components/doc/blocks/MermaidBlockView.tsx`](../web/src/components/doc/blocks/MermaidBlockView.tsx#L12-L20)、[L64-L77](../web/src/components/doc/blocks/MermaidBlockView.tsx#L64-L77)、[L199-L208](../web/src/components/doc/blocks/MermaidBlockView.tsx#L199-L208),访问于 2026-09-11。
|
||||
[^22]: Mermaid 官方文档,“[securityLevel](https://mermaid.js.org/config/schema-docs/config-properties-securitylevel.html),”访问于 2026-09-11。
|
||||
[^23]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go#L433-L443);[`docker-compose.main.yml`](../docker-compose.main.yml#L80-L118),访问于 2026-09-11。
|
||||
[^24]: 仓库待办,《[Chat Agent P6 Backlog Issues](./backlog/chat-agent-p6-backlog.md)》,访问于 2026-09-11。
|
||||
[^25]: OWASP Cheat Sheet Series, “[Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
[^26]: OWASP Cheat Sheet Series, “[Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
[^27]: OWASP Cheat Sheet Series, “[File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
本文档已迁至 [audit/2026-09-11-system-functional-gap-audit-and-remediation.md](audit/2026-09-11-system-functional-gap-audit-and-remediation.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,312 +1,3 @@
|
||||
# 项目全面审计 - 文档索引
|
||||
# 已迁移
|
||||
|
||||
> **HISTORICAL(2026-09-12 初审快照)**
|
||||
> **当前发布/缺口 SSOT** → [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md)
|
||||
> **协作焦点** → [.doc/ops/CURRENT.md](./ops/CURRENT.md)
|
||||
> **Agent 工作方式** → [AGENTS.md](../AGENTS.md) · [PROJECT.md](../PROJECT.md)
|
||||
|
||||
**审计日期**: 2026-09-12
|
||||
**项目**: Chat-Agent-System
|
||||
**审计状态**: 历史索引(下方 5.7/10 为初审结论,勿作 live status)
|
||||
|
||||
---
|
||||
|
||||
## 核心文档(按阅读顺序推荐)
|
||||
|
||||
### 0️⃣ 当前状态(Live SSOT)
|
||||
|
||||
**文件**: `2026-09-12-remediation-gap-matrix.md`
|
||||
**协作**: `.doc/ops/CURRENT.md` · `AGENTS.md` · `PROJECT.md`
|
||||
**用途**: 发布缺口、Codex 再审计闭环证据、发布门禁勾选
|
||||
|
||||
---
|
||||
|
||||
### 1️⃣ 从这里开始:审计总结报告(历史)
|
||||
**文件**: `2026-09-12-audit-summary-report.md`
|
||||
**用途**: 项目整体现状、关键数字、风险评估
|
||||
**适合**: 项目经理、技术负责人、快速概览
|
||||
**阅读时间**: 15-20 分钟
|
||||
|
||||
**关键内容**:
|
||||
- 项目评分及各维度打分
|
||||
- 12 个已确认缺陷分布(critical/high/medium)
|
||||
- 未完成功能清单
|
||||
- 开发库数据污染现状(88 个测试定义)
|
||||
- 整改时间与资源规划
|
||||
- 立即行动建议
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ 详细缺陷与整改:综合整改方案
|
||||
**文件**: `2026-09-12-comprehensive-audit-and-remediation-plan.md`
|
||||
**用途**: 12 个缺陷的详细分析 + 3 个新功能的整改方案
|
||||
**适合**: 架构师、资深开发工程师
|
||||
**阅读时间**: 45-60 分钟
|
||||
|
||||
**关键内容**:
|
||||
- BUG-01 到 BUG-12 的代码现场与后果分析
|
||||
- 5 个 high 缺陷的深层原因
|
||||
- 3 个 MISSING 新功能的实现设计
|
||||
- 3 个 Phase (A/B/C) 的整改计划
|
||||
- 风险预案与建议
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ 可执行的任务拆分:任务清单与验收
|
||||
**文件**: `2026-09-12-remediation-tasks-and-acceptance-checklist.md`
|
||||
**用途**: 具体的代码修改指引、单元测试框架、验收标准
|
||||
**适合**: 开发工程师、QA、代码审查人
|
||||
**阅读时间**: 60-90 分钟
|
||||
|
||||
**关键内容**:
|
||||
- Task A1-A6:关键缺陷修复(15h)
|
||||
- 每个 Task 的修改文件、代码片段、测试用例
|
||||
- 验收标准与预计工作量
|
||||
- Task B1-B3:高优先级新功能(26h)
|
||||
- 受控终止 API 的完整实现
|
||||
- E2E 测试框架与运行命令
|
||||
- 项目上下文快照的数据模型与集成点
|
||||
- Task C1-C7:完善与发布(20h)
|
||||
- 全套验收检查表
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ 快速参考与速查:快速指南
|
||||
**文件**: `2026-09-12-quick-reference-guide.md`
|
||||
**用途**: 问题症状→原因→解决方案的快速诊断
|
||||
**适合**: 所有开发人员、值班人员
|
||||
**阅读时间**: 5-10 分钟(按需查阅)
|
||||
|
||||
**关键内容**:
|
||||
- 10 个常见症状的诊断矩阵
|
||||
- 代码热点地图(哪个文件有哪个 bug)
|
||||
- 整改优先级排序
|
||||
- 代码修改检查清单
|
||||
- 数据库迁移清单
|
||||
- 测试命令参考
|
||||
- API 变动汇总
|
||||
- 常见问题 Q&A
|
||||
|
||||
---
|
||||
|
||||
## 配套参考文档
|
||||
|
||||
### 业务需求原文
|
||||
**文件**: `2026-09-12-three-workflows-strict-governance-remediation.md`
|
||||
**用途**: 业务决策、验收标准的原始出处
|
||||
**适合**: 产品、架构、QA(需要理解业务背景)
|
||||
|
||||
**关键章节**:
|
||||
- 第 3 章:不可违反的业务规则
|
||||
- 第 7 章:验收标准(7.1-7.5)
|
||||
- 第 8-9 章:已确认决策与实施解释
|
||||
|
||||
---
|
||||
|
||||
## 快速导航
|
||||
|
||||
### 我是 PM/项目经理
|
||||
```
|
||||
1. 读 audit-summary-report.md 第一部分(总体评估)
|
||||
2. 重点关注第九章(建议行动计划)
|
||||
3. 查阅 quick-reference-guide.md 第三部分(优先级排序)
|
||||
4. 预估资源与时间
|
||||
```
|
||||
|
||||
### 我是后端开发
|
||||
```
|
||||
1. 读 quick-reference-guide.md(快速了解要改什么)
|
||||
2. 针对每个 task 查阅 remediation-tasks-and-acceptance-checklist.md
|
||||
3. 参考 comprehensive-audit-and-remediation-plan.md 理解原因
|
||||
4. 按照 task 中的"修改文件"和"代码片段"进行开发
|
||||
5. 执行"测试用例"部分验证修改
|
||||
```
|
||||
|
||||
### 我是 QA/测试工程师
|
||||
```
|
||||
1. 读 audit-summary-report.md 第十一章(验收标准清单)
|
||||
2. 查阅 quick-reference-guide.md 第五部分(检查清单)
|
||||
3. 针对每个 task 制定测试计划
|
||||
4. 执行 comprehensive-audit-and-remediation-plan.md 中的验收标准
|
||||
5. 特别关注 remediation-tasks 的 E2E 部分
|
||||
```
|
||||
|
||||
### 我是前端工程师
|
||||
```
|
||||
1. 读 quick-reference-guide.md 第三部分(了解哪些前端需改)
|
||||
2. 查看 BUG-09、BUG-10、BUG-12 的具体改动
|
||||
3. 关注 comprehensive-audit 中的前端相关缺陷
|
||||
4. 参考 remediation-tasks 的 API 变动部分
|
||||
```
|
||||
|
||||
### 我是架构师/技术负责人
|
||||
```
|
||||
1. 读 audit-summary-report.md(整体判定)
|
||||
2. 深入 comprehensive-audit-and-remediation-plan.md(详细分析)
|
||||
3. 关注第八章(架构建议)和第十二章(结语)
|
||||
4. 制定整改计划和资源分配
|
||||
```
|
||||
|
||||
### 我要处理现场问题
|
||||
```
|
||||
1. 查询 quick-reference-guide.md 第五部分(症状→原因→解决)
|
||||
2. 找到对应的 bug 号
|
||||
3. 查阅 comprehensive-audit 的完整分析
|
||||
4. 按照 remediation-tasks 中的修复步骤操作
|
||||
5. 若需临时绕过,参考 quick-reference-guide 的建议
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文档关系图
|
||||
|
||||
```
|
||||
入口文档
|
||||
↓
|
||||
audit-summary-report.md ← 总体评估与建议
|
||||
↓
|
||||
├→ comprehensive-audit-and-remediation-plan.md ← 详细缺陷分析
|
||||
│ ├─ BUG-01 到 BUG-12 详解
|
||||
│ ├─ MISSING-01 到 MISSING-04 详解
|
||||
│ └─ Phase A/B/C 整改计划
|
||||
│
|
||||
├→ remediation-tasks-and-acceptance-checklist.md ← 可执行任务
|
||||
│ ├─ Task A1-A6(关键缺陷)
|
||||
│ ├─ Task B1-B3(新功能)
|
||||
│ └─ 验收检查表
|
||||
│
|
||||
├→ quick-reference-guide.md ← 快速查询
|
||||
│ ├─ 症状诊断矩阵
|
||||
│ ├─ 代码热点地图
|
||||
│ ├─ 优先级排序
|
||||
│ └─ 常见问题 Q&A
|
||||
│
|
||||
└→ three-workflows-strict-governance-remediation.md ← 业务背景
|
||||
├─ 业务需求与决策
|
||||
├─ 验收标准
|
||||
└─ 来源证据
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 关键指标速查
|
||||
|
||||
| 指标 | 数值 | 位置 |
|
||||
|---|---|---|
|
||||
| 项目完成度 | 70% | audit-summary-report.md:1.2 |
|
||||
| 总体评分 | 5.7/10 | audit-summary-report.md:1.1 |
|
||||
| 缺陷总数 | 12 个 | audit-summary-report.md:2.1 |
|
||||
| Critical 缺陷 | 3 个 | audit-summary-report.md:2.1 |
|
||||
| 整改工作量 | 61h | audit-summary-report.md:9.1 |
|
||||
| 单元测试覆盖率 | 85% | audit-summary-report.md:1.2 |
|
||||
| E2E 覆盖率 | 0% | audit-summary-report.md:1.2 |
|
||||
| 开发库污染定义 | 88 个 | audit-summary-report.md:4.1 |
|
||||
|
||||
---
|
||||
|
||||
## 立即行动清单
|
||||
|
||||
**今天需要做的事**(第一天):
|
||||
|
||||
```
|
||||
[ ] 技术负责人读 audit-summary-report.md(20 分钟)
|
||||
[ ] 架构师读 comprehensive-audit-and-remediation-plan.md(60 分钟)
|
||||
[ ] 后端 A 开发师启动 Task A1(2h)- 项目生命周期修复
|
||||
[ ] 后端 A 开发师启动 Task A4(2h)- 对话推进新服务
|
||||
[ ] QA 准备 E2E 测试框架(同步进行)
|
||||
[ ] 全队讨论确认整改计划(30 分钟)
|
||||
```
|
||||
|
||||
**本周目标**(5 天):
|
||||
|
||||
```
|
||||
Day 1: 完成 Phase A 关键缺陷修复(15h)
|
||||
Day 2-3: 启动 Phase B 新功能开发并行(26h)
|
||||
Day 4-5: Phase C 完善与发布准备(20h)
|
||||
+ 每晚运行完整测试套件验证
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见路径快查
|
||||
|
||||
**"完成工作流后项目仍然是 active"**
|
||||
→ quick-reference-guide.md 第二部分 症状 1
|
||||
→ comprehensive-audit 第二部分 BUG-01
|
||||
→ remediation-tasks 的 Task A1
|
||||
|
||||
**"对话推进不起作用"**
|
||||
→ quick-reference-guide.md 第二部分 症状 3
|
||||
→ comprehensive-audit 第二部分 BUG-04
|
||||
→ remediation-tasks 的 Task A4
|
||||
|
||||
**"禁用文档仍能被打开"**
|
||||
→ quick-reference-guide.md 第二部分 症状 2
|
||||
→ comprehensive-audit 第二部分 BUG-05
|
||||
→ remediation-tasks 的 Task A5
|
||||
|
||||
**"激活 token 可能被重复使用"**
|
||||
→ quick-reference-guide.md 第二部分 症状 6
|
||||
→ comprehensive-audit 第二部分 BUG-06
|
||||
→ remediation-tasks 的 Task A6
|
||||
|
||||
**"无法运行测试流程"**
|
||||
→ quick-reference-guide.md 第二部分 症状 7
|
||||
→ comprehensive-audit 第三部分 MISSING-06
|
||||
→ remediation-tasks 的 Phase B 开始
|
||||
|
||||
**"需要完整 E2E 验证"**
|
||||
→ comprehensive-audit 第三部分 MISSING-04
|
||||
→ remediation-tasks 的 Task B2
|
||||
|
||||
---
|
||||
|
||||
## 发布检查清单
|
||||
|
||||
**上线前必须确认**:
|
||||
|
||||
```
|
||||
整改完成度:
|
||||
□ Phase A 全部 PASS
|
||||
□ Phase B 全部 PASS
|
||||
□ Phase C 全部 PASS
|
||||
|
||||
测试覆盖:
|
||||
□ 单元测试覆盖率 ≥ 85%
|
||||
□ E2E 测试三工作流完整链路
|
||||
□ 并发测试通过
|
||||
□ 数据库迁移兼容性验证
|
||||
|
||||
业务验收:
|
||||
□ 验收标准 7.1-7.5 全部满足
|
||||
□ 不存在 critical 缺陷
|
||||
□ 安全性审计通过
|
||||
|
||||
运维就绪:
|
||||
□ 数据库备份与恢复方案
|
||||
□ 审计日志完整
|
||||
□ 监控告警配置
|
||||
□ 性能基准测试
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文档维护
|
||||
|
||||
这套审计文档为 v1.0,应定期更新:
|
||||
|
||||
- **每完成一个 task**: 更新对应 task 的状态
|
||||
- **每发现新缺陷**: 补充到 comprehensive-audit-and-remediation-plan.md
|
||||
- **每月**: 做一次整体进度评估和文档更新
|
||||
|
||||
---
|
||||
|
||||
**审计完毕**
|
||||
|
||||
**下一步**: 确认整改计划,进入实施阶段
|
||||
|
||||
**总体建议**: 立即启动 Phase A(关键缺陷),并行启动 E2E 测试框架,一周内完成所有整改。
|
||||
|
||||
---
|
||||
|
||||
*本索引最后更新于 2026-09-12 15:05 UTC*
|
||||
本文档已迁至 [audit/INDEX.md](audit/INDEX.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,440 +1,3 @@
|
||||
# 项目全面审计总结报告
|
||||
# 已迁移
|
||||
|
||||
> **SUPERSEDED** — 历史初审快照。Live 状态见 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 与 [.doc/ops/CURRENT.md](./ops/CURRENT.md)。
|
||||
|
||||
**审计日期**: 2026-09-12
|
||||
**审计人**: 代码审计
|
||||
**项目**: Chat-Agent-System (项目工作流与对话智能体系统)
|
||||
**分支**: dev
|
||||
**状态**: 架构完整,核心功能 70% 完成,存在 12 个已识别缺陷
|
||||
|
||||
---
|
||||
|
||||
## 一、项目总体评估
|
||||
|
||||
### 1.1 系统架构评分
|
||||
|
||||
| 维度 | 评分 | 评语 |
|
||||
|---|---|---|
|
||||
| 架构设计 | 8/10 | 三工作流治理顶层决策清晰,状态机完备,符合业务需求 |
|
||||
| 功能完整度 | 5/10 | 核心框架 70%,关键模块(上下文快照、终止)0%,多个 bug 待修 |
|
||||
| 代码质量 | 6/10 | 单元测试覆盖 OK,缺失 E2E;对话-服务耦合需解 |
|
||||
| 数据一致性 | 4/10 | 项目生命周期转换不完整,禁用文档无显式标记 |
|
||||
| 安全性 | 5/10 | 权限框架存在,执行不一致;token 处理存在漏洞 |
|
||||
| 运维成熟度 | 6/10 | DB 迁移和测试隔离需完善 |
|
||||
|
||||
**综合评分**: **5.7/10** → **需立即整改**
|
||||
|
||||
---
|
||||
|
||||
### 1.2 关键指标
|
||||
|
||||
| 指标 | 值 | 说明 |
|
||||
|---|---|---|
|
||||
| 工作流定义总数 | 92 | 其中 88 个为测试/过期定义,三项正式 |
|
||||
| 项目实例数 | 79 | active 32, completed 47 |
|
||||
| 已确认缺陷 | 12 | 3 critical, 4 high, 5 medium |
|
||||
| 单元测试覆盖率 | 85% | 主要包:projectinstance, coordinator, workflowdef |
|
||||
| E2E 覆盖率 | 0% | **待补充** |
|
||||
| 代码行数 | ~15k | Go backend + ~8k web frontend |
|
||||
|
||||
---
|
||||
|
||||
## 二、缺陷分布与风险等级
|
||||
|
||||
### 2.1 严重缺陷(Critical)- 立即修复
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ BUG-01: 完成后项目生命周期未更新 [CRITICAL] │
|
||||
│ 风险: 项目永久锁死,用户无法配置下一流程 │
|
||||
│ 优先级: 🔴 P0 (2h) │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ BUG-02: 推进强制批准文档 [CRITICAL] │
|
||||
│ 风险: 违反业务规则,数据不一致 │
|
||||
│ 优先级: 🔴 P0 (1h) │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ BUG-04: 对话推进调用旧服务 [CRITICAL] │
|
||||
│ 风险: 绕过新权限检查,双轨运行 │
|
||||
│ 优先级: 🔴 P0 (2h) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 高优先级缺陷(High)- 本周修复
|
||||
|
||||
```
|
||||
BUG-03: 禁用文档无显式 skipped_disabled 标记
|
||||
BUG-05: 禁用文档拒绝逻辑不一致
|
||||
BUG-06: 激活 token 安全问题
|
||||
BUG-07: 项目完成后下一流程配置缺失
|
||||
```
|
||||
|
||||
### 2.3 中低优先级缺陷(Medium/Low)- 下周处理
|
||||
|
||||
```
|
||||
BUG-08: 测试数据库隔离不完全
|
||||
BUG-09: 版本冲突时前端自动重试
|
||||
BUG-10: 项目设置无审计视图
|
||||
BUG-11: 旧 API 未正式下线
|
||||
BUG-12: 前端名称不一致
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、未完成功能模块
|
||||
|
||||
### 3.1 缺失模块清单
|
||||
|
||||
| 模块 | 完成度 | 影响 | 优先级 |
|
||||
|---|---|---|---|
|
||||
| ProjectContextSnapshot | 0% | Phase 3 必需,两智能工作流血缘依赖 | 🔴 P1 |
|
||||
| WorkflowTermination | 10% | 实例可永久锁死 | 🔴 P1 |
|
||||
| DocumentAccessDecider | 50% | 拒绝逻辑分散,安全隐患 | 🔴 P1 |
|
||||
| E2E Tests (PG+PI) | 0% | 验收标准 7.5 要求 | 🔴 P1 |
|
||||
| 项目生命周期完整转换 | 40% | 完成后无法切换 | 🔴 P1 |
|
||||
|
||||
### 3.2 代码现状与缺陷位置
|
||||
|
||||
**问题集中地**:
|
||||
- `internal/projectinstance/stage_store.go:71-158` - 推进事务问题
|
||||
- `internal/coordinator/engine.go:672-811` - 对话推进耦合
|
||||
- `internal/projectinstance/service.go:119-135` - 生命周期不完整
|
||||
- `internal/projectinstance/stage_access.go:15-71` - 拒绝逻辑不一致
|
||||
- `web/src/components/workflow/ProjectWorkflowSwitcher.tsx` - 前端名称&自动重试
|
||||
|
||||
---
|
||||
|
||||
## 四、数据一致性风险分析
|
||||
|
||||
### 4.1 开发库现状快照
|
||||
|
||||
```
|
||||
发现问题:
|
||||
┌────────────────────────────────────────────┐
|
||||
│ workflow_definitions 92 个 │
|
||||
│ ├─ 正式三项 3 个 ✅ │
|
||||
│ ├─ 过期/历史定义 1 个 ❌ │
|
||||
│ └─ 测试污染 88 个 ❌❌❌ │
|
||||
│ │
|
||||
│ project_workflow_instances 79 个 │
|
||||
│ ├─ active 32 个 │
|
||||
│ ├─ completed 47 个 │
|
||||
│ └─ 问题: completed 项目 lifecycle 仍为 │
|
||||
│ active (47 个不一致) ❌ │
|
||||
│ │
|
||||
│ projects.lifecycle_status 分布 │
|
||||
│ ├─ active 97 个 │
|
||||
│ ├─ planning 51 个 │
|
||||
│ └─ completed 0 个 (不支持) │
|
||||
│ │
|
||||
│ 隔离问题: │
|
||||
│ 集成测试未设置 TEST_DATABASE_URL │
|
||||
│ → 默认连接本地 agent_system_dev │
|
||||
│ → 88 个定义污染 ❌❌ │
|
||||
└────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**风险评估**:
|
||||
- **数据污染**: 🔴 严重 - 无法清洁复现
|
||||
- **生命周期不一致**: 🔴 严重 - 47 个实例数据已破损
|
||||
- **隔离缺失**: 🟠 高 - CI/CD 不可信
|
||||
|
||||
---
|
||||
|
||||
## 五、安全性审计结论
|
||||
|
||||
### 5.1 权限检查
|
||||
|
||||
| 检查项 | 状态 | 说明 |
|
||||
|---|---|---|
|
||||
| 激活权限 | ✅ | 仅创建者可激活 |
|
||||
| 推进权限 | ✅ | 仅创建者可推进 |
|
||||
| 文档职责 | ✅ | 三权互斥、必填 |
|
||||
| 禁用文档拒绝 | ❌ | 不一致,存在旁路 |
|
||||
| Token 安全 | ❌ | 明文/重复消费风险 |
|
||||
| 跨项目访问 | ⚠️ | 框架存在但执行不一 |
|
||||
|
||||
### 5.2 威胁模型
|
||||
|
||||
**高风险场景**:
|
||||
|
||||
1. **禁用文档旁路**(CVSS 6.5)
|
||||
- 通过 SSE 或 Agent tool 绕过禁用检查
|
||||
- 修改方案: Task A5 `DocumentAccessDecider`
|
||||
|
||||
2. **Token 重放**(CVSS 7.2)
|
||||
- 激活 token 明文保存,可多次使用
|
||||
- 修改方案: Task A6 token hash + one-time
|
||||
|
||||
3. **对话权限绕过**(CVSS 7.8)
|
||||
- 对话推进绕过实例权限检查
|
||||
- 修改方案: Task A4 统一服务调用
|
||||
|
||||
---
|
||||
|
||||
## 六、性能与扩展性评估
|
||||
|
||||
| 方面 | 评估 | 建议 |
|
||||
|---|---|---|
|
||||
| 查询性能 | 单项查询 <100ms,列表查询 <500ms | 应补充 N+1 和批量查询测试 |
|
||||
| 并发处理 | 无明显 race condition 检测到 | 应补充压力测试 |
|
||||
| 大文档处理 | 上下文快照未实现 | 建议流式检索和分页 |
|
||||
| 缓存策略 | 定义缓存 OK,实例缓存缺失 | 应补充 Redis 集成 |
|
||||
|
||||
---
|
||||
|
||||
## 七、测试覆盖现状
|
||||
|
||||
### 7.1 单元测试
|
||||
|
||||
```
|
||||
✅ PASS 套件:
|
||||
- projectinstance: 45 tests, avg 0.1s/test
|
||||
- coordinator: 32 tests, avg 0.01s/test
|
||||
- workflowdef: 28 tests, avg 0.05s/test
|
||||
- server: 15 tests, avg 0.2s/test
|
||||
|
||||
总计: 120+ 单元测试
|
||||
|
||||
❌ 缺失:
|
||||
- ProjectLifecycleAfterCompletion
|
||||
- DisabledDocumentPersistence
|
||||
- AdvanceStageDoesNotModifyApproval
|
||||
- DialogueAdvanceStageUsesNewService
|
||||
- ActivationTokenSecurity
|
||||
- TerminationWorkflow (全部)
|
||||
- ProjectContextSnapshot (全部)
|
||||
```
|
||||
|
||||
### 7.2 集成测试
|
||||
|
||||
```
|
||||
✅ 可运行:
|
||||
- workflow_governance_pg_test.go
|
||||
- phase5_fault_injection_pg_test.go
|
||||
|
||||
❌ 问题:
|
||||
- 未设置 TEST_DATABASE_URL 时连接开发库
|
||||
- 测试定义发布后无清理
|
||||
- 并发测试不完整
|
||||
```
|
||||
|
||||
### 7.3 E2E 测试
|
||||
|
||||
```
|
||||
❌ 完全缺失:
|
||||
- 真实 PostgreSQL 端到端验证
|
||||
- PI Agent 集成测试
|
||||
- 三工作流完整链路
|
||||
- 项目生命周期转换
|
||||
|
||||
需补充:
|
||||
- setupE2ETestDB()
|
||||
- TestE2E_BizdevWorkflow_Complete
|
||||
- TestE2E_ProductManagerWorkflow_Standalone
|
||||
- TestE2E_TestEngineerWorkflow_WithoutSRS
|
||||
- TestE2E_ProjectTransitionToNextWorkflow
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、架构建议
|
||||
|
||||
### 8.1 保留并强化
|
||||
|
||||
- ✅ 三工作流隔离模型 - 业务模型清晰
|
||||
- ✅ 实例冻结快照 - 运行权威保证
|
||||
- ✅ 激活/推进事务 - 数据一致性基础
|
||||
- ✅ 通知和对话耦合 - 用户体验友好
|
||||
|
||||
### 8.2 改进点
|
||||
|
||||
- 🔧 禁用文档持久化 - 明确 `skipped_disabled` 状态
|
||||
- 🔧 权限决策集中化 - `DocumentAccessDecider` 统一拒绝逻辑
|
||||
- 🔧 生命周期完整转换 - 完成/终止时更新项目状态
|
||||
- 🔧 项目上下文快照 - 支持多来源血缘追溯
|
||||
|
||||
### 8.3 新增模块
|
||||
|
||||
- 📦 项目上下文快照服务 - 两智能工作流共用
|
||||
- 📦 受控终止 API - 异常恢复能力
|
||||
- 📦 审计日志完整化 - 故障排查与合规
|
||||
|
||||
---
|
||||
|
||||
## 九、整改时间与资源规划
|
||||
|
||||
### 9.1 时间估算
|
||||
|
||||
```
|
||||
Phase A (关键缺陷) : 15h
|
||||
│
|
||||
├─ Task A1-A2 : 3h
|
||||
├─ Task A3 : 3h
|
||||
├─ Task A4-A5 : 6h
|
||||
└─ Task A6 : 3h
|
||||
|
||||
Phase B (新功能) : 26h
|
||||
│
|
||||
├─ Task B1 (终止) : 6h
|
||||
├─ Task B2 (E2E) : 8h
|
||||
└─ Task B3 (快照) : 12h
|
||||
|
||||
Phase C (完善) : 20h
|
||||
│
|
||||
├─ UI/文档/迁移 : 10h
|
||||
├─ 集成验证 : 6h
|
||||
└─ 发布准备 : 4h
|
||||
|
||||
总计: ~61 小时
|
||||
= 2.5 天(单人全职)
|
||||
= 5 天(双人并行)
|
||||
```
|
||||
|
||||
### 9.2 资源配置建议
|
||||
|
||||
```
|
||||
推荐配置: 2 人团队
|
||||
├─ 开发 A (后端):
|
||||
│ └─ Phase A (15h) + Phase B 部分 (8h)
|
||||
│
|
||||
├─ 开发 B (全栈):
|
||||
│ └─ Phase B 部分 (18h) + Phase C (20h)
|
||||
│
|
||||
└─ QA (并行):
|
||||
└─ E2E 测试框架、验收检查
|
||||
|
||||
里程碑:
|
||||
Day 1 (8h): Phase A 完成,单测 PASS
|
||||
Day 2 (8h): Phase B 进行中,E2E 框架启动
|
||||
Day 3 (8h): Phase B 完成,真实链路验证
|
||||
Day 4 (8h): Phase C 完善,发布准备
|
||||
Day 5 (5h): 最终验收,合并主分支
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、验收标准清单
|
||||
|
||||
### 10.1 功能验收(来自 `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:417-459`)
|
||||
|
||||
**7.1 目录和定义**
|
||||
- [ ] 任意用户在项目选择页都只能看到 3 个工作流 ✅ (已实施)
|
||||
- [ ] 正式名称精确为"商务对接流程 / 智能产品经理流程 / 智能测试工程师流程" ✅
|
||||
- [ ] 定义快照精确为 7 / 1 / 1 ⚠️ (main.v2.json 缺 2 个)
|
||||
- [ ] 三个正式定义均没有流程级上游依赖 ✅
|
||||
|
||||
**7.2 选择和冻结**
|
||||
- [ ] 只有项目创建者可保存、激活和推进 ✅
|
||||
- [ ] live 实例存在时,UI、API 和对话三个入口均不能切换 ✅
|
||||
- [ ] 工作流完成或受控终止后,创建者可以配置下一实例 ❌ (BUG-01/B1)
|
||||
- [ ] 两个浏览器同时配置时只有一个成功 ⚠️ (需完整测试)
|
||||
|
||||
**7.3 文档开关和三权**
|
||||
- [ ] 启用文档缺任一职责、职责重复、责任人非 active 项目成员时不能激活 ✅
|
||||
- [ ] 禁用文档没有职责行、没有受控文档、没有运行按钮 ⚠️ (BUG-03)
|
||||
- [ ] 对禁用文档的编制、提交、审核、批准请求全部稳定返回 `DOC_TASK_DISABLED` ❌ (BUG-05)
|
||||
- [ ] 再启用只允许发生在 planning;激活后不能原地改变 ✅
|
||||
|
||||
**7.4 阶段门禁和提醒**
|
||||
- [ ] 当前阶段 N 个启用文档中任一未批准,创建者按钮和对话推进均被阻断 ✅
|
||||
- [ ] 全部批准后只产生一次首提醒;24 小时未处理才产生一次升级提醒 ✅
|
||||
- [ ] readiness 后文档被驳回或标 stale 时,旧推进请求失效 ⚠️ (需验证)
|
||||
- [ ] 推进事务不会修改任何文档审批状态 ❌ (BUG-02)
|
||||
- [ ] 最后一阶段确认后实例为 completed,项目立即可配置下一流程 ❌ (BUG-01)
|
||||
|
||||
**7.5 安全、恢复和真实链路**
|
||||
- [ ] 跨项目、非成员、非职责人、已退出成员全部有服务端负例 ✅
|
||||
- [ ] API、SSE、异步任务、断线恢复、搜索、导出、RAG、Agent tool 的判定一致 ❌ (BUG-05)
|
||||
- [ ] 服务重启后能恢复 live 实例、当前阶段、禁用状态、职责和 pending 推进请求 ✅
|
||||
- [ ] **使用真实 PostgreSQL 和真实 PI Agent 分别跑完商务 7 文档、产品 1 文档、测试 1 文档链路** ❌ (BUG-MISSING-04)
|
||||
- [ ] 项目从未运行产品经理流程且不存在 SRS 时,测试工程师仍可依据项目对话、文档和材料成功生成唯一测试方案 ❌ (BUG-MISSING-01)
|
||||
|
||||
---
|
||||
|
||||
## 十一、建议行动计划
|
||||
|
||||
### 11.1 立即行动(今天)
|
||||
|
||||
```
|
||||
1. 确认 BUG-02 现状 (grep "UPDATE.*approved")
|
||||
2. 启动 Task A1 修复(项目完成后生命周期)
|
||||
3. 启动 Task A4 修复(对话推进新服务)
|
||||
4. 启动数据库 00025 迁移设计(禁用文档标记)
|
||||
```
|
||||
|
||||
### 11.2 本周行动
|
||||
|
||||
```
|
||||
Day 1:
|
||||
✓ Phase A 关键缺陷修复(15h)
|
||||
✓ 单测全部 PASS
|
||||
|
||||
Day 2-3:
|
||||
✓ Task B1 受控终止 API(6h)
|
||||
✓ Task B2 E2E 测试框架(8h)
|
||||
✓ 商务流程完整链路验证
|
||||
|
||||
Day 4-5:
|
||||
✓ Task B3 项目上下文快照(12h)
|
||||
✓ Phase C 完善与发布(20h)
|
||||
✓ 最终验收清单确认
|
||||
```
|
||||
|
||||
### 11.3 后续维护
|
||||
|
||||
```
|
||||
生产上线前:
|
||||
□ 性能基准测试
|
||||
□ 压力测试
|
||||
□ 灾难恢复演练
|
||||
|
||||
生产上线后:
|
||||
□ 审计日志监控
|
||||
□ 每周数据一致性检查
|
||||
□ 用户反馈收集与迭代
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十二、结语
|
||||
|
||||
### 12.1 总体判定
|
||||
|
||||
**项目状态**: 🟠 **中等风险** → 需立即整改
|
||||
|
||||
**原因**:
|
||||
1. 架构设计合理,业务需求清晰
|
||||
2. 核心框架 70% 已实现,技术选型无问题
|
||||
3. **关键性缺陷 3 个**(项目生命周期、推进状态、对话服务)必须本周修复
|
||||
4. **新功能 3 个**(快照、终止、E2E)需并行开发
|
||||
5. **数据污染**(88 个测试定义)影响可信度
|
||||
|
||||
### 12.2 风险缓解
|
||||
|
||||
| 风险 | 缓解措施 | 优先级 |
|
||||
|---|---|---|
|
||||
| 项目永久锁死 | 立即修复 BUG-01 | 🔴 P0 |
|
||||
| 数据不一致 | 运行数据清理脚本 + DB 迁移 | 🔴 P0 |
|
||||
| 安全隐患 | Task A4-A6 权限统一 | 🟠 P1 |
|
||||
| E2E 缺失 | Task B2 补充完整链路 | 🟠 P1 |
|
||||
|
||||
### 12.3 建议
|
||||
|
||||
1. **立即启动 Phase A**(5 天内完成关键缺陷修复)
|
||||
2. **并行启动 Phase B**(E2E 测试框架必须本周启动)
|
||||
3. **建立自动化验收流程**(CI 应包含验收标准检查)
|
||||
4. **定期数据库审计**(周期性检查一致性)
|
||||
|
||||
---
|
||||
|
||||
**审计完毕**
|
||||
**下一步**: 技术评审确认整改计划,进入实施阶段
|
||||
|
||||
**相关文档**:
|
||||
- `.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md` - 详细缺陷说明与整改方案
|
||||
- `.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md` - 可执行的任务拆分
|
||||
|
||||
---
|
||||
|
||||
*生成于 2026-09-12 14:50 UTC*
|
||||
本文档已迁至 [audit/2026-09-12-audit-summary-report.md](audit/2026-09-12-audit-summary-report.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,680 +1,3 @@
|
||||
# 项目全面审计与整改方案
|
||||
# 已迁移
|
||||
|
||||
> **HISTORICAL** — 缺陷详解与 Phase 设计档案。执行状态以 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 为准。
|
||||
|
||||
**日期**:2026-09-12
|
||||
**编制**:代码审计
|
||||
**状态**:待执行
|
||||
**范围**:功能完整性、实现缺陷、潜在bug 及整改优先级
|
||||
|
||||
---
|
||||
|
||||
## 一、执行现状总结
|
||||
|
||||
### 1.1 已完成的工作
|
||||
|
||||
| 项目 | 完成度 | 说明 |
|
||||
|---|---|---|
|
||||
| 业务决策文档 | ✅ 100% | `.doc/2026-09-12-three-workflows-strict-governance-remediation.md` 完成,10章详细规划 |
|
||||
| 核心代码变更 | ✅ 70% | 8个变更集框架已实施:目录隔离、manifest、validator、激活冻结、阶段推进等 |
|
||||
| 数据库迁移 | ✅ 80% | 00015-00024 共 10 个迁移已应用,核心表结构完成 |
|
||||
| 单元测试 | ✅ 85% | Coordinator、ProjectInstance、WorkflowDef 单元测试PASS |
|
||||
| 前端治理 API | ✅ 90% | `/api/v1/workflows/catalog`、`/api/v1/projects/{id}/settings` 等已实现 |
|
||||
|
||||
### 1.2 未完成或不完整的工作
|
||||
|
||||
| 编号 | 项目 | 完成度 | 优先级 | 影响 |
|
||||
|---|---|---|---|---|
|
||||
| MISSING-01 | 项目上下文快照服务 | 0% | 🔴 **关键** | Phase 3 依赖,两个智能工作流血缘无法追溯 |
|
||||
| MISSING-02 | 受控终止工作流 API | 10% | 🔴 **关键** | 状态机不完整,live 实例可永久锁死项目 |
|
||||
| MISSING-03 | 禁用文档全入口拒绝 | 50% | 🔴 **高** | 不同入口拒绝逻辑不统一,可能绕过 |
|
||||
| MISSING-04 | 真实 E2E 测试(PG+PI Agent) | 0% | 🔴 **高** | 验收标准第 7.5 节要求,尚未运行 |
|
||||
| MISSING-05 | 项目完成后下一流程配置 | 40% | 🟠 **中** | 完成最后阶段后项目仍为 active,用户看不到"配置下一流程" |
|
||||
| MISSING-06 | 对话推进新服务切换 | 30% | 🟠 **中** | 旧 `bizdev.ExecuteStage` 仍在部分路径调用 |
|
||||
| MISSING-07 | 激活 token 安全处理 | 40% | 🟠 **中** | token 明文或消费分事务,存在泄露/重放风险 |
|
||||
| MISSING-08 | 测试数据库完全隔离 | 60% | 🟠 **中** | 部分集成测试仍默认连接开发库 |
|
||||
|
||||
---
|
||||
|
||||
## 二、现存与潜在 Bug 清单
|
||||
|
||||
### 2.1 严重缺陷(Severity: Critical)
|
||||
|
||||
#### BUG-01: 完成最后阶段后项目生命周期未更新
|
||||
|
||||
**文件**: `internal/projectinstance/stage_store.go:128-158`, `internal/projectinstance/service.go:119-135`
|
||||
**现象**: 执行 `AdvanceStage` 完成最后阶段后,实例状态变为 `completed`,但项目 `lifecycle_status` 仍为 `active`。
|
||||
|
||||
**代码现场**:
|
||||
```go
|
||||
// stage_store.go:AdvanceStage
|
||||
after, err := s.store.AdvanceStage(ctx, instanceID, in.StageKey, in.ExpectedConfigRevision)
|
||||
// ... 只更新实例,未更新项目
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 项目创建者无法看到"配置下一工作流"选项
|
||||
- 前端无法识别项目已完成,可能显示旧流程按钮
|
||||
- 项目实际生命周期与数据库记录不一致
|
||||
|
||||
**验收标准冲突**: 7.4 "最后一阶段确认后实例为 completed,项目立即可配置下一流程"
|
||||
|
||||
**整改方案**:
|
||||
1. `AdvanceStage` 在同一事务中检查是否为最后阶段
|
||||
2. 若是最后阶段,同时更新 `projects.lifecycle_status` 为 `planning`
|
||||
3. 清空 `projects.current_workflow_instance_id`(可选,视数据模型)
|
||||
4. 写审计事件 `ProjectWorkflowCompleted`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-02: 推进事务内仍强制更新文档批准状态
|
||||
|
||||
**文件**: `internal/projectinstance/stage_store.go:71-158`
|
||||
**现象**: 执行阶段推进时,SQL 语句中有类似逻辑将启用任务的文档强制设置为 `approved`。
|
||||
|
||||
**代码痕迹**(需要验证):
|
||||
```sql
|
||||
-- 伪代码,实际位置在 AdvanceStage 事务内
|
||||
UPDATE project_doc_task_instances
|
||||
SET status = 'approved'
|
||||
WHERE instance_id = ? AND task_key = ? AND enabled = true;
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 违反业务规则 3.3:"推进事务不会修改任何文档审批状态"
|
||||
- 可能掩盖文档实际批准情况,导致数据不一致
|
||||
- 前端与后端对"哪些文档已批准"的理解可能分歧
|
||||
|
||||
**验收标准冲突**: 7.4 "推进事务不会修改任何文档审批状态"
|
||||
|
||||
**整改方案**:
|
||||
1. 确认 `stage_store.go:AdvanceStage` 中是否存在此 UPDATE 逻辑
|
||||
2. 若存在,删除该 UPDATE 语句
|
||||
3. `AdvanceStage` 只改变阶段状态和实例状态,不触及文档
|
||||
4. 补充单测: `TestAdvanceStage_DoesNotModifyDocumentApprovalStatus`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-03: 禁用文档状态未标记为 `skipped_disabled`
|
||||
|
||||
**文件**: `internal/projectinstance/store.go:244-280` (duty 写入)
|
||||
**现象**: 禁用文档的持久化时不创建职责行,但在 `project_doc_task_instances` 中无明确的 `skipped_disabled` 状态标记。
|
||||
|
||||
**代码现场**:
|
||||
```go
|
||||
// store.go:SaveWorkflowPlan 或类似
|
||||
for _, doc := range docs {
|
||||
if !doc.Enabled {
|
||||
continue // 跳过,不写入
|
||||
}
|
||||
// 只写启用文档
|
||||
}
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 禁用文档没有显式的数据库记录,无法区分"从未创建"与"被禁用"
|
||||
- 运行时查询时无法快速定位哪些文档被禁用,只能通过与定义比对
|
||||
- 审计和恢复时无法追溯禁用历史
|
||||
|
||||
**验收标准冲突**: 3.2 "禁用后实例状态写为 `skipped_disabled`"
|
||||
|
||||
**整改方案**:
|
||||
1. `project_doc_task_instances` 表添加状态枚举支持 `skipped_disabled`
|
||||
2. 激活时为禁用文档创建记录,状态明确设为 `skipped_disabled`
|
||||
3. 查询、拒绝等所有入口统一检查此状态
|
||||
4. 补充测试: `TestDisabledDocumentPersistence` 和 `TestDisabledDocumentRejectionAllEntries`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-04: 对话推进仍调用旧商务执行服务
|
||||
|
||||
**文件**: `internal/coordinator/engine.go:672-811`
|
||||
**现象**: 对话识别 `ADVANCE_STAGE` 意图后,调用 `bizdevSvc.ExecuteStage` 而非新的 `projectinstance.Service.AdvanceStage`。
|
||||
|
||||
**代码现场**:
|
||||
```go
|
||||
// engine.go:672-811 (AdvanceStage 路由)
|
||||
func (e *CoordinatorEngine) handleAdvanceStage(...) {
|
||||
// ...
|
||||
result, err := e.bizdevSvc.ExecuteStage(ctx, ...) // ❌ 旧服务
|
||||
// 应该调用 e.instSvc.AdvanceStage(...)
|
||||
}
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 对话推进绕过新的权限和门禁检查
|
||||
- 可能导致阶段推进状态不一致(新旧实例双轨运行)
|
||||
- 文档审批状态可能被旧 executor 强制改写
|
||||
|
||||
**验收标准冲突**: 3.4 "两种入口都调用同一个 `AdvanceStage` 应用服务"
|
||||
|
||||
**整改方案**:
|
||||
1. 修改 `CoordinatorEngine.handleAdvanceStage` 以调用新服务
|
||||
2. 删除对 `bizdevSvc.ExecuteStage` 的依赖(或标记 deprecated)
|
||||
3. 对话推进需要提取 `workflow_instance_id`(可从项目或上文获取)
|
||||
4. 补充端到端测试: `TestDialogueAdvanceStage_UsesNewService`
|
||||
|
||||
---
|
||||
|
||||
### 2.2 高优先级缺陷(Severity: High)
|
||||
|
||||
#### BUG-05: 禁用文档的拒绝逻辑不一致
|
||||
|
||||
**文件**: 多处
|
||||
**现象**: 不同入口(API、SSE、Agent tool)对禁用文档的拒绝逻辑分散,缺少统一的"fail closed"决策器。
|
||||
|
||||
**问题点**:
|
||||
- `stage_access.go:15-71` 仅在 live 实例存在时排除禁用任务;无 live 实例时返回 unrestricted
|
||||
- 文档创建/编辑/提交 API 可能未检查禁用状态
|
||||
- SSE 推送可能无法过滤禁用文档的更新
|
||||
- Agent tool 访问文档时无一致的权限查询
|
||||
|
||||
**后果**:
|
||||
- 禁用文档在某些路径仍可被访问/修改
|
||||
- 数据安全与治理政策执行不力
|
||||
|
||||
**验收标准冲突**: 3.2 "禁用后…不能通过 task key、对话、SSE、Agent tool 或旧 API 旁路启动"
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 `DocumentAccessDecider` 接口,统一决策逻辑:
|
||||
```go
|
||||
type DocumentAccessDecider interface {
|
||||
CanAccess(ctx context.Context, docTaskInstID int64, action string, userID int64) (bool, error)
|
||||
}
|
||||
```
|
||||
2. 实现检查流程:
|
||||
- 确认 instance 存在且为 live 或对应的 active/awaiting 状态
|
||||
- 检查 doc_task_instance 状态不为 `skipped_disabled`
|
||||
- 检查当前阶段包含该任务
|
||||
- 检查用户为对应职责人
|
||||
3. 在所有入口(API、SSE、异步任务、搜索、导出、RAG、Agent tool)使用此决策器
|
||||
4. 补充测试: `TestDocumentAccessDecider_AllEntries`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-06: 激活 token 安全问题
|
||||
|
||||
**文件**: `internal/projectinstance/service.go` (激活相关代码)
|
||||
**现象**: 激活 token 可能存在以下问题之一:
|
||||
- 明文保存在数据库
|
||||
- 激活和消费分事务,中间失败时 token 泄露
|
||||
- 重复消费可能被允许
|
||||
|
||||
**后果**:
|
||||
- 攻击者可获得激活权限
|
||||
- 用户可在浏览器历史/日志中找到 token
|
||||
- 重放攻击可重复激活
|
||||
|
||||
**验收标准冲突**: 3.1 "激活时冻结…运行中不可静默修改" 的先决条件是原子激活
|
||||
|
||||
**整改方案**:
|
||||
1. 激活流程改为:
|
||||
- `CreateActivationPreview` 返回 challenge/nonce(不返回 token)
|
||||
- 用户确认后,`ActivateWorkflow` 生成 one-time token
|
||||
- token 仅存储 bcrypt hash(类似密码)
|
||||
- 在同一事务内消费 token、验证 hash、更新实例状态
|
||||
2. token 过期时间设为 5 分钟
|
||||
3. 补充测试: `TestActivationTokenSecurity`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-07: 项目完成后项目生命周期转换逻辑缺失
|
||||
|
||||
**文件**: `internal/projectinstance/service.go`, `internal/projectworkflow/service.go`
|
||||
**现象**: 完成一个工作流后,项目无法自动进入可选择下一工作流的状态。
|
||||
|
||||
**代码现场**:
|
||||
```go
|
||||
// projectinstance/service.go:119-135
|
||||
// GetSettings 只允许 lifecycle == LifecyclePlanning 时编辑
|
||||
if lifecycle != LifecyclePlanning {
|
||||
return nil, ErrPlanFrozen // completed 实例的项目仍不能选择下一流程
|
||||
}
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 用户必须手工改数据库才能运行下一工作流
|
||||
- 用户体验与业务规则相悖
|
||||
|
||||
**验收标准冲突**: 3.1 "完成或受控终止后创建下一工作流实例"
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 `CompleteWorkflowInstance` 应用服务:
|
||||
- 检查实例处于最后阶段且阶段就绪
|
||||
- 在事务内:标记实例为 `completed`,项目改为 `planning`,清空 live 指针
|
||||
2. `AdvanceStage` 检查当前阶段是否为最后阶段,是则调用此服务
|
||||
3. 补充测试: `TestProjectLifecycleAfterCompletion`
|
||||
|
||||
---
|
||||
|
||||
### 2.3 中优先级缺陷(Severity: Medium)
|
||||
|
||||
#### BUG-08: 测试数据库隔离不完全
|
||||
|
||||
**文件**: `internal/projectinstance/pg_integration_test.go:19-49`,`internal/server/workflow_governance_pg_test.go:26-61`
|
||||
**现象**: 集成测试未设置 `TEST_DATABASE_URL` 时默认连接本地开发库,导致测试数据污染。
|
||||
|
||||
**现场数据**:
|
||||
```
|
||||
开发库 workflow_definitions = 92 个
|
||||
其中 pg_* / test_* 命名 = 88 个(测试污染)
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 业务数据与测试数据混淆
|
||||
- 本地开发环境无法清洁复现
|
||||
- CI/CD 若复用开发库会产生不可预测的行为
|
||||
|
||||
**验收标准冲突**: 7.5 "测试结束后业务数据库中不残留 `pg_*`、`test_*` 定义"
|
||||
|
||||
**整改方案**:
|
||||
1. 所有 `*_test.go` 中强制要求 `TEST_DATABASE_URL`;未设置时 skip 或 fatal
|
||||
2. 测试前创建隔离 schema 或独立库,测试后清理
|
||||
3. CI 配置中显式设置 `TEST_DATABASE_URL` 指向临时数据库
|
||||
4. 补充 CI 脚本检查:测试结束后确认开发库中无 `pg_*`、`test_*` 定义
|
||||
|
||||
---
|
||||
|
||||
#### BUG-09: 版本冲突时前端自动重试
|
||||
|
||||
**文件**: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:38-76,173-236`
|
||||
**现象**: 当两个浏览器同时切换工作流时,第一个返回版本冲突,但前端自动取新版本再次提交,无需用户确认。
|
||||
|
||||
**代码现场**:
|
||||
```typescript
|
||||
// ProjectWorkflowSwitcher.tsx:173-236
|
||||
// 冲突时自动重试,而非展示冲突提示
|
||||
if (conflict) {
|
||||
fetchLatestAndRetry(); // ❌ 自动重试,用户不知情
|
||||
}
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 用户最新选择被覆盖
|
||||
- 可能激活非预期的工作流
|
||||
- 与业务规则冲突
|
||||
|
||||
**验收标准冲突**: 7.2 "两个浏览器同时配置或推进时…另一个收到版本冲突并重新确认"
|
||||
|
||||
**整改方案**:
|
||||
1. 冲突时展示弹窗:"您的选择与其他编辑冲突,请重新确认"
|
||||
2. 显示当前版本、冲突版本和新版本内容
|
||||
3. 用户确认后重新提交,而非自动重试
|
||||
4. 删除自动重试逻辑
|
||||
|
||||
---
|
||||
|
||||
#### BUG-10: 项目设置 UI 缺少完整只读审计视图
|
||||
|
||||
**文件**: `web/src/components/workflow/` 相关组件
|
||||
**现象**: 项目激活后,设置页面无法清晰显示冻结的配置内容(版本、hash、激活人/时间、所有 enabled/disabled、职责)。
|
||||
|
||||
**后果**:
|
||||
- 创建者不知道实际冻结的是什么
|
||||
- 无法自助诊断权限问题
|
||||
- 审计信息不可见
|
||||
|
||||
**验收标准冲突**: 7.2 "live 配置缺少完整只读审计视图"
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 "工作流运行详情" 只读面板,显示:
|
||||
- 工作流版本、发布时间、hash
|
||||
- 激活人员、激活时间
|
||||
- 所有启用文档及三权职责
|
||||
- 所有禁用文档及禁用原因
|
||||
- 当前阶段进度
|
||||
2. 补充测试: `TestWorkflowAuditViewCompleteness`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-11: 旧切换 API 未正式下线
|
||||
|
||||
**文件**: `internal/server/server.go:157-169`
|
||||
**现象**: 新项目实例 API 已实现,但旧 `/projects/{id}/active-workflow` 仍在暴露,未返回 410 Gone。
|
||||
|
||||
**代码现场**:
|
||||
```go
|
||||
// server.go:157-169
|
||||
mux.HandleFunc("POST /projects/{id}/active-workflow", s.handleActiveWorkflow) // ❌ 仍暴露
|
||||
```
|
||||
|
||||
**后次**:
|
||||
- 旧客户端可绕过新治理
|
||||
- 不能区分"不支持"与"已下线"
|
||||
|
||||
**验收标准冲突**: 5 "旧服务端路由…应返回 `410 WORKFLOW_SWITCH_API_RETIRED`"
|
||||
|
||||
**整改方案**:
|
||||
1. 将 `/projects/{id}/active-workflow` 路由改为返回 410 Gone 和迁移指引
|
||||
2. 添加 deprecation 日志
|
||||
3. 补充测试: `TestLegacyAPIReturns410`
|
||||
|
||||
---
|
||||
|
||||
### 2.4 低优先级缺陷(Severity: Low)
|
||||
|
||||
#### BUG-12: 前端名称不一致
|
||||
|
||||
**文件**: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:16-23`
|
||||
**现象**: 前端硬编码的三个工作流名称与后端正式名称不一致。
|
||||
|
||||
**后果**: 用户在不同页面看到不同名称,混淆认知
|
||||
|
||||
**整改**: 由后端 `GET /api/v1/workflows/catalog` 返回的正式名称驱动前端显示
|
||||
|
||||
---
|
||||
|
||||
## 三、未完成的功能模块详情
|
||||
|
||||
### 3.1 项目上下文快照服务(ProjectContextSnapshot)
|
||||
|
||||
**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:82-105`
|
||||
**当前状态**: 规划完整,实现 0%
|
||||
**关键要求**:
|
||||
|
||||
1. **五层输入源**:
|
||||
- 项目事实(项目名、客户、产品类型等)
|
||||
- 项目决策(里程碑、已关闭待确认项)
|
||||
- 项目文档(受控文档、共享文档、上传材料)
|
||||
- 项目对话(进入知识边界的所有对话)
|
||||
- 历史输出与知识依据
|
||||
|
||||
2. **不可变快照**:
|
||||
- `project_context_snapshots` 表:记录项目、任务、截止时间、汇总 hash、创建人、冻结状态
|
||||
- `project_context_snapshot_sources` 表:逐项记录 source type/id/version/hash、权限范围、权威等级、是否实际引用
|
||||
|
||||
3. **冲突优先级**:
|
||||
- 创建者确认事实/决策 > 已批准文档 > 上传材料 > 里程碑记录 > 普通对话 > 智能体总结
|
||||
|
||||
4. **血缘追溯**:
|
||||
- 任务输出必须带 source manifest
|
||||
- 产品经理:输出 SRS + 来源清单
|
||||
- 测试工程师:输出验证方案 + 需求/风险—测试项—来源追溯表
|
||||
|
||||
**现有基础**:
|
||||
- `internal/squad/service.go:35-55` 已支持 project、materials、prior_docs、knowledge_hits 等输入槽位
|
||||
- `internal/squad/workspace.go:262-408` 已有 context 索引建立能力
|
||||
- `internal/bizdev/service.go:250-294` 已有部分项目事实输入逻辑
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 `internal/projectcontext/service.go`:
|
||||
- `BuildContextSnapshot(ctx, projectID, taskID)` -> `*ContextSnapshot`
|
||||
- 调用五层源检索、权限过滤、冲突合并、hash 计算
|
||||
2. 新增数据库表与迁移
|
||||
3. 产品经理与测试工程师都改用此服务
|
||||
4. 补充集成测试
|
||||
|
||||
**验收标准**: 7.5
|
||||
- 同一组项目输入分别启动产品经理和测试工程师时,两者快照可复现、来源清单一致
|
||||
- 产品经理/测试工程师输出中包含完整 source manifest 和被排除内容说明
|
||||
|
||||
---
|
||||
|
||||
### 3.2 受控终止工作流(WorkflowTermination)
|
||||
|
||||
**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:109-131` (状态机)
|
||||
**当前状态**: 状态表存在,API 和逻辑 0%
|
||||
**关键要求**:
|
||||
|
||||
1. **状态转换**:
|
||||
```
|
||||
active → termination_requested → terminated
|
||||
```
|
||||
|
||||
2. **操作约束**:
|
||||
- 仅创建者可申请
|
||||
- 需二次确认
|
||||
- 需填写原因
|
||||
- 处理或取消在途任务
|
||||
- 生成审计
|
||||
|
||||
3. **API**:
|
||||
- `POST /api/v1/workflow-instances/{id}/termination-preview` - 预览影响
|
||||
- `POST /api/v1/workflow-instances/{id}/terminate` - 执行终止
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 `internal/projectinstance/terminate.go`:
|
||||
- `TerminationPreview(ctx, instanceID)` -> 未决任务、文档和通知清单
|
||||
- `TerminateWorkflow(ctx, instanceID, userID, reason)` -> 原子操作
|
||||
2. 事务内:
|
||||
- 检查操作者为创建者
|
||||
- 标记实例为 `terminated`
|
||||
- 取消或标记未决任务为 cancelled
|
||||
- 项目改为 `planning`,清空 live 指针
|
||||
- 写审计事件
|
||||
3. 补充 API 路由和端到端测试
|
||||
|
||||
**验收标准**: 7.3
|
||||
- 创建者可以选择"受控终止"而非永久锁死
|
||||
- terminated 状态的项目可创建下一实例
|
||||
- 审计记录包含终止原因
|
||||
|
||||
---
|
||||
|
||||
### 3.3 真实 E2E 测试(PostgreSQL + PI Agent)
|
||||
|
||||
**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:417-459` (验收标准)
|
||||
**当前状态**: 单元测试 PASS,E2E 0%
|
||||
**要求**:
|
||||
|
||||
1. 使用真实 PostgreSQL(不是内存 mock)
|
||||
2. 使用真实 PI Agent 容器
|
||||
3. 完整链路:
|
||||
- 创建项目 → 选择工作流 → 激活 → 推进各阶段 → 完成 → 配置下一工作流
|
||||
4. 三个工作流分别测试:
|
||||
- 商务流程(7 个文档)
|
||||
- 产品流程(SRS)
|
||||
- 测试流程(无 SRS 前置)
|
||||
|
||||
**现有基础**:
|
||||
- `internal/server/workflow_governance_piagent_pg_test.go` 已有 PG 集成框架
|
||||
- PI Agent 容器已在 `docker-compose.yml` 中定义
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 `internal/server/e2e_workflow_test.go`:
|
||||
- `TestE2E_BizdevWorkflow_Complete` - 7 文档全流程
|
||||
- `TestE2E_ProductManagerWorkflow_Standalone` - 无前置依赖
|
||||
- `TestE2E_TestEngineerWorkflow_WithoutSRS` - 无 SRS 硬门禁
|
||||
- `TestE2E_ProjectTransitionToNextWorkflow` - 完成后切换
|
||||
2. 设置 `TEST_DATABASE_URL` 指向隔离库
|
||||
3. 启动 PI Agent 容器(或 mock 其接口)
|
||||
4. 逐步执行,记录结果
|
||||
|
||||
**验收标准**: 7.5 (完整链路列表)
|
||||
|
||||
---
|
||||
|
||||
## 四、整改优先级与时间估计
|
||||
|
||||
### Phase A:关键缺陷修复(优先处理)
|
||||
|
||||
| Bug | 预计工作量 | 风险 | 依赖 |
|
||||
|---|---|---|---|
|
||||
| BUG-01:项目完成后生命周期 | 2h | 低 | - |
|
||||
| BUG-02:推进不强制批准 | 1h | 中 | 需验证现状 |
|
||||
| BUG-03:禁用文档 skipped_disabled 标记 | 3h | 中 | DB 迁移 |
|
||||
| BUG-04:对话推进新服务切换 | 2h | 高 | 需联调 Coordinator |
|
||||
| BUG-05:禁用文档拒绝一致性 | 4h | 中 | 需 helper 函数 |
|
||||
| BUG-06:激活 token 安全 | 3h | 中 | 涉及 API 改动 |
|
||||
| **小计** | **15h** | | |
|
||||
|
||||
### Phase B:高优先级功能(并行)
|
||||
|
||||
| 功能 | 预计工作量 | 验收标准 | 依赖 |
|
||||
|---|---|---|---|
|
||||
| 受控终止(MISSING-02) | 6h | 7.3 | BUG-01 |
|
||||
| 真实 E2E 测试(MISSING-04) | 8h | 7.5 | Phase A + 容器 |
|
||||
| 项目上下文快照(MISSING-01) | 12h | 7.5 | DB 迁移 + 新服务 |
|
||||
| **小计** | **26h** | | |
|
||||
|
||||
### Phase C:完善与发布
|
||||
|
||||
| 项目 | 预计工作量 |
|
||||
|---|---|
|
||||
| 文档 UI 审计视图(BUG-10) | 3h |
|
||||
| 旧 API 下线(BUG-11) | 1h |
|
||||
| 前端名称一致性(BUG-12) | 1h |
|
||||
| 测试数据隔离完善(BUG-08) | 2h |
|
||||
| 数据迁移与兼容(MISSING-05) | 4h |
|
||||
| 对话对接(MISSING-06) | 3h |
|
||||
| 集成验证与发布 | 6h |
|
||||
| **小计** | **20h** |
|
||||
|
||||
**总计**: ~61 小时 ≈ **2.5 天(单人全职)**或 **5 天(双人)**
|
||||
|
||||
---
|
||||
|
||||
## 五、整改执行计划
|
||||
|
||||
### 5.1 Day 1: 关键缺陷修复
|
||||
|
||||
**Morning (4h)**:
|
||||
1. BUG-01 修复:AdvanceStage → 同事务更新项目生命周期
|
||||
- 修改 `stage_store.go` 和 `service.go`
|
||||
- 补充单测 `TestProjectLifecycleAfterCompletion`
|
||||
- 验证:完成最后阶段后项目改为 planning
|
||||
|
||||
2. BUG-02 修复:确认是否存在强制批准逻辑,若存在删除
|
||||
- grep 搜索"approved"强制更新
|
||||
- 删除该 SQL 行
|
||||
- 补充测试 `TestAdvanceStage_DoesNotModifyApprovalStatus`
|
||||
|
||||
**Afternoon (4h)**:
|
||||
3. BUG-04 修复:对话推进切换到新服务
|
||||
- 修改 `coordinator/engine.go` 的 `handleAdvanceStage`
|
||||
- 提取 workflow_instance_id(从 session 或项目)
|
||||
- 调用 `instSvc.AdvanceStage` 替代 `bizdevSvc.ExecuteStage`
|
||||
- 补充对话测试
|
||||
|
||||
4. BUG-06 开始:激活 token 安全重构
|
||||
- 设计 one-time token 与 hash 方案
|
||||
- 修改激活预览与激活 API
|
||||
|
||||
### 5.2 Day 2: 继续缺陷修复 + 开始新功能
|
||||
|
||||
**Morning (4h)**:
|
||||
5. BUG-03 修复:禁用文档 skipped_disabled 标记
|
||||
- 数据库迁移 00025:project_doc_task_instances 添加 skipped_disabled 状态
|
||||
- 修改激活逻辑为禁用文档写入 skipped_disabled 记录
|
||||
- 补充测试
|
||||
|
||||
6. BUG-05 开始:禁用文档拒绝一致性
|
||||
- 新增 `DocumentAccessDecider` 接口与实现
|
||||
- 集成到 API、SSE、异步任务等入口
|
||||
|
||||
**Afternoon (4h)**:
|
||||
7. 受控终止开发(MISSING-02)
|
||||
- 新增 `terminate.go` 服务
|
||||
- 实现终止预览和执行 API
|
||||
- 补充测试
|
||||
|
||||
### 5.3 Day 3: 新功能开发与集成测试
|
||||
|
||||
**Full Day (8h)**:
|
||||
8. 项目上下文快照初版(MISSING-01)
|
||||
- 新增 `projectcontext/service.go`
|
||||
- 实现快照构建与来源清单
|
||||
- 产品/测试工程师改用新服务
|
||||
|
||||
9. 真实 E2E 测试启动(MISSING-04)
|
||||
- 编写 E2E 测试框架
|
||||
- 三个工作流链路验证
|
||||
- 文档与验证报告
|
||||
|
||||
---
|
||||
|
||||
## 六、质量保证与验收检查表
|
||||
|
||||
### 6.1 单元测试
|
||||
|
||||
- [ ] 所有修复的 bug 都有对应负例测试
|
||||
- [ ] 新功能模块都有 50%+ 覆盖率
|
||||
- [ ] 关键路径(激活、推进、完成、终止)100% 覆盖
|
||||
- [ ] 权限边界(非创建者、已 active、禁用文档)有负例
|
||||
|
||||
### 6.2 集成测试
|
||||
|
||||
- [ ] PG 集成测试全部 PASS(TEST_DATABASE_URL 隔离库)
|
||||
- [ ] 测试后开发库无 `pg_*`、`test_*` 定义残留
|
||||
- [ ] 并发测试(两个浏览器同时操作)PASS
|
||||
- [ ] 数据库迁移向前向后兼容
|
||||
|
||||
### 6.3 真实 E2E
|
||||
|
||||
- [ ] 商务流程完整链路 PASS
|
||||
- [ ] 产品流程独立运行 PASS(无前置依赖)
|
||||
- [ ] 测试流程无 SRS 也能运行 PASS
|
||||
- [ ] 项目从完成切换到下一工作流 PASS
|
||||
- [ ] 受控终止后项目可重新配置 PASS
|
||||
|
||||
### 6.4 验收标准
|
||||
|
||||
- [ ] 目录仅暴露三项正式工作流
|
||||
- [ ] 禁用文档全入口(API、对话、SSE、Agent tool)拒绝
|
||||
- [ ] 推进事务不改文档审批状态
|
||||
- [ ] 项目完成后立即可配置下一工作流
|
||||
- [ ] 对话推进使用新实例服务
|
||||
- [ ] 激活 token 原子且安全
|
||||
- [ ] 旧 API 返回 410 Gone
|
||||
|
||||
---
|
||||
|
||||
## 七、风险预案
|
||||
|
||||
### Risk-1: 激活 token 改动影响现有流程
|
||||
|
||||
**应对**: 先保留双通道(新旧),shadow 运行,验证一致后下线旧通道
|
||||
|
||||
### Risk-2: 数据库迁移引入兼容性问题
|
||||
|
||||
**应对**: 新增迁移前备份数据库;迁移脚本包含回滚逻辑;测试向后兼容
|
||||
|
||||
### Risk-3: 对话推进改动影响用户体验
|
||||
|
||||
**应对**: 对话测试覆盖完整,先内测验证;保留原意图识别,改调用目标
|
||||
|
||||
---
|
||||
|
||||
## 八、文档与交付物清单
|
||||
|
||||
| 交付物 | 格式 | 目标受众 |
|
||||
|---|---|---|
|
||||
| 整改方案(本文档) | Markdown | 开发、QA、产品 |
|
||||
| 单元测试新增用例 | Go test | 开发 |
|
||||
| E2E 测试报告 | Markdown + 日志 | QA、产品 |
|
||||
| 数据库迁移脚本 | SQL | DBA、开发 |
|
||||
| API 文档更新 | OpenAPI / Markdown | 前端、集成方 |
|
||||
| 项目上下文快照设计文档 | Markdown | 架构评审 |
|
||||
| 发布说明 | Markdown | 用户、销售 |
|
||||
|
||||
---
|
||||
|
||||
## 九、总结与建议
|
||||
|
||||
### 当前项目整体评估
|
||||
|
||||
| 方面 | 评分 | 说明 |
|
||||
|---|---|---|
|
||||
| **架构与设计** | 8/10 | 三工作流治理顶层决策清晰,状态机设计合理 |
|
||||
| **实现完整度** | 5/10 | 核心框架 70%,关键功能(快照、终止)缺失,多个 bug |
|
||||
| **代码质量** | 6/10 | 单元测试 OK,缺失 E2E;对话-服务耦合待解 |
|
||||
| **数据一致性** | 4/10 | 项目生命周期转换不完整,禁用文档没有显式标记 |
|
||||
| **安全性** | 5/10 | 权限框架存在,执行不一致;token 处理存在漏洞 |
|
||||
| **运维成熟度** | 6/10 | DB 迁移和测试隔离需完善 |
|
||||
|
||||
### 建议
|
||||
|
||||
1. **优先完成 Phase A 缺陷修复**(2 天)以稳定当前功能
|
||||
2. **并行开发 Phase B 新功能**(3 天),特别是 E2E 测试以验证整体逻辑
|
||||
3. **建立自动化验收流程**:CI 应包括所有验收标准的检查
|
||||
4. **后续维护建议**:
|
||||
- 禁用项目选择非正式工作流的自动检查(CI 中)
|
||||
- 每次激活/推进/完成后都输出审计链(便于故障排查)
|
||||
- 项目完成前端页面加"确认完成工作流"的双确认卡
|
||||
- 定期数据库快照与清理脚本(防止垃圾数据)
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**最后更新**: 2026-09-12 14:45 UTC
|
||||
**下一步**: 待产品&技术评审确认,进入实施阶段
|
||||
本文档已迁至 [remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md](remediation/2026-09-12-comprehensive-audit-and-remediation-plan.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,706 +1,3 @@
|
||||
# Agent System 权限、设置与三类工作流完整实施方案
|
||||
# 已迁移
|
||||
|
||||
## 1. 执行结论
|
||||
|
||||
当前系统已经完成了从原型向受控工作流平台演进所需的多数“结构件”:数据库账户与会话、系统角色/权限表、项目成员、工作流定义及版本、模板版本、项目工作流实例、阶段实例、文档任务实例、三权职责、激活确认、阶段推进请求、通知 Outbox、任务运行持久化和文档血缘均已存在。现有 Go 短测、前端测试和生产构建也能通过。因此,本轮不应推倒重做,而应完成最后一段也是最关键的一段:**统一授权权威、把设置真正落到服务端、让已发布工作流版本成为运行时唯一事实源,并将商务对接、智能产品经理、智能测试经理发布为可配置、可冻结、可执行、可审计的正式工作流。**[^1][^2][^3]
|
||||
|
||||
但截至本次审计,系统还不能宣称“权限和设置已做全”,三个工作流也还不能按当前治理设计直接投入多人生产使用。核心原因如下:
|
||||
|
||||
1. **权限表存在,但策略执行不完整。** 部分项目查询、工作流历史和血缘查询缺少对象级授权;创建项目只校验登录,不校验 `project:create`;工作流管理 API 仍统一要求超级管理员,未使用已入库的细粒度权限;系统权限计算还忽略绑定作用域、角色状态和 `valid_from`。[^4][^5][^6]
|
||||
2. **阶段权限存在高风险放行路径。** 解析 live 实例发生数据库错误时会回退为“不限制”,多个列表、聊天、RAG/上下文过滤辅助函数也在错误时放行;拥有当前阶段任一文档职责的用户会获得该阶段全部文档任务权限,任务执行门禁还允许其运行任意 `task_key`。[^7][^8]
|
||||
3. **设置界面与服务端权威尚未闭环。** 浏览器仍把 Bearer token 和会话对象放入 `localStorage`,登出只删除本地状态;个人资料保存、个人偏好和部分权限画像仍是前端本地数据,已有活动会话 API 未在用户设置中形成闭环。[^9][^10]
|
||||
4. **三个工作流只是“登记过”,不是“完整接入”。** `main`、`product_manager`、`test_manager` 已作为发布种子存在,但都是单阶段包装;运行目录会把任意已发布版本压扁为第一阶段的第一个任务。商务对接真实的 V0.1/V0.5/V1.0 阶段仍硬编码在 BizDev 执行器中;产品经理和测试经理的五步 Agent 流程存在,但没有由版本化定义驱动。[^11][^12][^13]
|
||||
5. **项目实例与文档治理还未成为同一条链。** 规划校验没有检查必需阶段/必需任务是否被整个遗漏,也没有校验三权人员是否为有效项目成员;实例持久化把所有阶段 `position` 写成 0;执行器又会在请求未传三权时回退到固定用户 2/3,并把文档阶段固定为 `V0.5_feasibility`,没有消费冻结实例中的职责和活动阶段。[^14][^15]
|
||||
|
||||
因此建议把工作拆为三道发布闸门:
|
||||
|
||||
- **闸门 A:授权止血。** 先关闭跨项目读取、错误放行、任意任务键、身份/会话本地权威等 P0;完成全部 API/数据通路的策略矩阵。
|
||||
- **闸门 B:配置与运行时合流。** 扩展工作流 schema,建立 `executor_key` 注册表和全阶段解释器,让项目实例、DocGov、任务运行、对话/RAG、文档血缘都从同一冻结快照取值。
|
||||
- **闸门 C:发布三个正式版本。** 以新版本而不是覆盖旧数据的方式发布三个工作流,完成迁移、真实 PostgreSQL、跨用户负例和真实 PI Agent E2E 后再开放生产选择。
|
||||
|
||||
本方案遵循当前系统已经确定的治理原则:生产身份只来自服务端会话;系统角色、项目角色和单文档三权职责分离;已发布版本不可原地修改;项目激活时冻结完整快照;同一项目只允许一个 live 工作流;当前流程完成或受控终止后才能选择下一个;门禁满足只发提醒,阶段推进必须由项目创建人明确确认。[^1]
|
||||
|
||||
## 2. 本次研究范围与验证边界
|
||||
|
||||
### 2.1 已审阅范围
|
||||
|
||||
| 层 | 已审阅内容 |
|
||||
|---|---|
|
||||
| 数据库 | Goose `00014`–`00020`:成员、IAM、工作流/模板、项目实例、通知、任务运行 |
|
||||
| 后端 | `internal/auth`、`authz`、`workflowdef`、`projectinstance`、`projectworkflow`、`bizdev`、`squad`、`server` |
|
||||
| 前端 | 登录会话、RBAC 类型、用户设置、系统设置、项目设置、工作流切换/展示 |
|
||||
| 业务执行 | 商务对接真实阶段;产品经理/测试经理 Agent 角色、步骤、模板、质量门禁、前置依赖和血缘 |
|
||||
| 既有文档 | 2026-09-11 治理总方案、Phase 1/2 实施计划、当前 PG/CI/Soak/E2E 报告 |
|
||||
|
||||
### 2.2 本轮已执行验证
|
||||
|
||||
```text
|
||||
go test -short -timeout 8m \
|
||||
./internal/auth/... ./internal/authz/... ./internal/workflowdef/... \
|
||||
./internal/projectinstance/... ./internal/projectworkflow/... ./internal/server/...
|
||||
结果:全部通过
|
||||
|
||||
cd web && npm test
|
||||
结果:170 项 Node tests + 22 项 Vitest tests 全部通过
|
||||
|
||||
cd web && npm run build
|
||||
结果:TypeScript + Vite 构建通过;存在主 bundle 过大的非阻断警告
|
||||
```
|
||||
|
||||
这些结果证明当前分支能编译且现有回归未破坏,不证明跨租户授权、真实 PostgreSQL 事务、重启恢复和真实 PI Agent 长链路已满足本方案的发布门禁。当前测试报告中 PI Agent 全生命周期仍记录了 `/v1/run` 超时,且报告结尾又写“仍在运行”,应先修正文档状态,再以一次新的、带 commit SHA 和环境指纹的运行作为验收证据。[^16]
|
||||
|
||||
### 2.3 外部设计基线
|
||||
|
||||
授权采用“默认拒绝、每次请求验证、对象标识不可猜测越权、失败安全退出、记录审计”的基线;动态项目、阶段和文档条件用 RBAC + ReBAC + ABAC 组合,而不是只靠全局角色。OWASP 明确建议默认拒绝并对每次请求执行权限判断;NIST RBAC 模型把用户、角色、权限、操作和对象建模为独立关系,并支持职责分离约束。[^17][^18]
|
||||
|
||||
浏览器会话不再把认证 token 放在 `localStorage`。OWASP 指出 Web Storage 可被同源 JavaScript 读取,建议会话使用 `HttpOnly; Secure; SameSite` Cookie;Cookie 模式下同时补齐 CSRF 防护。[^19]
|
||||
|
||||
## 3. 当前系统能力盘点
|
||||
|
||||
### 3.1 可以直接保留并扩展的能力
|
||||
|
||||
| 能力 | 当前状态 | 本方案处理 |
|
||||
|---|---|---|
|
||||
| 统一 API 认证中间件 | 已存在 | 保留;切换到安全 Cookie/CSRF,并在授权失败时统一错误模型 |
|
||||
| 数据库账户、密码哈希、会话哈希 | 已存在 | 保留;增加密码/MFA/重置策略、会话前端闭环和安全事件 |
|
||||
| 系统角色/权限/绑定 | 已存在 | 纠正多角色、作用域、有效期、状态和管理审计语义 |
|
||||
| `project_members` | 已存在 | 增加 FK、项目业务角色多绑定、成员状态和职责候选资格 |
|
||||
| 工作流草稿/发布/退役 | 后端基础存在 | 增加复制草稿、完整 schema、细粒度授权、发布影响预览和 UI |
|
||||
| 模板 CAS/版本/扫描状态 | 基础存在 | 增加扫描 worker、隔离区、预览、发布/退役和引用影响分析 |
|
||||
| 项目规划/预览/确认/冻结 | 基础存在 | 修复完整性校验、原子 token、阶段顺序、受控变更和下一个工作流 |
|
||||
| 文档三权状态机 | 已存在 | 由实例职责驱动;加职责资格、再认证/签署策略和阶段门禁映射 |
|
||||
| Outbox/通知/阶段推进请求 | 已存在 | 完成用户偏好、渠道、升级、去重和创建人确认体验 |
|
||||
| 任务运行持久化/lease | 已存在 | 把任务与实例/阶段/任务定义绑定;细分 read/cancel/resume 权限 |
|
||||
| 文档血缘/stale | 已存在 | stale 成为阶段退出阻断条件,提供影响分析和重新基线闭环 |
|
||||
|
||||
### 3.2 当前成熟度判定
|
||||
|
||||
| 领域 | 代码骨架 | 服务端权威 | 前端闭环 | 生产验收 | 判定 |
|
||||
|---|---:|---:|---:|---:|---|
|
||||
| 认证与会话 | 高 | 中 | 低 | 中 | 需整改 |
|
||||
| 系统 RBAC | 中 | 低 | 中 | 低 | 发布阻断 |
|
||||
| 项目 ReBAC | 中 | 中 | 中 | 低 | 发布阻断 |
|
||||
| 阶段/文档 ABAC | 中 | 低 | 中 | 低 | 发布阻断 |
|
||||
| 用户设置 | 中 | 低 | 中 | 低 | 未做全 |
|
||||
| 系统设置 | 中 | 中 | 中 | 低 | 未做全 |
|
||||
| 项目设置 | 中高 | 中 | 中 | 低 | 关键断点 |
|
||||
| 工作流设计/版本 | 中高 | 中 | 低 | 低 | 关键断点 |
|
||||
| 三工作流执行器 | 高 | 低 | 中 | 低 | 尚未正式接入 |
|
||||
| 审计与通知 | 中 | 中 | 低 | 低 | 尚未闭环 |
|
||||
|
||||
## 4. 必须优先修复的问题清单
|
||||
|
||||
### 4.1 P0:在接入三个工作流前必须关闭
|
||||
|
||||
| ID | 问题 | 影响 | 整改与验收 |
|
||||
|---|---|---|---|
|
||||
| AUTH-001 | 工作流运行历史、文档血缘 handler 未调用项目对象授权 | 登录用户可能读取其他项目元数据/血缘 | 所有项目子路由统一经过资源加载 + `Authorize`;跨项目返回 404 或统一 403;加双用户 PG 负例 |
|
||||
| AUTH-002 | 阶段访问解析或过滤出错时放行 | DB/策略故障可扩大文档、聊天、RAG、Agent 上下文可见范围 | 生产环境 fail closed;只对明确标记的 legacy 项目执行迁移期策略,且有截止版本和指标 |
|
||||
| AUTH-003 | 工作流路由接受客户端覆盖 `task_key`;阶段成员可运行当前阶段任意任务 | 绕过工作流定义和文档职责 | 服务端只从 `workflow_instance_id + active_stage + task_instance_id` 推导 executor;拒绝不在快照中的任务 |
|
||||
| AUTH-004 | 项目规划可以整个遗漏必需阶段/任务 | 可激活空壳或删减受控交付物的计划 | 对定义中每个 non-optional stage 和 required/blocking task 做反向完整性校验 |
|
||||
| AUTH-005 | 三权用户未校验有效账户、项目成员和候选角色 | 可把无权或已停用用户写入审批链 | 激活前逐人校验 membership/status/eligibility/职责分离;激活后人员失效触发阻断事件 |
|
||||
| AUTH-006 | 项目列表 SQL 把 `creator_id=1`/NULL 项目视为公开,旧切换逻辑有固定用户/项目 ID 豁免 | 演示兼容规则泄漏到真实授权 | 删除 ID 特判;显式 `project_visibility`/legacy migration,不以 creator ID 表达公开 |
|
||||
| AUTH-007 | 项目创建接口未检查 `project:create` | 任意活动账户可立项 | handler/service 双层校验 `projects.create`,前端按钮仅作体验控制 |
|
||||
| AUTH-008 | 项目成员可读取/取消其他成员任务运行,未区分动作 | 破坏他人运行和审计归属 | `task_runs.view_own/view_project/cancel_own/cancel_any/resume` 分权;取消他人任务须负责人或创建人 |
|
||||
| AUTH-009 | 本地 token、仅本地 logout、失效 `/me` 后仍保留登录态 | XSS/撤销后前端假登录 | 改安全 Cookie;服务端 logout;`/me` 401 立即清空主体和缓存;权限加载失败敏感动作 fail closed |
|
||||
| WF-001 | DBCatalog 将完整版本压扁为第一阶段第一任务 | 发布多阶段定义也不会按定义运行 | 移除 flatten 执行路径,新增实例编排器逐阶段/任务读取冻结快照 |
|
||||
| WF-002 | DocGov 三权和阶段来自请求/固定默认值,不来自实例 | 配置的责任人和活动阶段不生效 | 由 `doc_task_instance_id` 解析 author/reviewer/approver/stage;禁止生产请求传入身份覆盖 |
|
||||
|
||||
### 4.2 P1:首次正式发布必须完成
|
||||
|
||||
| ID | 问题 | 整改 |
|
||||
|---|---|---|
|
||||
| IAM-101 | `ListCapabilities` 忽略 `scope_type/scope_id`、角色状态和 `valid_from` | 引入带资源上下文的 PDP;系统能力只取 `scope_type=system, scope_id=0`,校验角色/账户/有效期 |
|
||||
| IAM-102 | `users.role_id` 与 `user_role_bindings` 双权威,更新角色会删除其他绑定 | `user_role_bindings` 为唯一权威;`users.role_id` 只作迁移兼容后移除;支持多角色 |
|
||||
| IAM-103 | `assigned_by` 被写成目标用户本身,角色+状态更新非原子且忽略角色更新错误 | 从 principal 传 actor;单事务变更;写不可变审计事件;失败整体回滚 |
|
||||
| IAM-104 | `role-admin` 字符串直接赋予管理员身份,`perm:manage` 又作为所有权限通配 | 显式 `system.superadmin`;普通 `permissions.manage` 不再通配业务数据;至少两名受控管理员防死锁 |
|
||||
| IAM-105 | 前端权限键只有最早 7 项,后端迁移已有更多权限 | 后端暴露 permission catalog;前端由 API 渲染,不维护硬编码联合类型作为事实源 |
|
||||
| SET-101 | 用户资料保存只改 React state;偏好仅组件本地;活动会话 UI 缺失 | 增加 `/me/profile`、`/me/preferences`、`/me/notification-preferences` 和会话管理 UI |
|
||||
| SET-102 | 管理中心工作流页只能列出/校验/发布,不能完整建模 | 增加创建、复制草稿、阶段排序、任务/职责/参与策略、模板选择、diff、发布、退役 |
|
||||
| SET-103 | Office 模板进入 `pending` 后缺少扫描完成链 | 隔离上传 + scanner worker + 状态回调/轮询;只有 `ready` 可发布 |
|
||||
| SET-104 | UI 宣称符合 21 CFR Part 11,但未实现电子签名控制 | 删除不实文案;如需合规,另立 e-sign scope(再认证、签署含义、签名绑定、审计、防篡改) |
|
||||
| WF-101 | 所有阶段实例 `position=0` | 从定义快照持久化真实 position;增加唯一性与连续性校验 |
|
||||
| WF-102 | 激活 token 明文保存且消费、激活非同一事务 | 仅存 token hash;`SELECT FOR UPDATE` 后在同一事务验证、消费和激活 |
|
||||
| WF-103 | 推进会把全部启用任务强制标成 approved | 推进只允许已满足门禁的状态,不修正业务状态;不一致即事务失败 |
|
||||
| WF-104 | stale 未纳入阶段门禁 | required upstream/downstream lineage 有 stale 时禁止推进,重新批准后清除 stale 并留痕 |
|
||||
| WF-105 | 完成后缺少“选择下一工作流”与受控终止/变更 API | 实现 `completed/termination_requested/terminated` 全状态机及下一实例创建 |
|
||||
| WF-106 | bootstrap 发现已有 published 版本就退出 | 种子升级采用显式版本 manifest;内容 hash 变化创建 v2 draft,经校验批准后发布 |
|
||||
|
||||
### 4.3 P2:可在首发后持续增强
|
||||
|
||||
- 管理员 break-glass:理由、近期认证、限时、醒目标识、禁止代签、完整审计。
|
||||
- MFA/WebAuthn、企业 SSO/SCIM、组织层级和角色层级。
|
||||
- 策略模拟器、权限差异比较、定期访问复核和孤儿权限报告。
|
||||
- 工作流可视化 DAG;首版仍建议坚持线性阶段,减少编排复杂度。
|
||||
- 审计日志防篡改、WORM/外部归档和监管报表。
|
||||
|
||||
## 5. 目标授权架构
|
||||
|
||||
### 5.1 五层判定模型
|
||||
|
||||
每个敏感动作统一调用一个服务端策略决策点(PDP),判定表达式为:
|
||||
|
||||
```text
|
||||
ALLOW = authenticated(principal)
|
||||
AND account.active
|
||||
AND session.active
|
||||
AND permission_allows(action, resource_type, scope)
|
||||
AND project_relationship_allows(principal, project)
|
||||
AND workflow_snapshot_policy_allows(principal, active_instance, stage)
|
||||
AND document_policy_allows(principal, doc_task, document)
|
||||
AND state_machine_allows(action, current_state)
|
||||
AND separation_of_duty_allows(principal, action)
|
||||
|
||||
unknown / missing policy / dependency error => DENY
|
||||
```
|
||||
|
||||
| 层 | 回答的问题 | 数据权威 |
|
||||
|---|---|---|
|
||||
| 认证 | 这个请求是谁,账号/会话是否有效 | `users`、`auth_sessions` |
|
||||
| 系统 RBAC | 是否具备创建、管理、发布、审计等平台动作 | role/permission/binding 表 |
|
||||
| 项目 ReBAC | 是否属于该项目,承担哪些项目业务角色 | `project_members` + `project_role_bindings` |
|
||||
| 工作流/阶段 ABAC | 当前实例、阶段、参与策略是否允许 | 冻结 `config_snapshot` + 实例状态 |
|
||||
| 文档职责/状态 | 是否为该文档的编制/审核/批准人,当前状态能否执行动作 | `document_duty_assignments` + DocGov |
|
||||
|
||||
### 5.2 角色分层
|
||||
|
||||
系统角色不再表达具体项目里的业务职责,项目角色也不再等同于某一份文档的三权。
|
||||
|
||||
| 范围 | 建议内置角色 | 用途 |
|
||||
|---|---|---|
|
||||
| 系统 | 超级管理员、安全管理员、用户管理员、工作流管理员、模板管理员、安全审计员、普通用户 | 平台配置和治理;业务项目数据不因管理员身份默认全开 |
|
||||
| 项目 | 项目创建人、项目经理、商务 BD、产品经理、系统/研发工程师、测试、法规、QA、观察者 | 阶段参与、项目资料范围和业务动作候选资格 |
|
||||
| 文档 | author、reviewer、approver | 绑定单个文档任务实例;必须是具体用户,默认互斥 |
|
||||
|
||||
一个用户可以在同一项目绑定多个业务角色;角色绑定和文档职责均必须有 `valid_from/valid_until/status/assigned_by/reason`。静态职责分离在配置时阻止冲突,动态职责分离在动作时阻止同一主体对同一版本自审自批。
|
||||
|
||||
### 5.3 权限目录
|
||||
|
||||
权限键统一采用 `resource.action`,旧键通过一版兼容映射迁移,之后删除。建议首发目录:
|
||||
|
||||
| 域 | 权限 |
|
||||
|---|---|
|
||||
| 系统 | `system.settings.view/manage`、`system.security.manage`、`system.audit.view/export` |
|
||||
| 用户 | `users.view/create/edit/disable/reset_password`、`users.sessions.revoke` |
|
||||
| 角色 | `roles.view/create/edit/retire/assign/review` |
|
||||
| 工作流 | `workflow_defs.view/create/edit_draft/publish/retire`、`workflow_defs.impact_view` |
|
||||
| 模板 | `templates.view/upload/download/publish/retire` |
|
||||
| 项目 | `projects.create/view/edit/archive`、`projects.members.view/manage` |
|
||||
| 项目流程 | `projects.workflow.view/configure/activate/terminate`、`projects.stage.advance` |
|
||||
| 参与 | `workflow.chat.view/send`、`workflow.task.run`、`workflow.progress.view` |
|
||||
| 任务运行 | `task_runs.view_own/view_project/cancel_own/cancel_any/resume` |
|
||||
| 文档 | `documents.view/edit/submit/review/approve/export`、`documents.visibility.manage` |
|
||||
| 通知 | `notifications.view/update`、`notification_policies.manage` |
|
||||
|
||||
### 5.4 服务端执行点
|
||||
|
||||
不要在每个 handler 手写角色判断。建立:
|
||||
|
||||
```go
|
||||
Decision Authorize(ctx, Principal, Action, ResourceRef, Attributes)
|
||||
|
||||
Decision {
|
||||
Allowed bool
|
||||
ReasonCode string
|
||||
PolicyVersion string
|
||||
Obligations []string // redact, require_recent_auth, audit_reason, etc.
|
||||
}
|
||||
```
|
||||
|
||||
- 路由中间件负责身份和粗粒度权限。
|
||||
- service 层在事务内重新验证对象关系和当前状态,防止 TOCTOU。
|
||||
- repository 查询默认带可见范围,不先查全量再在浏览器过滤。
|
||||
- SSE、附件下载、搜索、导出、RAG、Agent tools 使用同一个 `ResourceRef`/Decision。
|
||||
- 禁止把 `user_id`、`role`、`stage`、`work_dir` 或 duty 作为客户端可信授权输入。
|
||||
- 403/404 策略统一;审计记录 actor、resource、action、decision、reason、request_id、policy_version。
|
||||
|
||||
### 5.5 核心动作矩阵
|
||||
|
||||
| 动作 | 普通成员 | 项目业务角色 | 项目创建人 | 系统管理角色 | 文档三权 |
|
||||
|---|---|---|---|---|---|
|
||||
| 创建项目 | 需 `projects.create` | 同左 | 同左 | 不默认拥有,按绑定 | 无关 |
|
||||
| 查看项目 | active membership | active membership | 是 | 仅 break-glass 或显式审计权限 | 无关 |
|
||||
| 管理成员 | 否 | 项目经理可选 | 是 | break-glass | 无关 |
|
||||
| 配置待激活流程 | 否 | 可提议 | 是 | 工作流管理员不能代替业务确认 | 无关 |
|
||||
| 激活/终止流程 | 否 | 可申请 | 是 + 再确认 | 只可 break-glass | 无关 |
|
||||
| 运行任务 | 否 | 阶段策略允许 + 对应 task permission | 同策略,不绕过 | 不默认 | author 或显式执行人 |
|
||||
| 查看文档 | 文档策略允许 | 阶段/角色策略允许 | 仍受私密/合规策略 | 不默认 | 当前职责人允许 |
|
||||
| 提交审核 | 否 | 否 | 不默认 | 不默认 | author |
|
||||
| 审核 | 否 | 否 | 不默认 | 不默认 | reviewer 且非 author |
|
||||
| 批准 | 否 | 否 | 不默认 | 不默认 | approver 且非 author/reviewer |
|
||||
| 推进阶段 | 否 | 只能申请/接收提醒 | 明确确认 | 不替代业务确认 | 无关 |
|
||||
| 发布工作流版本 | 否 | 否 | 无关 | 工作流发布权限 + 双人复核可选 | 无关 |
|
||||
|
||||
## 6. 设置体系完整方案
|
||||
|
||||
### 6.1 用户设置 `/settings`
|
||||
|
||||
| 页面 | 服务端能力 | 验收 |
|
||||
|---|---|---|
|
||||
| 个人资料 | `GET/PATCH /api/v1/me/profile`;姓名、邮箱、语言、时区;部门/工号受控只读 | 刷新、换设备仍一致;审计敏感字段变更 |
|
||||
| 安全 | 修改密码、MFA 状态、活动会话、撤销其他会话、最近登录 | 修改密码撤销其他会话;撤销后下一请求 401 |
|
||||
| 通知 | 站内/邮件渠道、事件类型、免打扰、升级策略 | Outbox 读取服务端偏好;关键审批提醒不可被完全关闭 |
|
||||
| 偏好 | 主题、默认导出、语言、默认项目页、Agent 显示偏好 | 落库并有 schema 版本;不再只存在组件 state |
|
||||
| 我的权限 | 服务端返回生效角色、作用域、有效期和权限来源 | 不由前端本地 role 推导;支持“为何有/无此权限” |
|
||||
|
||||
安全会话改造:登录响应通过 `Set-Cookie: __Host-agent_session=...; Secure; HttpOnly; SameSite=Lax|Strict; Path=/` 建立会话;状态变更使用 CSRF token/origin 验证;logout 调服务端撤销当前会话。测试环境可通过独立 fixture 获取 Cookie,不在产品包保留任意身份切换。
|
||||
|
||||
### 6.2 项目设置 `/projects/{id}/settings`
|
||||
|
||||
| 页面 | planning | active/awaiting | completed/terminated |
|
||||
|---|---|---|---|
|
||||
| 基本信息 | 创建人编辑 | 受控字段变更单 | 只读/归档 |
|
||||
| 成员与业务角色 | 增删改,校验职责候选 | 变更需影响分析;不能留下无人职责 | 历史只读,可为下个实例配置 |
|
||||
| 工作流选择 | 选已发布版本 | 冻结只读 | 可创建下一个 planning 实例 |
|
||||
| 阶段/任务 | 配置 optional/default,required 不可关闭 | 冻结;仅受控变更 | 快照只读 |
|
||||
| 模板版本 | 从 ready 版本选择 | 冻结 | 快照只读 |
|
||||
| 三权职责 | 必填、互斥、成员/资格校验 | 变更单 + 未决审批处理 | 历史只读 |
|
||||
| 参与/可见策略 | 从版本默认值继承,可按允许范围收紧 | 冻结;紧急收紧可走安全变更 | 历史只读 |
|
||||
| 预览与激活 | diff + 门禁 + 二次确认 | 不显示“重新激活” | 显示下一流程入口 |
|
||||
| 推进/终止 | 无 | 门禁满足后创建人确认;终止需原因/影响 | 展示完整审计 |
|
||||
|
||||
项目创建人不是系统超级管理员。项目设置的“独占确认权”和系统权限的“是否允许操作接口”同时成立:例如可由项目经理编辑草案,但最终激活和阶段推进仍由创建人确认。
|
||||
|
||||
### 6.3 系统管理中心 `/admin/*`
|
||||
|
||||
| 页面 | 必做功能 |
|
||||
|---|---|
|
||||
| 概览 | 服务/DB/Runner/Outbox/worker 健康、失败任务、待审批、策略版本 |
|
||||
| 用户 | 创建、审批、启停、资料、重置密码、撤销会话、多角色绑定、批量导入 |
|
||||
| 角色权限 | 权限目录、多角色、作用域、有效期、职责分离、影响预览、角色退役 |
|
||||
| 工作流设计器 | 创建/复制草稿、阶段排序、任务、执行器、模板、输入输出、门禁、职责候选、参与/可见策略、校验、diff、发布、退役 |
|
||||
| 模板库 | 隔离上传、扫描、预览、变量 schema、版本、发布/退役、引用关系 |
|
||||
| 项目类型与合规 | `product_domain` 与 `compliance_profile` 分离;可用流程、必需文档和签署强度 |
|
||||
| 通知自动化 | 事件、渠道、模板、频率、升级和去重 |
|
||||
| 审计 | 按 actor/action/resource/result/request_id 查询和导出;高风险变更对比 |
|
||||
| 安全 | 注册、审批、密码、MFA、会话时限、CSRF/CORS、上传限制、保留期、break-glass |
|
||||
|
||||
管理端不能继续依赖硬编码权限清单。`GET /api/v1/admin/permissions` 返回目录和风险等级;每个页面使用服务端 capabilities 控制入口,但最终仍由 API 决策。
|
||||
|
||||
## 7. 工作流定义 Schema v2
|
||||
|
||||
现有 schema 只有阶段、位置、人工门禁和文档任务基本字段,无法表达运行绑定、参与策略、职责资格、输入输出和确定性质量门禁。建议新增 `schema_version: 2`:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": 2,
|
||||
"workflow_key": "product_manager",
|
||||
"product_domains": ["medical_device", "non_medical_software"],
|
||||
"required_upstream": [],
|
||||
"participation_policy": {},
|
||||
"completion_policy": {},
|
||||
"stages": [{
|
||||
"key": "requirements_baseline",
|
||||
"name": "系统需求基线",
|
||||
"position": 10,
|
||||
"optional": false,
|
||||
"entry_gate": {},
|
||||
"exit_gate": {},
|
||||
"participation_policy": {},
|
||||
"doc_tasks": [{
|
||||
"key": "system_reqs",
|
||||
"executor_key": "squad.system_reqs.v1",
|
||||
"required": true,
|
||||
"blocking": true,
|
||||
"template": {"asset_key": "system_reqs", "version": 2},
|
||||
"input_contract": {},
|
||||
"output_contract": {},
|
||||
"quality_gate_key": "quality.system_reqs.v2",
|
||||
"eligible_project_roles": {},
|
||||
"visibility_policy": {},
|
||||
"retry_policy": {},
|
||||
"timeout_seconds": 3600
|
||||
}]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
发布校验必须至少验证:
|
||||
|
||||
- key 格式和全局唯一;stage position 唯一且严格递增;必需阶段/任务不可缺失;
|
||||
- `executor_key` 已注册且声明支持相应输入/输出;不再把未知任务落入 generic runner;
|
||||
- template version 存在且 `scan_status=ready`,变量 schema 与 input contract 一致;
|
||||
- 三权候选角色存在,且不会造成项目无人可配;author/reviewer/approver 默认互斥;
|
||||
- 上游工作流和文档依赖无环、能解析到已发布版本;
|
||||
- 每个 required/blocking task 有确定性质量门禁;
|
||||
- 可见/参与策略有明确默认值,未知即拒绝;
|
||||
- 发布后 definition JSON/hash 和所有引用版本不可变;编辑从已发布版本复制新 draft。
|
||||
|
||||
## 8. 三个工作流的正式定义
|
||||
|
||||
### 8.1 兼容性决定
|
||||
|
||||
当前项目和代码广泛使用 `main` 代表商务主线。首轮迁移**保留稳定 key `main`**,显示名统一为“商务对接”,避免破坏存量项目、任务记录和文档 ID;停止在新代码里把它解释成“任意默认流程”。`product_manager` 和 `test_manager` 保持现有 key。若未来希望改为 `business_engagement`,新增显式 alias 表,不直接改历史 key。
|
||||
|
||||
三个正式版本均以 v2 draft 创建和发布;不得修改已有 published v1,也不得依赖当前 `UpsertPublishedSeed` 自动覆盖。已 active 的 v1 项目继续使用原快照;planning 项目由创建人查看 diff 后主动升级。
|
||||
|
||||
### 8.2 商务对接 `main` v2
|
||||
|
||||
当前真实执行器已有以下阶段和任务,本方案将其搬入版本定义,执行器只保留能力注册,不再保留另一套阶段事实源。[^13]
|
||||
|
||||
| 顺序 | 阶段 | 文档任务 | 必需/阻断 | 建议三权候选 | 退出门禁 |
|
||||
|---:|---|---|---|---|---|
|
||||
| 10 | `V0.1_triage` 闪电摸底与盲区探测 | `intake` 客户需求采集/初始需求表 | 是/是 | author: BD/PM;reviewer: 项目经理;approver: 创建人或商务负责人 | intake approved;关键项无缺失;无运行任务 |
|
||||
| 20 | `V0.5_feasibility` 方案成型与法规对齐 | `research` 竞品调研;`feasibility_reg` 法规可行性;`prelim_design` 初步设计 | 全部是/是 | 按文档分别指派 BD、法规、研发;审核/批准分离 | 三文档 approved;无 stale/open change;entry inputs 已基线化 |
|
||||
| 30 | `V1.0_quoting` 工程拆解与商业锁定 | `cdo_quote` CDO 报价与核算 | 是/是 | author: 商务/项目经理;reviewer: 技术/财务;approver: 创建人/授权商务负责人 | 正文和核算 XLSX hash 一致、approved;报价关键字段完整 |
|
||||
|
||||
参与策略默认值:
|
||||
|
||||
- BD 可参与 V0.1/V0.5 的 `intake/research`,不因“是项目成员”自动获得 `prelim_design` 或报价批准权。
|
||||
- 法规只访问被授权的法规任务及其显式上游;研发只访问初步设计及显式上游。
|
||||
- 创建人可看项目进度并确认推进,但不会自动获得某份文档的审核/批准动作。
|
||||
- 阶段完成只产生 `ready_to_advance` 通知;创建人确认后原子进入下一阶段。
|
||||
|
||||
### 8.3 智能产品经理 `product_manager` v2
|
||||
|
||||
项目层保持一个受控阶段,阶段内的五个 Agent step 是 executor 内部步骤,不把内部 agent step 误建成五个需要人工推进的项目阶段。现有代码已经定义需求梳理、系统工程、法规、成文、终审五角色和五步执行链,可直接注册为 `squad.system_reqs.v1`。[^20]
|
||||
|
||||
| 项 | 正式配置 |
|
||||
|---|---|
|
||||
| 阶段 | `requirements_baseline` 系统需求基线,position=10,required/blocking |
|
||||
| 文档任务 | `system_reqs`,输出受控《系统需求规格书》 |
|
||||
| 执行器 | `squad.system_reqs.v1` |
|
||||
| 模板 | `system_reqs` ready version;发布时固定版本 |
|
||||
| 必需输入 | 项目五要素;已批准/显式基线化的客户需求或上游商务文档;项目材料清单 |
|
||||
| 结构化输出 | `output.md`、`artifacts/requirements.json`、manifest/hash、质量报告 |
|
||||
| 三权候选 | author: PM/系统工程;reviewer: 技术负责人/法规;approver: 创建人授权的批准人/QA |
|
||||
| 质量门禁 v2 | 每条需求唯一 ID;来源、理由、优先级、可验证准则、验证方法齐全;无未替换占位;JSON 与正文一致;重复/冲突/孤儿需求为 0 |
|
||||
| 完成门禁 | executor 成功 + deterministic gate 通过 + 文档 approved + 无 stale/open change/running task |
|
||||
|
||||
当前质量门禁只检查正文中是否出现 `REQ-` 和宽泛的“测试/分析/审查”等词,达不到“需求集合完整、唯一、可追溯、可测”的正式门禁。v2 必须解析 `requirements.json`,以结构化集合为准,并把校验报告与文档版本绑定。[^21]
|
||||
|
||||
### 8.4 智能测试经理 `test_manager` v2
|
||||
|
||||
| 项 | 正式配置 |
|
||||
|---|---|
|
||||
| 阶段 | `system_verification_planning` 系统验证策划,position=10,required/blocking |
|
||||
| 文档任务 | `test_manager`,输出受控《系统验证方案及计划》 |
|
||||
| 执行器 | `squad.test_manager.v1` |
|
||||
| 上游条件 | 同项目最近一次已批准且非 stale 的 `system_reqs`;记录上游 doc/version/hash |
|
||||
| 模板 | `test_manager` ready version;发布时固定版本 |
|
||||
| 结构化输出 | `output.md`、必需的 `artifacts/test_cases.json`、coverage report、manifest/hash |
|
||||
| 三权候选 | author: 测试;reviewer: 系统/法规;approver: 测试负责人/QA,三者互斥 |
|
||||
| 质量门禁 v2 | 上游需求全集解析成功;每条 requirement 至少一条有效 case;case ID 唯一;步骤、预期、判据、环境、方法完整;覆盖率 100%;无孤儿引用 |
|
||||
| stale 策略 | 上游 SR hash 变化立即将下游标为 stale,禁止提交/批准/阶段完成,完成影响分析与重新基线后解除 |
|
||||
|
||||
现有 executor 已要求上游 SR approved 并建立血缘,也定义了 100% 覆盖的 Agent 目标;但当前确定性门禁只检查 `TC-/TEST-`、`REQ-` 字符串,并且 `test_cases.json` 仅在文件存在时校验 JSON,文件不存在不会失败。v2 必须把结构化用例文件和覆盖率报告设为必需产物。[^21][^22]
|
||||
|
||||
### 8.5 三个工作流的串联语义
|
||||
|
||||
系统当前设计是“一项目最多一个 live 工作流”,不是三条流程同时 active:
|
||||
|
||||
```text
|
||||
商务对接 completed/受控 terminated
|
||||
-> 创建人选择并配置 product_manager v2
|
||||
-> 产品经理流程 completed,系统需求 approved
|
||||
-> 创建人选择并配置 test_manager v2
|
||||
-> 测试经理流程完成
|
||||
```
|
||||
|
||||
系统可以在前一流程门禁满足时推荐下一个流程并通知创建人,但绝不自动激活。上游依赖解析按文档类型 + workflow instance + approved version 查询,不依赖固定文件路径或仅由字符串拼出的 doc ID。
|
||||
|
||||
## 9. 配置到运行时的唯一权威链
|
||||
|
||||
必须建立以下单向链,禁止旁路:
|
||||
|
||||
```text
|
||||
published workflow version + ready template versions
|
||||
↓ creator configures / preview / confirms
|
||||
immutable project workflow snapshot
|
||||
↓ creates ordered stage/task instances + duty assignments
|
||||
active stage + authorized doc task instance
|
||||
↓ resolves executor, template, inputs, actor obligations
|
||||
task run + DocGov document version + lineage + audit
|
||||
↓ deterministic gate + three-duty approval + no stale/open work
|
||||
ready_to_advance notification
|
||||
↓ creator explicit confirmation
|
||||
next stage OR workflow completed
|
||||
```
|
||||
|
||||
具体约束:
|
||||
|
||||
1. `POST task-runs` 接收 `doc_task_instance_id` 和业务输入,不接收可信 `user_id/role/stage/work_dir/reviewer_id/approver_id`。
|
||||
2. 服务端锁定实例和 task instance,验证 active stage、actor、executor、模板和当前状态。
|
||||
3. WorkDir 由服务端按 project/instance/task_run 生成并做路径约束。
|
||||
4. DocGov 从 duty assignment 创建/校验文档责任人,stage 来自 stage instance。
|
||||
5. 任务结果写入与运行终态、文档版本、manifest、lineage、outbox 使用事务/可恢复 saga,避免“显示完成但产物未落稳”。
|
||||
6. 列表、详情、导出、附件、搜索、SSE、RAG 和 Agent tool read 都使用同一资源授权上下文。
|
||||
|
||||
## 10. 数据库迁移方案
|
||||
|
||||
迁移号以合并时最新 Goose 版本为准,下表暂按 `00021+` 表示。
|
||||
|
||||
| 迁移 | 主要变更 | 兼容/回填 |
|
||||
|---|---|---|
|
||||
| 00021 IAM hardening | project_members.user_id FK;role/binding 状态、reason;审计 actor;权限键 alias | 校验孤儿成员后加 FK;旧 `users.role_id` 双读一版、停止写入 |
|
||||
| 00022 project roles | `project_roles`、`project_role_permissions`、`project_user_role_bindings` | owner/member/viewer 映射为 owner/contributor/observer;原表保留 membership 状态 |
|
||||
| 00023 settings | user preferences、notification preferences、security policy versions | 把可识别的 local preferences 一次性导入需用户确认;其余使用服务端默认 |
|
||||
| 00024 workflow schema v2 | executor registry/version、schema fields、policy JSON schema/version | 不修改 v1 JSON;validator 按 schema_version 路由 |
|
||||
| 00025 instance integrity | stage position、task executor/template/output snapshot、duty eligibility、change requests | 修正现有 position;对 active 数据先报告后修复,不静默重排 |
|
||||
| 00026 authorization audit | `authorization_audit_events` 或统一 audit_event 扩展、policy version、request ID | 明确保留期和敏感字段脱敏 |
|
||||
| 00027 workflow v2 manifests | 创建三个 v2 draft/版本 manifest | 只在 hash 匹配预期时创建;不覆盖用户自定义版本 |
|
||||
|
||||
数据库约束建议:
|
||||
|
||||
- live instance 部分唯一索引继续保留;增加 planning 与 live 状态转换约束测试。
|
||||
- `project_stage_instances(workflow_instance_id, position)` unique,position > 0。
|
||||
- task instance 保存 `executor_key/template_version/output_doc_type/quality_gate_key` 的冻结副本。
|
||||
- duty assignment 引用 active project membership;跨表动态条件用事务 trigger 或 service + deferred validation 实现。
|
||||
- activation token 只存 hash;高风险一次性 token 使用短 TTL、actor/project/plan hash 绑定。
|
||||
- published definition/template 通过数据库权限或 trigger 阻止 UPDATE/DELETE,不只依赖 Go service。
|
||||
|
||||
## 11. API 调整
|
||||
|
||||
### 11.1 身份与设置
|
||||
|
||||
```text
|
||||
POST /api/v1/auth/login -> Set-Cookie
|
||||
POST /api/v1/auth/logout -> revoke current session
|
||||
GET /api/v1/me
|
||||
PATCH /api/v1/me/profile
|
||||
GET/PUT /api/v1/me/preferences
|
||||
GET/PUT /api/v1/me/notification-preferences
|
||||
GET /api/v1/me/sessions
|
||||
DELETE /api/v1/me/sessions/{id}
|
||||
POST /api/v1/me/password/change
|
||||
```
|
||||
|
||||
### 11.2 权限与管理
|
||||
|
||||
```text
|
||||
GET /api/v1/admin/permissions
|
||||
GET/POST/PATCH /api/v1/admin/roles...
|
||||
GET/POST/DELETE /api/v1/admin/role-bindings...
|
||||
POST /api/v1/admin/authorization/simulate
|
||||
GET /api/v1/admin/audit-events
|
||||
POST /api/v1/admin/users/{id}/reset-password
|
||||
POST /api/v1/admin/users/{id}/sessions/revoke
|
||||
```
|
||||
|
||||
每个 admin endpoint 绑定独立 permission,不再通过 `requireSystemAdmin` 全包。
|
||||
|
||||
### 11.3 工作流与项目实例
|
||||
|
||||
```text
|
||||
POST /api/v1/admin/workflows/{id}/versions/{v}/copy-draft
|
||||
PATCH /api/v1/admin/workflows/{id}/versions/{v}
|
||||
POST /api/v1/admin/workflows/{id}/versions/{v}/validate
|
||||
GET /api/v1/admin/workflows/{id}/versions/{v}/impact
|
||||
POST /api/v1/admin/workflows/{id}/versions/{v}/publish
|
||||
POST /api/v1/admin/workflows/{id}/versions/{v}/retire
|
||||
|
||||
GET/PUT /api/v1/projects/{id}/workflow-plan
|
||||
POST /api/v1/projects/{id}/workflow-plan/preview
|
||||
POST /api/v1/projects/{id}/workflow-plan/activate
|
||||
POST /api/v1/projects/{id}/workflow-instances/{iid}/termination-requests
|
||||
POST /api/v1/projects/{id}/workflow-instances/{iid}/terminate
|
||||
POST /api/v1/projects/{id}/workflow-instances/{iid}/change-requests
|
||||
POST /api/v1/projects/{id}/workflow-instances/{iid}/stages/{stage}/advance
|
||||
POST /api/v1/projects/{id}/doc-tasks/{taskInstanceId}/runs
|
||||
```
|
||||
|
||||
所有资源路径先验证 path 中 project/instance/stage/task/document 的归属一致性,避免用合法项目权限访问另一个项目的子资源。
|
||||
|
||||
## 12. 前端实施方案
|
||||
|
||||
1. **认证壳**:不从 `localStorage` 恢复 principal/token;启动时只调用 `/me`。401 清空全部敏感状态并跳转登录。
|
||||
2. **权限 Provider**:从 `/me` 获取 capabilities + scoped grants;按钮、菜单和路由只做 UX 控制,错误统一展示服务端 reason code。
|
||||
3. **用户设置**:现有 modal 拆到真实 API;接入活动会话;资料/偏好保存失败不更新本地成功态。
|
||||
4. **系统管理中心**:从单一大 modal 演进为路由页面;权限矩阵来自 catalog;高风险变更提供 diff、影响人数和二次确认。
|
||||
5. **工作流设计器**:线性阶段排序、每阶段多任务、executor 只从注册表下拉、模板版本选择、职责候选、参与/可见策略、JSON 高级视图、发布校验报告。
|
||||
6. **项目设置**:明确 planning/live/history 三态;live 快照只读;门禁列表展示每个阻断项;下一工作流必须由创建人确认。
|
||||
7. **工作台**:根据服务端返回的 allowed actions 渲染,不在前端用姓名/本地角色重新计算业务授权。
|
||||
8. **删除演练入口**:`UserProjectRightsModal` 的测试角色切换、旧 `SettingsModal`、本地模拟分支和生产 bundle 中的测试身份文案移出产品代码。
|
||||
|
||||
## 13. 分阶段交付计划
|
||||
|
||||
估时为单个熟悉代码库的小组工作日,安全修复与工作流建模可并行开发,但发布必须按闸门顺序。
|
||||
|
||||
### Phase 0:基线冻结与权限清单(1–2 天)
|
||||
|
||||
- 固定 commit、DB schema、环境和三个 workflow v1 hash。
|
||||
- 自动导出全部 `/api/v1` 路由,建立 resource/action/owner/negative test 矩阵。
|
||||
- 修正当前 E2E 报告状态矛盾;归档一次干净的 short test 和 build 结果。
|
||||
- 输出:`authorization-matrix-v2.md`、migration preflight SQL、测试数据拓扑。
|
||||
|
||||
门禁:每个非公开路由都有责任 owner、策略和至少一个未授权负例;未知路由默认为拒绝。
|
||||
|
||||
### Phase 1:P0 授权止血(3–5 天)
|
||||
|
||||
- 修复 AUTH-001–009、WF-001/002 的越权入口。
|
||||
- 建立统一 `Authorize`/ResourceRef 和 server-side allowed actions。
|
||||
- 删除固定管理员/演示项目 ID 豁免;生产禁用 permissive fallback。
|
||||
- Cookie/CSRF/logout/401 前端失效闭环。
|
||||
|
||||
门禁:匿名、跨用户、跨项目、跨阶段、错 task、错 child resource、DB authz fault 全部负例通过;SSE/RAG/Agent tool 同样验证。
|
||||
|
||||
### Phase 2:IAM 与设置权威化(4–6 天)
|
||||
|
||||
- 完成 IAM-101–105 和用户/项目/系统设置 API。
|
||||
- 角色多绑定、作用域/有效期、permission catalog、原子用户变更和审计。
|
||||
- 用户资料、偏好、通知、活动会话 UI;管理中心权限拆分。
|
||||
|
||||
门禁:重启/换浏览器数据一致;权限收回和账号停用下一请求生效;至少两名管理员防锁死演练通过。
|
||||
|
||||
### Phase 3:工作流 Schema v2 与运行时合流(5–8 天)
|
||||
|
||||
- 实现 schema v2、executor/quality gate registry、完整 validator。
|
||||
- 移除 `flattenVersion` 作为执行路径;编排器只读实例快照。
|
||||
- 修复 position、token 原子性、DocGov duty/stage 绑定、stale 门禁。
|
||||
- 完成受控终止、变更单和下一个工作流生命周期。
|
||||
|
||||
门禁:修改全局 published/latest 不影响 active 实例;请求伪造 stage/task/duty 无效;故障恢复后实例位置和职责不漂移。
|
||||
|
||||
### Phase 4:发布三个 v2 工作流(4–6 天)
|
||||
|
||||
- 按 §8 创建 `main`、`product_manager`、`test_manager` v2 draft。
|
||||
- 绑定 ready 模板和 executor;补齐结构化门禁。
|
||||
- 对 planning v1 项目生成可读 diff,由创建人选择是否升级;active v1 不迁移。
|
||||
- 完成三个流程的串联推荐,但保持人工选择/激活。
|
||||
|
||||
门禁:三个版本通过静态校验、dry-run、单流程 PG E2E 和串联 PG E2E。
|
||||
|
||||
### Phase 5:管理端/项目端完整体验(4–6 天)
|
||||
|
||||
- 工作流设计器、模板库、项目规划、门禁详情、影响预览、下一流程、终止/变更 UI。
|
||||
- 删除旧本地/演示权威路径和不实合规文案。
|
||||
- 可访问性、错误恢复、并发 diff/reconfirm。
|
||||
|
||||
门禁:产品经理无需改代码即可复制 v2 为 v3 草案、换模板/职责候选、校验并由有权者发布;普通管理员无法越权发布。
|
||||
|
||||
### Phase 6:发布验证与灰度(5–8 天)
|
||||
|
||||
- 全量 Go/前端、race、PG、迁移升级/回滚、重启、worker 故障注入。
|
||||
- 真实 PI Agent 三工作流 E2E;长任务超时/恢复/取消;跨用户负例。
|
||||
- 备份恢复、日志脱敏、监控告警、容量和 bundle 分包。
|
||||
- 灰度一个内部项目,再扩到新项目;旧项目只读兼容指标归零后删除 fallback。
|
||||
|
||||
门禁:§14 全部完成;P0/P1 为 0;可恢复演练和回滚演练均有报告。
|
||||
|
||||
总体建议:**21–35 个小组工作日**。如多人并行,最短日历时间约 4–5 周;不应通过跳过负例、迁移和真实 Runner 验证压缩关键路径。
|
||||
|
||||
## 14. 测试与验收矩阵
|
||||
|
||||
### 14.1 授权负例
|
||||
|
||||
| 场景 | 预期 |
|
||||
|---|---|
|
||||
| 未登录访问任意非公开 API/SSE/附件 | 401,不泄漏资源存在性 |
|
||||
| A 项目成员读 B 项目、run history、lineage、搜索、导出 | 403/404,审计 deny |
|
||||
| 当前阶段 BD 请求研发 task key | 403;不创建 task_run/workdir/doc |
|
||||
| 非职责人提交/审核/批准 | 403;状态、版本、审计不变 |
|
||||
| author 尝试审核或批准同一版本 | 409/403 SoD violation |
|
||||
| authz DB/策略加载故障 | 敏感路径拒绝,健康状态 degraded,触发告警 |
|
||||
| 权限撤销后复用旧页面/旧 SSE/旧 Cookie | 下一次鉴权失败;流关闭或重新鉴权 |
|
||||
| 猜测 task/document/template/blob ID | 不能跨项目读取 |
|
||||
| 客户端伪造 user/role/stage/workdir/duty | 服务端忽略或 400;不得改变判定 |
|
||||
|
||||
### 14.2 工作流配置与冻结
|
||||
|
||||
- v2 required stage/task 被遗漏、禁用、重复或错序时校验失败。
|
||||
- executor 未注册、模板非 ready、变量 schema 不匹配时禁止发布。
|
||||
- published version UPDATE/DELETE 在 service 和 DB 层均失败。
|
||||
- 激活 token 重放、过期、跨 actor、跨 project、plan hash 不同均失败。
|
||||
- 并发保存/激活/推进只成功一个;另一方收到 diff/reconfirm,不自动重试。
|
||||
- 修改 v3 不影响使用 v2 的 active 项目;历史 hash 可复算。
|
||||
- 流程未完成/未终止时不能创建第二个 live;完成后可配置下一个 planning。
|
||||
|
||||
### 14.3 三工作流 E2E
|
||||
|
||||
**商务对接:** 按 V0.1 → V0.5 三任务 → V1.0 运行;每阶段文档分别走三权;未全部 approved 不产生 ready;满足后产生一次去重提醒;只有创建人确认推进。
|
||||
|
||||
**智能产品经理:** 从批准的输入基线生成 `requirements.json` 和正文;随机抽取、重复 ID、缺验证准则、正文/JSON 不一致均被确定性门禁拒绝;批准后可作为下游输入。
|
||||
|
||||
**智能测试经理:** 没有 approved SR、SR stale、hash 不匹配时拒绝启动;生成必需 `test_cases.json`;需求全集覆盖率必须 100%;上游更新后下游立即 stale 且不能完成。
|
||||
|
||||
**串联:** `main` 完成后只推荐 PM;创建人配置并激活;PM 完成后只推荐 Test;每个实例版本、模板、职责、输入 hash、输出 hash 和审计链可追溯。
|
||||
|
||||
### 14.4 运行与灾难恢复
|
||||
|
||||
- 应用、worker、PostgreSQL、PI Runner 分别重启,验证会话/任务/实例/Outbox 恢复。
|
||||
- PI Runner 超时后 task 可恢复或明确失败,不重复生成审批版本。
|
||||
- Outbox 重投不重复发阶段提醒;消费者幂等。
|
||||
- 迁移从 v20 的生产快照升级;备份恢复后 hash/权限/实例一致。
|
||||
- `go test -race`、前端测试、生产 build、依赖/镜像扫描、长期 soak。
|
||||
|
||||
## 15. 发布完成定义(Definition of Done)
|
||||
|
||||
只有同时满足以下条件,才能宣布“权限、设置和三个工作流已按当前设计做全”:
|
||||
|
||||
- [ ] 生产产品不存在任意身份切换、本地认证 fallback 或客户端身份权威。
|
||||
- [ ] 每个 API/SSE/RAG/Agent tool/附件通路都有服务端授权和跨用户负例。
|
||||
- [ ] 授权失败或依赖异常默认拒绝;不存在固定用户 ID、项目 ID 特权。
|
||||
- [ ] 系统角色、项目业务角色、文档三权分离且可审计;三权职责分离生效。
|
||||
- [ ] 用户、项目、系统三类设置均由服务端持久化,刷新/重启/换端一致。
|
||||
- [ ] 工作流、模板、权限管理使用各自细粒度 permission,而不是全员超级管理员。
|
||||
- [ ] 已发布工作流/模板不可变;项目激活冻结版本、模板、阶段、任务、策略和职责。
|
||||
- [ ] 同一项目最多一个 live;完成/受控终止后由创建人选择下一个。
|
||||
- [ ] 门禁满足只通知,不自动推进;创建人确认与推进在事务中完成。
|
||||
- [ ] `main` v2 完整执行 V0.1/V0.5/V1.0,不再由硬编码目录另行决定。
|
||||
- [ ] `product_manager` v2 结构化需求门禁通过;`test_manager` v2 实现 100% 需求覆盖和 stale 阻断。
|
||||
- [ ] DocGov 的 stage 和三权全部来自冻结实例,客户端不能覆盖。
|
||||
- [ ] PG、真实 PI Agent、重启恢复、故障注入、跨项目/跨阶段负例均有可复现报告。
|
||||
- [ ] P0/P1 缺陷归零,灰度/回滚/监控/告警和审计查询可用。
|
||||
|
||||
## 16. 风险与控制
|
||||
|
||||
| 风险 | 概率/影响 | 控制 |
|
||||
|---|---|---|
|
||||
| v1/v2 双执行权威并存 | 高/高 | feature flag 只选一个 orchestrator;记录每次 run 的 schema/executor/version;不静默 fallback |
|
||||
| 存量项目职责/成员数据不完整 | 高/中 | preflight 报告;active 不强迁;planning 由创建人补全并确认 |
|
||||
| 权限收紧影响现有演示项目 | 高/中 | 显式 legacy visibility 数据迁移;不保留 ID 豁免;灰度观察 deny 指标 |
|
||||
| Cookie 改造引入 CSRF | 中/高 | SameSite + CSRF token + Origin/Referer 校验;状态变更不用 GET |
|
||||
| 长 Agent 运行与 HTTP 超时 | 高/高 | 异步 task + lease/heartbeat + resumable worker;客户端订阅状态,不持有超长请求 |
|
||||
| 结构化质量门禁误报 | 中/中 | schema version、明确错误定位、golden corpus、允许修复重跑但不可人工静默跳过 |
|
||||
| 角色配置锁死管理员 | 中/高 | 双管理员、关键权限不可清空、变更影响预览、break-glass 离线流程 |
|
||||
| 模板恶意文件/解析炸弹 | 中/高 | 隔离、扩展/MIME/签名、大小/解压限制、扫描、Web root 外 CAS;仅 ready 可引用 |
|
||||
|
||||
## 17. 建议的首个迭代任务包
|
||||
|
||||
第一周不要先画完整工作流设计器,先完成以下可独立验收的任务:
|
||||
|
||||
1. `AUTH-001`:给 run history/lineage 及所有项目子资源补统一对象授权和双用户 PG 负例。
|
||||
2. `AUTH-002`:阶段访问错误全部 fail closed,加入数据库故障注入测试。
|
||||
3. `AUTH-003`:workflow run/task run 改从 task instance 推导 task/stage/executor,客户端覆盖返回 400。
|
||||
4. `AUTH-004/005`:补必需项反向校验和 duty member/status/role eligibility 校验。
|
||||
5. `AUTH-006/007`:删除 ID 特判,项目列表改用 `ListVisibleProjectIDs`/membership join,创建项目校验 permission。
|
||||
6. `AUTH-009`:服务端 logout + `/me` 失效清理;设计 Cookie/CSRF 兼容迁移。
|
||||
7. `WF-001/002`:提交 schema v2 ADR 和 runtime authority contract,阻止新增旁路。
|
||||
|
||||
首周验收物应是:代码、迁移 preflight、授权矩阵、负例测试、更新后的安全报告。只有该闸门通过,才开始发布三个 v2 draft。
|
||||
|
||||
## 18. 交付物清单
|
||||
|
||||
- 本实施方案。
|
||||
- API 授权矩阵 v2(路由、动作、资源、策略、负例、owner)。
|
||||
- Schema v2 JSON Schema + executor/quality gate registry ADR。
|
||||
- Goose 00021+ 迁移和 preflight/rollback SQL。
|
||||
- 三个工作流 v2 manifest、模板版本清单和 golden fixtures。
|
||||
- 用户/项目/系统设置产品规格与 API contract。
|
||||
- 授权负例、PG、真实 PI Agent、迁移、恢复、soak 测试报告。
|
||||
- 灰度清单、监控面板、告警规则、回滚 runbook。
|
||||
|
||||
## 资料来源
|
||||
|
||||
[^1]: 当前治理原则与目标模型见 [2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md)。
|
||||
[^2]: IAM、工作流定义、项目实例、通知和任务持久化分别见 [00015 IAM](../deploy/postgres/goose/00015_2026-09-12-iam-core.sql)、[00016 workflow definitions](../deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql)、[00017 project instances](../deploy/postgres/goose/00017_2026-09-12-project-workflow-instances.sql)、[00018 outbox](../deploy/postgres/goose/00018_2026-09-12-outbox-notifications-stage-advance.sql)、[00019 task runs](../deploy/postgres/goose/00019_2026-09-12-task-runs-events.sql) 和 [00020 worker lease](../deploy/postgres/goose/00020_2026-09-12-task-run-worker-lease.sql)。
|
||||
[^3]: 本轮验证命令与结果记录在本方案 §2.2;当前历史测试状态见 [2026-09-12-pg-ci-soak-e2e-test-report.md](./test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md)。
|
||||
[^4]: 系统能力查询没有限定 binding scope/role status/valid_from,且 role-admin 字符串直接判 admin,见 [internal/authz/service.go](../internal/authz/service.go#L26-L99)。
|
||||
[^5]: 创建项目只验证身份,见 [project_handlers.go](../internal/server/project_handlers.go#L16-L46);运行历史和血缘查询未做项目访问判断,见同文件 [run history/lineage](../internal/server/project_handlers.go#L221-L274)。
|
||||
[^6]: 工作流管理统一走 `requireSystemAdmin`,没有使用已经入库的 `workflow_defs.*`,见 [admin_workflow_handlers.go](../internal/server/admin_workflow_handlers.go#L13-L23);权限种子见 [00016](../deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql#L67-L82)。
|
||||
[^7]: `ResolveStageAccess` 在 live 查询错误时返回 unrestricted,且一个阶段任一职责会放开该阶段全部任务,见 [stage_access.go](../internal/projectinstance/stage_access.go#L15-L68);服务器过滤辅助函数也在错误时放行,见 [stage_access_helpers.go](../internal/server/stage_access_helpers.go#L23-L47)。
|
||||
[^8]: 任务门禁在 actor 能访问 active stage 时放过不匹配 task,见 [bizdev_stage_gate.go](../internal/server/bizdev_stage_gate.go#L40-L54);workflow run 接收客户端 task override,见 [project_handlers.go](../internal/server/project_handlers.go#L205-L218)。
|
||||
[^9]: token/session 存 localStorage 且 logout 只删除本地键,见 [web/src/api/auth.ts](../web/src/api/auth.ts#L306-L330);恢复 session 后 `/me` 失败被吞掉,见 [web/src/App.tsx](../web/src/App.tsx#L690-L703)。
|
||||
[^10]: 用户设置把偏好描述为浏览器本地并从前端角色推导权限,见 [UserSettingsModal.tsx](../web/src/components/user/UserSettingsModal.tsx#L68-L77) 与 [同文件](../web/src/components/user/UserSettingsModal.tsx#L673-L779);后端已有活动会话 API,见 [auth_handlers.go](../internal/server/auth_handlers.go#L162-L204)。
|
||||
[^11]: 三个单阶段种子见 [workflowdef/bootstrap.go](../internal/workflowdef/bootstrap.go#L63-L74);seed 遇到已有发布版本直接退出,见 [workflowdef/store.go](../internal/workflowdef/store.go#L364-L372)。
|
||||
[^12]: DBCatalog 只取首阶段/首任务,见 [workflowdef/catalog.go](../internal/workflowdef/catalog.go#L50-L82);现有 schema 能表达的字段见 [workflowdef/types.go](../internal/workflowdef/types.go#L15-L43)。
|
||||
[^13]: 商务流程真实阶段和任务仍由 [internal/bizdev/service.go](../internal/bizdev/service.go#L202-L223) 硬编码。
|
||||
[^14]: 规划 validator 只遍历客户端提交项,没有反向验证必需定义项是否缺失,见 [projectinstance/validator.go](../internal/projectinstance/validator.go#L37-L105);三权只校验非空和互斥,见 [同文件](../internal/projectinstance/validator.go#L108-L144)。
|
||||
[^15]: 阶段实例 position 固定写 0,见 [projectinstance/store.go](../internal/projectinstance/store.go#L244-L249);执行器默认 reviewer=2、approver=3 并固定阶段,见 [bizdev/service.go](../internal/bizdev/service.go#L383-L418)。
|
||||
[^16]: 当前报告的真实 PI Agent E2E 记录 `/v1/run` 超时,同时结论仍称“进行中”,见 [2026-09-12-pg-ci-soak-e2e-test-report.md](./test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md)。
|
||||
[^17]: [OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html)。
|
||||
[^18]: [NIST Role Based Access Control](https://csrc.nist.gov/Projects/Role-Based-Access-Control) 与 [NIST SP 800-162 ABAC](https://csrc.nist.gov/pubs/sp/800/162/upd2/final)。
|
||||
[^19]: [OWASP Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)。
|
||||
[^20]: 产品经理和测试经理的 Agent 角色及职责见 [squad/workspace.go](../internal/squad/workspace.go#L648-L743),内部步骤见 [同文件](../internal/squad/workspace.go#L940-L1073)。
|
||||
[^21]: 当前产品/测试质量门禁见 [squad/quality_gate.go](../internal/squad/quality_gate.go#L108-L146)。
|
||||
[^22]: 测试经理对 approved SR 的前置校验和材料注入见 [bizdev/service.go](../internal/bizdev/service.go#L365-L381),stale 传播见 [projectworkflow/service.go](../internal/projectworkflow/service.go#L237-L265)。
|
||||
本文档已迁至 [remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md](remediation/2026-09-12-permissions-settings-three-workflows-implementation-plan.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,81 +1,3 @@
|
||||
# Phase 0 API 授权矩阵与术语冻结
|
||||
# 已迁移
|
||||
|
||||
> 依据:[2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) Phase 0
|
||||
> 状态:Phase 0 止血基线(非完整 RBAC 权威化)
|
||||
|
||||
## 一、术语冻结
|
||||
|
||||
| 术语 | 定义 | Phase 0 权威来源 |
|
||||
|---|---|---|
|
||||
| 系统角色 | 如 `role-admin`,决定系统级管理能力 | 服务端 `users.role_id`(内存/后续持久化) |
|
||||
| 项目成员角色 | `owner` / `member` / `viewer` | 数据库 `project_members` + `internal/authz` |
|
||||
| 文档职责 | 单文档 `author` / `reviewer` / `approver` | DocGov + 文档任务(Phase 1+ 解耦) |
|
||||
| 登录主体 | 当前会话用户 | **仅** Bearer / `X-Session-Token` → `principalFromContext` |
|
||||
| 前端权限 | `hasPermission` / `localStorage` roles | **非安全边界**,仅 UI 体验层 |
|
||||
|
||||
**Phase 0 红线:**
|
||||
|
||||
- 禁止新增依赖 `localStorage` 的权威业务状态。
|
||||
- 禁止产品 UI 身份模拟、`X-User-ID` 请求头、body `user_id` 覆盖 principal。
|
||||
- 对象级授权以服务端 middleware + 已挂载的 `requireProjectAccess` 为准。
|
||||
|
||||
## 二、公开路由(无需认证)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| GET | `/`, `/health`, `/api/v1/health` | SPA / 健康检查 |
|
||||
| POST | `/api/v1/auth/login` | 登录 |
|
||||
| POST | `/api/v1/auth/register` | 注册(若启用) |
|
||||
| * | 非 `/api/*` | 静态资源 / SPA fallback |
|
||||
|
||||
## 三、API 资源—动作—条件矩阵
|
||||
|
||||
图例:`authn`=需登录;`admin`=需 `role-admin`;`proj`=需 `requireProjectAccess`;`—`=未挂对象级授权(Phase 1 补齐)
|
||||
|
||||
| 路由 | authn | admin | proj | Phase 0 备注 |
|
||||
|---|---:|---:|---:|---|
|
||||
| POST `/api/v1/projects` | ✓ | — | — | 创建人来自 token |
|
||||
| GET `/api/v1/projects` | ✓ | — | — | 列表按 user_id 过滤 |
|
||||
| GET `/api/v1/projects/{id}` | ✓ | — | ✓ | |
|
||||
| GET `/api/v1/projects/{id}/workflows` | ✓ | — | ✓ | |
|
||||
| PUT `/api/v1/projects/{id}/active-workflow` | ✓ | — | ✓ | |
|
||||
| POST `/api/v1/projects/{id}/workflows/{key}/run` | ✓ | — | ✓ | |
|
||||
| GET `/api/v1/projects/{id}/workflows/{key}/runs` | ✓ | — | ✓ | |
|
||||
| GET `/api/v1/projects/{id}/lineage` | ✓ | — | ✓ | |
|
||||
| GET `/api/v1/projects/{id}/documents` | ✓ | — | ✓ | |
|
||||
| POST/GET `/api/v1/projects/{id}/assets` | ✓ | — | ✓ | |
|
||||
| GET `/api/v1/workflows` | ✓ | — | — | |
|
||||
| POST `/api/v1/chat` | ✓ | — | — | user_id 来自 principal |
|
||||
| POST/GET `/api/v1/chat/stream` | ✓ | — | — | SSE;principal 强制 |
|
||||
| GET `/api/v1/chat/turns/{id}` | ✓ | — | — | |
|
||||
| POST/GET `/api/v1/tasks/run/stream` | ✓ | — | — | |
|
||||
| POST `/api/v1/tasks/runs` 等 | ✓ | — | 部分 | task_run_auth |
|
||||
| POST `/api/v1/admin/workspaces/reconcile` | ✓ | ✓ | — | |
|
||||
| GET/PUT `/api/v1/context/user*` | ✓ | — | — | |
|
||||
| GET `/api/v1/context/project` | ✓ | — | — | |
|
||||
| GET/POST `/api/v1/chat/sessions` 等 | ✓ | — | — | 会话归属校验 |
|
||||
| GET/POST `/api/v1/freeform-documents*` | ✓ | — | — | owner 校验在 service |
|
||||
| GET/POST `/api/v1/docgov/*` | ✓ | — | — | DocGov 三权 |
|
||||
| POST `/api/v1/auth/logout` 等 | ✓ | — | — | |
|
||||
| GET/POST `/api/v1/admin/users` | ✓ | ✓ | — | |
|
||||
| GET/PUT `/api/v1/admin/config` | ✓ | ✓ | — | |
|
||||
|
||||
## 四、Phase 0 已知 P0-gap(→ Phase 1)
|
||||
|
||||
| 缺口 | 说明 |
|
||||
|---|---|
|
||||
| 无 DB 时 authz 降级 | `authorizer.enabled()==false` 时任意已登录用户可访问任意 project_id(仅 dev/stub) |
|
||||
| localStorage RBAC | 前端按钮可见性仍非服务端 capabilities |
|
||||
| 阶段/文档 ABAC | 未实施;BD 跨阶段隔离在 Phase 3 |
|
||||
|
||||
## 五、Phase 0 验收对照
|
||||
|
||||
| 门禁 | 验证方式 |
|
||||
|---|---|
|
||||
| 无身份切换 UI | `scripts/check-prod-bundle.sh` + 人工 |
|
||||
| 匿名 API 401 | `TestP0_AnonymousBusinessAPIReturns401` |
|
||||
| X-User-ID 无效 | `TestP0_XUserIDCannotAuthenticate` |
|
||||
| body user_id 不覆盖 principal | `TestP0_BodyUserIDCannotOverridePrincipal` |
|
||||
| 生产无种子用户 | `TestMemoryStore_MainEnvNoSeedUsers` |
|
||||
| main 禁止 AllowInMemory | `TestValidateProductionSecrets_RejectsAllowInMemory` |
|
||||
| CORS 无 `*` | `TestP0_CORSAllowlist` |
|
||||
本文档已迁至 [audit/2026-09-12-phase0-api-authz-matrix.md](audit/2026-09-12-phase0-api-authz-matrix.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,99 +1,3 @@
|
||||
# Phase 1:账户与授权权威化 Implementation Plan
|
||||
# 已迁移
|
||||
|
||||
> **依据**:[2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) §5.2、§4、§12、Phase 1
|
||||
> **前置**:Phase 0 已合并(5 commits on `dev`,`8341168`)
|
||||
|
||||
**Goal:** 登录、角色、权限、项目成员关系全部以数据库 + 服务端策略为唯一权威;前端只消费 `capabilities`;重启后会话/账户策略仍有效;禁用账户下一请求失效。
|
||||
|
||||
**Architecture:** Goose 迁移新增 IAM 表 → `PostgresAuthStore` 替换 `MemoryStore`(dev 可 feature flag 回退)→ `AuthorizationService` 统一 RBAC + `project_members` + admin 判定 → `/api/v1/auth/me` 返回 capabilities → 管理端用户/角色 API 持久化 → 前端移除 localStorage 权限权威。
|
||||
|
||||
**Tech Stack:** Goose、pgx、现有 `internal/auth`、`internal/authz`、React/Vite。
|
||||
|
||||
**明确不在本阶段:** 工作流版本模型、阶段 ABAC、capabilities 到每个 DocGov 动作的全覆盖(先系统 + 项目 + 已挂 authz 路由)。
|
||||
|
||||
---
|
||||
|
||||
## 完成门禁
|
||||
|
||||
| 门禁 | 判定 |
|
||||
|---|---|
|
||||
| 持久化账户 | 重启后 users/roles 仍在 DB |
|
||||
| 持久化会话 | token 存哈希;logout/禁用立即失效 |
|
||||
| 无 localStorage RBAC 权威 | `AdminSettingsModal` 读写 API;`hasPermission` 仅 UI 兜底并标注 deprecated |
|
||||
| 项目成员 CRUD | 创建者可增删改成员;API 测试 |
|
||||
| 负例 | 禁用用户 token → 401;跨项目已挂 authz → 403 |
|
||||
|
||||
---
|
||||
|
||||
## 任务分解
|
||||
|
||||
### Task 1 — IAM 数据库迁移(`feat(db)`)
|
||||
|
||||
新建 `deploy/postgres/goose/00015_iam_core.sql`:
|
||||
|
||||
- `users`(id, 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)
|
||||
- `auth_sessions`(id, token_hash, user_id, created_at, last_seen_at, idle_expires_at, absolute_expires_at, revoked_at, ip_hash, user_agent)
|
||||
- `roles` / `permissions` / `role_permissions` / `user_role_bindings`
|
||||
- seed:`role-admin` + 核心 permissions + 从 MemoryStore dev 用户回填(仅 dev/test 迁移脚本)
|
||||
|
||||
约束:username unique;token_hash unique;至少一个 super-admin binding。
|
||||
|
||||
### Task 2 — PostgresAuthStore(`feat(auth)`)
|
||||
|
||||
- `internal/auth/pg_store.go` 实现 `AuthStore`
|
||||
- 会话:Login 写 `auth_sessions`(只存 SHA256(token));ValidateToken 查库 + 更新 last_seen
|
||||
- Logout/RevokeAll 标记 revoked_at
|
||||
- `server.go`:有 `ContextDbHost` 时用 PgStore,否则 dev 仍 MemoryStore
|
||||
|
||||
### Task 3 — AuthorizationService(`feat(authz)`)
|
||||
|
||||
- `internal/authz/service.go`:`Capabilities(ctx, userID) []string`
|
||||
- `HasPermission(ctx, userID, perm, scope)` 组合系统 role_bindings + `project_members`
|
||||
- 替换 scattered `role-admin` 硬编码 → `HasSystemPermission(..., "system.admin")` 或保留 admin role_id 映射
|
||||
- `requireAdmin` / `requireProjectAccess` 改调用 Authorizer + AuthzService
|
||||
|
||||
### Task 4 — Auth API 扩展(`feat(api)`)
|
||||
|
||||
- `GET /api/v1/auth/me` 增加 `capabilities: string[]`
|
||||
- 会话列表/撤销(用户设置 Phase 1 最小版):`GET/DELETE /api/v1/auth/sessions`
|
||||
- Admin users/roles CRUD 对齐 DB(现有 handler 改接 PgStore)
|
||||
|
||||
### Task 5 — 项目成员 API(`feat(api)`)
|
||||
|
||||
- `GET/POST/PUT/DELETE /api/v1/projects/{id}/members`
|
||||
- 仅 owner/creator + `projects.members.manage` 可写
|
||||
- 与 `project_members` 表对齐;禁止把 author/reviewer/approver 写入成员 role
|
||||
|
||||
### Task 6 — 前端 capabilities(`feat(web)`)
|
||||
|
||||
- `authClient.me()` 缓存 capabilities
|
||||
- `engine/rbac.ts`:`hasPermission` 优先读 capabilities;localStorage roles 只读迁移提示
|
||||
- `AdminSettingsModal` / `UserProjectRightsModal` 成员编辑走 API
|
||||
- 移除 `loadRoles(DEFAULT_ROLES)` 作为权威初始化(保留 demo 数据只读展示直至导入完成)
|
||||
|
||||
### Task 7 — 测试与报告(`test` / `docs(test)`)
|
||||
|
||||
- `internal/auth/pg_store_test.go`(testcontainers 或 stub pg)
|
||||
- `internal/authz/service_test.go`
|
||||
- 扩展 `security_p0_test` + 跨项目 403(需 DB fixture)
|
||||
- `.doc/test-reports/2026-09-12-phase1-iam-authz-test-report.md`
|
||||
|
||||
---
|
||||
|
||||
## 建议提交节奏
|
||||
|
||||
1. `feat(db):` IAM goose migration + seed
|
||||
2. `feat(auth):` PostgresAuthStore + session persistence
|
||||
3. `feat(authz):` AuthorizationService + admin gate
|
||||
4. `feat(api):` members CRUD + auth/me capabilities
|
||||
5. `feat(web):` frontend capabilities consumer
|
||||
6. `test(docs):` Phase 1 report
|
||||
|
||||
---
|
||||
|
||||
## 风险
|
||||
|
||||
- **双写期**:MemoryStore 与 PG 并存时须单一 Store 注入,避免混用。
|
||||
- **ID 对齐**:现有 `projects.creator_user_id` / memory user id 与 PG users.id 迁移需一次性回填脚本。
|
||||
- **前端降级**:capabilities 未加载前 fail closed(禁用敏感按钮,不默认 allow)。
|
||||
本文档已迁至 [remediation/2026-09-12-phase1-iam-authz-implementation-plan.md](remediation/2026-09-12-phase1-iam-authz-implementation-plan.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,23 +1,3 @@
|
||||
# Phase 2:工作流设计器与模板库 Implementation Plan
|
||||
# 已迁移
|
||||
|
||||
> **依据**:`.doc/2026-09-11-production-ready-workflow-governance-plan.md` §7、§15 Phase 2
|
||||
|
||||
**Goal:** 工作流定义版本化入库;模板 CAS 资产库;Admin 草稿/校验/发布/退役;静态 catalog bootstrap;运行时 DBCatalog。
|
||||
|
||||
**不在本阶段:** 项目激活冻结、instance 快照、阶段 ABAC(Phase 3)。
|
||||
|
||||
## 完成门禁
|
||||
|
||||
| 门禁 | 判定 |
|
||||
|---|---|
|
||||
| 已发布版本不可变 | Publish 后 UpdateDraft 拒绝 |
|
||||
| 非法工作流不能发布 | Validate 失败 → 422 |
|
||||
| 旧 catalog bootstrap | BootstrapSeeds 幂等写入 5 套 published v1 |
|
||||
| 运行时读 DB | NewCatalog 优先 DBCatalog |
|
||||
|
||||
## 已交付模块
|
||||
|
||||
- `deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql`
|
||||
- `internal/workflowdef/` — store, service, validator, catalog, bootstrap
|
||||
- `internal/server/admin_workflow_handlers.go`, `admin_template_handlers.go`
|
||||
- `web/src/api/workflowAdmin.ts` + AdminSettingsModal workflows Tab
|
||||
本文档已迁至 [remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md](remediation/2026-09-12-phase2-workflow-designer-implementation-plan.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,461 +1,3 @@
|
||||
# 项目审计快速参考指南
|
||||
|
||||
**用途**: 开发/QA 快速定位问题、理解整改方向
|
||||
**格式**: 结构化索引,支持搜索和导航
|
||||
|
||||
---
|
||||
|
||||
## 一、关键数字一览
|
||||
|
||||
| 指标 | 数值 | 说明 |
|
||||
|---|---|---|
|
||||
| 项目完成度 | 70% | 架构完整,核心功能大部分实现,缺新功能和 bug 修复 |
|
||||
| 已确认缺陷 | 12 个 | 3 个 critical,4 个 high,5 个 medium |
|
||||
| 未完成功能 | 3 个 | 项目上下文快照、受控终止、E2E 测试 |
|
||||
| 整改工作量 | 61h | 单人 2.5 天,双人 5 天 |
|
||||
| 单元测试 | 120+ | 85% 覆盖主要包 |
|
||||
| E2E 测试 | 0% | **需补充** |
|
||||
| 数据污染 | 88 个定义 | 测试定义混入开发库 |
|
||||
|
||||
---
|
||||
|
||||
## 二、快速诊断矩阵
|
||||
|
||||
### 症状 → 原因 → 解决方案
|
||||
|
||||
```
|
||||
症状 1: 完成工作流后项目仍显示为"正在运行",无法配置下一个工作流
|
||||
├─ 原因: BUG-01 - AdvanceStage 完成最后阶段时未更新项目 lifecycle
|
||||
├─ 代码位置: internal/projectinstance/stage_store.go:128-158
|
||||
├─ 优先级: 🔴 P0 CRITICAL
|
||||
└─ 解决: Task A1(2h)
|
||||
└─ 同事务更新 projects.lifecycle_status = 'planning'
|
||||
|
||||
症状 2: 禁用的文档仍然可以在某些页面被启动/编辑
|
||||
├─ 原因: BUG-05 - 拒绝逻辑分散,不同入口检查不一致
|
||||
├─ 代码位置: stage_access.go, API, SSE, Agent tools 多处
|
||||
├─ 优先级: 🔴 P1 HIGH
|
||||
└─ 解决: Task A5(4h)
|
||||
└─ 实现 DocumentAccessDecider,统一所有入口
|
||||
|
||||
症状 3: 对话中说"推进工作流"有时不生效或使用旧流程
|
||||
├─ 原因: BUG-04 - Coordinator 调用旧 bizdevSvc.ExecuteStage
|
||||
├─ 代码位置: internal/coordinator/engine.go:672-811
|
||||
├─ 优先级: 🔴 P0 CRITICAL
|
||||
└─ 解决: Task A4(2h)
|
||||
└─ 改为调用 instSvc.AdvanceStage
|
||||
|
||||
症状 4: 阶段推进后发现文档被强制标记为"已批准",但用户未操作
|
||||
├─ 原因: BUG-02 - AdvanceStage SQL 中有强制更新批准状态的逻辑
|
||||
├─ 代码位置: internal/projectinstance/stage_store.go(需 grep 验证)
|
||||
├─ 优先级: 🔴 P0 CRITICAL
|
||||
└─ 解决: Task A2(1h)
|
||||
└─ 删除 UPDATE 批准状态的 SQL 行
|
||||
|
||||
症状 5: 测试在开发环境运行后,88 个奇怪的 pg_* 定义出现在工作流目录
|
||||
├─ 原因: BUG-08 - 集成测试未设置 TEST_DATABASE_URL,默认连接开发库
|
||||
├─ 代码位置: internal/projectinstance/pg_integration_test.go
|
||||
├─ 优先级: 🟠 P1 MEDIUM
|
||||
└─ 解决: Task BUG-08(2h)
|
||||
└─ 强制要求 TEST_DATABASE_URL;测试后清理
|
||||
|
||||
症状 6: 激活工作流时 token 可能在浏览器历史中看到,或被重复使用
|
||||
├─ 原因: BUG-06 - Token 明文保存,消费分事务,不是 one-time
|
||||
├─ 代码位置: internal/projectinstance/service.go(激活相关)
|
||||
├─ 优先级: 🟠 P1 HIGH
|
||||
└─ 解决: Task A6(3h)
|
||||
└─ Token → hash + one-time,同事务消费
|
||||
|
||||
症状 7: 产品经理流程不运行,测试工程师流程无法启动,提示"需先运行产品流程"
|
||||
├─ 原因: MISSING-06 - test_manager manifest 中仍有 upstream 依赖
|
||||
├─ 代码位置: internal/workflowdef/manifests/test_manager.v2.json
|
||||
├─ 优先级: 🟠 P1 HIGH
|
||||
└─ 解决: Task B3(需先删除测试流程的上游依赖)
|
||||
└─ 修改 manifest,删除 required_upstream_workflow
|
||||
|
||||
症状 8: 选择工作流时前端显示"商务流程",但服务返回的名称不一致
|
||||
├─ 原因: BUG-12 - 前端硬编码名称 vs 后端正式名称不同步
|
||||
├─ 代码位置: web/src/components/workflow/ProjectWorkflowSwitcher.tsx
|
||||
├─ 优先级: 🟢 P2 LOW
|
||||
└─ 解决: 由后端 GET /api/v1/workflows/catalog 驱动前端显示
|
||||
|
||||
症状 9: 无法手工删除已完成的工作流实例,项目永久处于"运行中"
|
||||
├─ 原因: MISSING-02 - 受控终止 API 未实现
|
||||
├─ 代码位置: (缺失)
|
||||
├─ 优先级: 🔴 P1 CRITICAL
|
||||
└─ 解决: Task B1(6h)
|
||||
└─ 实现 TerminateWorkflow API,二次确认 + 原因记录
|
||||
|
||||
症状 10: 产品经理和测试工程师输出中缺少"来源追溯",无法知道数据从哪来
|
||||
├─ 原因: MISSING-01 - 项目上下文快照服务未实现
|
||||
├─ 代码位置: (缺失)
|
||||
├─ 优先级: 🔴 P1 CRITICAL
|
||||
└─ 解决: Task B3(12h)
|
||||
└─ 实现 ProjectContextSnapshot 服务,包含血缘表
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、代码热点地图
|
||||
|
||||
### 高风险区域(需特别关注的文件)
|
||||
|
||||
```
|
||||
🔴 CRITICAL
|
||||
├─ internal/projectinstance/stage_store.go
|
||||
│ ├─ BUG-01: AdvanceStage 不更新项目生命周期
|
||||
│ ├─ BUG-02: 推进强制批准文档(需验证)
|
||||
│ └─ 位置: 第 71-158 行
|
||||
│
|
||||
├─ internal/coordinator/engine.go
|
||||
│ ├─ BUG-04: 对话推进调用旧服务
|
||||
│ └─ 位置: 第 672-811 行(handleAdvanceStage)
|
||||
│
|
||||
├─ internal/projectinstance/service.go
|
||||
│ ├─ BUG-01: 完成后生命周期(同上)
|
||||
│ └─ 位置: 第 119-135 行(SaveWorkflowPlan)
|
||||
|
||||
🟠 HIGH
|
||||
├─ internal/projectinstance/stage_access.go
|
||||
│ ├─ BUG-05: 禁用文档拒绝逻辑不一致
|
||||
│ └─ 位置: 第 15-71, 90-104 行
|
||||
│
|
||||
├─ web/src/components/workflow/ProjectWorkflowSwitcher.tsx
|
||||
│ ├─ BUG-09: 版本冲突自动重试
|
||||
│ ├─ BUG-12: 硬编码名称
|
||||
│ └─ 位置: 第 16-23, 38-76, 173-236 行
|
||||
|
||||
🟡 MEDIUM
|
||||
├─ internal/projectinstance/pg_integration_test.go
|
||||
│ ├─ BUG-08: 未设置 TEST_DATABASE_URL
|
||||
│ └─ 位置: 第 19-49 行
|
||||
│
|
||||
├─ internal/workflowdef/manifests/test_manager.v2.json
|
||||
│ ├─ 依然有 upstream 依赖(需删除)
|
||||
│ └─ 位置: 第 1-23 行
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、整改优先级排序
|
||||
|
||||
### 必须在本周内完成(优先级递减)
|
||||
|
||||
```
|
||||
□ P0-1: BUG-01 项目完成后生命周期 (2h)
|
||||
→ 项目永久锁死的根本原因
|
||||
|
||||
□ P0-2: BUG-04 对话推进新服务切换 (2h)
|
||||
→ 权限检查绕过
|
||||
|
||||
□ P0-3: BUG-02 推进不强制批准 (1h)
|
||||
→ 数据违反业务规则
|
||||
|
||||
□ P1-1: BUG-05 禁用文档一致性 (4h)
|
||||
→ 安全隐患
|
||||
|
||||
□ P1-2: BUG-06 激活 token 安全 (3h)
|
||||
→ 存在泄露/重放风险
|
||||
|
||||
□ P1-3: Task B1 受控终止 API (6h)
|
||||
→ 恢复能力必需
|
||||
|
||||
□ P1-4: Task B2 E2E 测试 (8h)
|
||||
→ 验收标准要求
|
||||
|
||||
可以延后(下周处理)
|
||||
|
||||
□ P2-1: BUG-03 禁用文档 skipped_disabled (3h)
|
||||
□ P2-2: BUG-08 测试隔离完善 (2h)
|
||||
□ P2-3: BUG-10 项目设置审计视图 (3h)
|
||||
□ P2-4: BUG-09 前端冲突自动重试 (1h)
|
||||
□ P2-5: BUG-11 旧 API 下线 (1h)
|
||||
□ P2-6: BUG-12 前端名称一致性 (1h)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、代码修改检查清单
|
||||
|
||||
### 提交前验收标准
|
||||
|
||||
**修复 BUG-01 时**:
|
||||
```
|
||||
[ ] 修改 stage_store.go 的 AdvanceStage 函数
|
||||
- 检查是否最后阶段
|
||||
- 若是,同事务更新 projects.lifecycle_status
|
||||
- 清空 current_workflow_instance_id
|
||||
- 写审计事件
|
||||
[ ] 新增测试: TestAdvanceStage_CompletesProjectAfterLastStage
|
||||
[ ] 新增测试: TestAdvanceStage_DoesNotChangeProjectOnNonLastStage
|
||||
[ ] 本地测试通过 (go test ./internal/projectinstance -v)
|
||||
[ ] 前端检查:/projects/{id}/settings 显示"配置下一工作流"
|
||||
```
|
||||
|
||||
**修复 BUG-04 时**:
|
||||
```
|
||||
[ ] 修改 coordinator/engine.go 的 handleAdvanceStage
|
||||
- 提取 workflow_instance_id
|
||||
- 改调 instSvc.AdvanceStage 替代 bizdevSvc.ExecuteStage
|
||||
- 调整返回格式
|
||||
[ ] 新增测试: TestDialogueAdvanceStage_UsesNewService
|
||||
[ ] 新增测试: TestDialogueAdvanceStage_PermissionCheck
|
||||
[ ] 本地测试通过 (go test ./internal/coordinator -v)
|
||||
[ ] 对话测试通过 (go test ./internal/server -run Dialogue -v)
|
||||
```
|
||||
|
||||
**创建 Task B2 E2E 框架时**:
|
||||
```
|
||||
[ ] 确保 TEST_DATABASE_URL 已设置
|
||||
[ ] 创建 setupE2ETestDB() 函数
|
||||
- 创建隔离 schema
|
||||
- 运行所有迁移
|
||||
- 清理逻辑
|
||||
[ ] 编写 TestE2E_BizdevWorkflow_Complete
|
||||
- 7 文档完整流程
|
||||
- 每个阶段验证门禁
|
||||
- 完成后验证项目状态
|
||||
[ ] 编写 TestE2E_ProductManagerWorkflow_Standalone
|
||||
- 无前置依赖
|
||||
- 独立运行成功
|
||||
[ ] 编写 TestE2E_TestEngineerWorkflow_WithoutSRS
|
||||
- 无 SRS 输入仍能运行
|
||||
- 输出包含来源清单
|
||||
[ ] 全部 E2E 测试通过
|
||||
[ ] 验收标准 7.5 完全满足
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、数据库迁移清单
|
||||
|
||||
### 需要新增的迁移脚本
|
||||
|
||||
```
|
||||
00025_2026-09-12-disabled-doc-status.sql
|
||||
├─ 添加 project_doc_task_instances.status_reason
|
||||
├─ 添加约束:disabled 时 duties 为空
|
||||
└─ 编写回滚脚本
|
||||
|
||||
00026_2026-09-12-workflow-termination.sql
|
||||
├─ 添加 project_workflow_instances.terminated_at/by/reason
|
||||
├─ 添加 termination_reason 列
|
||||
└─ 编写回滚脚本
|
||||
|
||||
00027_2026-09-12-context-snapshots.sql
|
||||
├─ 创建 project_context_snapshots 表
|
||||
├─ 创建 project_context_snapshot_sources 表
|
||||
└─ 编写回滚脚本
|
||||
|
||||
00028_2026-09-12-activation-challenges.sql
|
||||
├─ 创建 activation_challenges 表
|
||||
├─ 创建 one_time_tokens 表
|
||||
└─ 编写回滚脚本
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、测试命令参考
|
||||
|
||||
```bash
|
||||
# 运行所有项目实例测试
|
||||
go test ./internal/projectinstance -v
|
||||
|
||||
# 运行所有协调器测试
|
||||
go test ./internal/coordinator -v
|
||||
|
||||
# 运行所有工作流定义测试
|
||||
go test ./internal/workflowdef -v
|
||||
|
||||
# 运行服务器集成测试
|
||||
go test ./internal/server -v
|
||||
|
||||
# 运行特定 bug 的测试
|
||||
go test ./internal/projectinstance -run "TestAdvanceStage" -v
|
||||
|
||||
# 运行 PG 集成测试(需 TEST_DATABASE_URL)
|
||||
TEST_DATABASE_URL=postgresql://... go test ./internal/server -run PG -v
|
||||
|
||||
# 运行 E2E 测试
|
||||
TEST_DATABASE_URL=postgresql://... go test ./internal/server -run E2E -v
|
||||
|
||||
# 代码覆盖率分析
|
||||
go test ./internal/projectinstance ./internal/coordinator ./internal/workflowdef \
|
||||
-coverprofile=coverage.out && go tool cover -html=coverage.out
|
||||
|
||||
# 静态检查
|
||||
go vet ./internal/...
|
||||
golangci-lint run ./internal/...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、API 快速参考
|
||||
|
||||
### 关键端点变动汇总
|
||||
|
||||
```
|
||||
现有(需保留或改进):
|
||||
GET /api/v1/workflows/catalog
|
||||
→ 返回三项正式工作流 ✅
|
||||
|
||||
GET /api/v1/projects/{id}/settings
|
||||
→ 返回项目设置及 live instance 配置 ✅
|
||||
|
||||
PUT /api/v1/projects/{id}/workflow-plan
|
||||
→ 保存/修改规划 (planning 状态下) ✅
|
||||
|
||||
POST /api/v1/projects/{id}/workflow-instances/activate
|
||||
→ 激活工作流 (需修复 token) ⚠️
|
||||
|
||||
GET /api/v1/workflow-instances/{id}/stages/{stage}/readiness
|
||||
→ 阶段门禁详情 ✅
|
||||
|
||||
POST /api/v1/workflow-instances/{id}/stages/{stage}/advance
|
||||
→ 推进阶段 (需修复生命周期) ❌
|
||||
|
||||
待实现(高优先级):
|
||||
POST /api/v1/workflow-instances/{id}/termination-preview
|
||||
→ 终止预览(Task B1)
|
||||
|
||||
POST /api/v1/workflow-instances/{id}/terminate
|
||||
→ 执行终止(Task B1)
|
||||
|
||||
待删除或返回 410:
|
||||
POST /projects/{id}/active-workflow
|
||||
→ 旧切换 API(需下线)
|
||||
|
||||
需改进(权限一致性):
|
||||
POST /api/v1/doc-task-instances/{id}/runs
|
||||
→ 启动编制 (需 DocumentAccessDecider) ⚠️
|
||||
|
||||
POST /api/v1/documents/{id}/submit
|
||||
→ 提交审核 (需统一权限检查) ⚠️
|
||||
|
||||
POST /api/v1/documents/{id}/approve
|
||||
→ 批准 (需统一权限检查) ⚠️
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、常见问题速查
|
||||
|
||||
### Q1: 为什么完成工作流后项目仍然处于"active"?
|
||||
**A**: BUG-01 - `AdvanceStage` 完成最后阶段时未同事务更新项目 `lifecycle_status`。
|
||||
**修复**: Task A1(2h)
|
||||
**临时绕过**: 手动执行 SQL `UPDATE projects SET lifecycle_status='planning' WHERE id=?`
|
||||
|
||||
### Q2: 禁用的文档仍然能被某些用户操作?
|
||||
**A**: BUG-05 - 不同入口对禁用文档的检查不一致。
|
||||
**修复**: Task A5(4h) - 实现 `DocumentAccessDecider`
|
||||
**临时绕过**: 在关键入口前添加 `if doc.status == 'skipped_disabled' { return 409 }`
|
||||
|
||||
### Q3: 激活 token 可能被重复使用?
|
||||
**A**: BUG-06 - Token 明文保存,消费分事务。
|
||||
**修复**: Task A6(3h)
|
||||
**临时保护**: 限制 token 有效期为 5 分钟;记录消费日志;审计异常 token 使用
|
||||
|
||||
### Q4: 对话推进工作流不起作用?
|
||||
**A**: BUG-04 - Coordinator 调用旧商务服务而非实例服务。
|
||||
**修复**: Task A4(2h)
|
||||
**临时检查**: 查看 `internal/coordinator/engine.go:672-811` 是否仍调用 `bizdevSvc`
|
||||
|
||||
### Q5: 为什么 E2E 测试一直 fail?
|
||||
**A**: 可能多个原因:
|
||||
1. TEST_DATABASE_URL 未设置 → 连接开发库(88 个污染定义)
|
||||
2. E2E 框架缺失 → 需实现 setupE2ETestDB()
|
||||
3. 实例生命周期 bug → BUG-01 导致测试逻辑不对
|
||||
|
||||
**修复**: 检查 TEST_DATABASE_URL;运行 Task B2
|
||||
|
||||
### Q6: 生产数据库中有 47 个"已完成但项目仍为 active"的不一致数据?
|
||||
**A**: BUG-01 导致。数据本身可恢复。
|
||||
**恢复方案**:
|
||||
1. 查询 `SELECT * FROM project_workflow_instances WHERE status='completed'`
|
||||
2. 对每个 completed 实例:
|
||||
```sql
|
||||
UPDATE projects SET lifecycle_status='planning', current_workflow_instance_id=NULL
|
||||
WHERE id=(SELECT project_id FROM project_workflow_instances WHERE id=?)
|
||||
```
|
||||
3. 补写审计日志
|
||||
|
||||
---
|
||||
|
||||
## 十、参考文档导航
|
||||
|
||||
| 文档 | 用途 | 适合人员 |
|
||||
|---|---|---|
|
||||
| [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) | **当前缺口 SSOT** | 全体 |
|
||||
| [ops/CURRENT.md](./ops/CURRENT.md) | 协作焦点 | Agent / 开发 |
|
||||
| [comprehensive-audit-and-remediation-plan.md](./2026-09-12-comprehensive-audit-and-remediation-plan.md) | 详细缺陷分析与整改方案(历史) | 架构师、资深开发 |
|
||||
| [remediation-tasks-and-acceptance-checklist.md](./2026-09-12-remediation-tasks-and-acceptance-checklist.md) | 可执行的任务拆分与验收 | 开发、QA |
|
||||
| [audit-summary-report.md](./2026-09-12-audit-summary-report.md) | 审计总结与建议(历史) | 项目经理、技术负责人 |
|
||||
| **[本文件]** | 快速参考与索引 | 全体团队 |
|
||||
| [three-workflows-strict-governance-remediation.md](./2026-09-12-three-workflows-strict-governance-remediation.md) | 业务需求原始规划 | 产品、架构 |
|
||||
|
||||
---
|
||||
|
||||
## 十一、快速评分表
|
||||
|
||||
### 修复每个 bug 后的自检清单
|
||||
|
||||
```
|
||||
BUG-01 ✓ 完成
|
||||
□ stage_store.go 修改
|
||||
□ 新增单元测试 ×2
|
||||
□ 本地 go test PASS
|
||||
□ 前端验证项目状态改变
|
||||
→ 接受标准: 完成最后阶段后项目 lifecycle='planning'
|
||||
|
||||
BUG-02 ✓ 完成
|
||||
□ grep 确认强制批准逻辑存在
|
||||
□ 删除 UPDATE 批准状态的 SQL
|
||||
□ 新增单元测试
|
||||
□ 本地 go test PASS
|
||||
→ 接受标准: 推进前后文档状态不变
|
||||
|
||||
BUG-04 ✓ 完成
|
||||
□ engine.go handleAdvanceStage 改为调用新服务
|
||||
□ 新增单元测试
|
||||
□ 本地 go test PASS
|
||||
□ 对话测试 PASS
|
||||
→ 接受标准: 对话推进使用 instSvc
|
||||
|
||||
BUG-05 ✓ 完成
|
||||
□ 实现 DocumentAccessDecider 接口
|
||||
□ 集成到 API、SSE、异步任务、Agent tools
|
||||
□ 新增综合测试
|
||||
□ 本地 go test PASS
|
||||
→ 接受标准: 禁用文档全拒绝,返回 409/403
|
||||
|
||||
BUG-06 ✓ 完成
|
||||
□ 数据库迁移 00028
|
||||
□ API 改为 challenge_id + one_time_token
|
||||
□ Token hash + 原子消费
|
||||
□ 新增安全测试 ×4
|
||||
□ 本地 go test PASS
|
||||
→ 接受标准: Token one-time、hash 存储、5 分钟过期
|
||||
|
||||
Task B1 ✓ 完成
|
||||
□ 新增 terminate.go 服务
|
||||
□ TerminationPreview API
|
||||
□ TerminateWorkflow API
|
||||
□ 新增端到端测试
|
||||
□ 本地 go test PASS
|
||||
→ 接受标准: 终止后项目可配置下一流程
|
||||
|
||||
Task B2 ✓ 完成
|
||||
□ setupE2ETestDB() 实现
|
||||
□ TestE2E_BizdevWorkflow_Complete PASS
|
||||
□ TestE2E_ProductManagerWorkflow_Standalone PASS
|
||||
□ TestE2E_TestEngineerWorkflow_WithoutSRS PASS
|
||||
□ TEST_DATABASE_URL 隔离库运行
|
||||
→ 接受标准: 三工作流完整链路验证
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0 快速参考
|
||||
**适用对象**: 项目全体
|
||||
**更新频率**: 同步更新主审计文档
|
||||
# 已迁移
|
||||
|
||||
本文档已迁至 [remediation/2026-09-12-quick-reference-guide.md](remediation/2026-09-12-quick-reference-guide.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,71 +1,3 @@
|
||||
# 整改缺口复核矩阵(SSOT)
|
||||
# 已迁移
|
||||
|
||||
**更新**: 2026-09-13
|
||||
**分支**: dev
|
||||
**production_ready**: no(CI 真实 PI E2E / 前端人工抽检未完成;main 本地冒烟已通过)
|
||||
**协作焦点**: [.doc/ops/CURRENT.md](ops/CURRENT.md)
|
||||
**Agent 手册**: [AGENTS.md](../AGENTS.md) · [PROJECT.md](../PROJECT.md)
|
||||
|
||||
> Codex 2026-09-12 再审计项与本轮回环证据见下表「Codex 再审计」区段。
|
||||
|
||||
---
|
||||
|
||||
## Phase A/B/C 原审计项
|
||||
|
||||
| ID | 审计描述 | 状态 | 证据 | 计划动作 |
|
||||
|---|---|---|---|---|
|
||||
| BUG-01 | 完成后 lifecycle 未更新 | PASS | `stage_remediation_test.go`;`scripts/fix-completed-instance-lifecycle.sql`;dev 执行 UPDATE 47 | 已完成 |
|
||||
| BUG-02 | 推进强制批文档 | PASS | `AdvanceStage` 无 doc UPDATE | 已完成 |
|
||||
| BUG-03 | 无 skipped_disabled | PASS | memStore `skipped_disabled` | 已完成 |
|
||||
| BUG-04 | 对话走旧 bizdev | PASS | `engine.go` live 门控 | 已完成 |
|
||||
| BUG-05 | 拒绝逻辑分散 | PASS | `document_access.go` + `stage_access_helpers.go` | 已完成 |
|
||||
| BUG-06 | token 明文/重放 | PASS | `activation_token_test.go` | 已完成 |
|
||||
| BUG-07 | 完成后下一流程 | PASS | 同 BUG-01 | 已完成 |
|
||||
| BUG-08 | 测试库隔离 | PARTIAL | `db/testdb.go` Require/Skip | CI 设 `TEST_DATABASE_URL` |
|
||||
| BUG-09 | 版本冲突自动重试 | PASS | `StageAdvanceBanner` reload | 已完成 |
|
||||
| BUG-10 | 无审计视图 | PASS | settings + UI | 已完成 |
|
||||
| BUG-11 | 旧 API 未下线 | PARTIAL | 治理开启时 410 | 保持 + 文档标注 |
|
||||
| BUG-12 | 前端名称硬编码 | PASS | catalog API | 已完成 |
|
||||
| MISSING-01 | 上下文快照 | PASS | `ctxmgr.CollectProjectDialogue` | 已完成 |
|
||||
| MISSING-02 | 终止 | PASS | `GetTerminationPreview` | 已完成 |
|
||||
| MISSING-04 | E2E | PASS | 三正式工作流 PG+PI E2E | 已完成 |
|
||||
|
||||
---
|
||||
|
||||
## Codex 2026-09-12 再审计
|
||||
|
||||
| ID | 描述 | 状态 | 证据 |
|
||||
|---|---|---|---|
|
||||
| AUTH-TASK-RUN | `/tasks/run` 缺项目鉴权 | PASS | `handlers.go` RequireProjectAccess;`task_run_authz_pg_test.go` |
|
||||
| AUTH-TASK-SSE | `/tasks/run/stream` 鉴权在 Flush 前 | PASS | `sse.go`;同上测试 |
|
||||
| DB-USERS-SEQ | 种子 users_id_seq 冷启动冲突 | PASS | `00025_...-sync-seed-sequences.sql`;dev/test setval |
|
||||
| DATA-LIFECYCLE-DEV | completed 实例对应 active 项目 | PASS | dev dry-run 47 → fix SQL → 0 |
|
||||
| DATA-TEST-WF | test 污染 active 工作流定义 | PASS | `retire-nonofficial-workflow-definitions.sql`;test UPDATE 5 |
|
||||
| TEST-ADVISOR-BRIEF | 多意图 AdvisorBrief 丢失 | PASS | `action_planner.go` enrich;`action_planner_test.go` |
|
||||
| TEST-V05-ARTIFACTS | V0.5 断言 3 vs 5 | PASS | `types_test.go` / `full_link_e2e_test.go` → 5 |
|
||||
| TEST-CHAT-MEMORY | 语义记忆 sleep 竞态 | PASS | `session_test.go` deadline 轮询 |
|
||||
| TEST-EMBEDDING-GATE | 默认打真实 embedding | PASS | `kb/integration_test.go` Short + `RUN_KB_INTEGRATION=1` |
|
||||
| HEALTH-SCHEMA-CACHE | health schema 启动缓存 | PASS | `LiveSchemaVersion` + health 实时读 |
|
||||
| GO-VET-ASSET | asset handler resp before err | PASS | `asset_handlers_test.go` err-first |
|
||||
| ENV-TEST-STALE | test 旧镜像/schema 漂移 | PASS | rebuild app;health schema_version=25 |
|
||||
| ENV-DEV-STALE | dev 二进制/schema 漂移 | PASS | docker app 重启;schema_version=25 |
|
||||
| ENV-MAIN-MISSING | main 未部署验收 | PASS | docker 创建 `data/main`;compose 注入 ADMIN/KB 密码;health/ready schema 25 |
|
||||
| DOC-SSOT | 文档叙事漂移 | PASS | 本矩阵 + superseded 标记 + ops |
|
||||
| OPS-AGENTS | 多 Agent 协作规范 | PASS | `AGENTS.md` / `PROJECT.md` / `.doc/ops` |
|
||||
|
||||
---
|
||||
|
||||
## 发布门禁(test → main)
|
||||
|
||||
```
|
||||
☑ go vet ./... 全绿
|
||||
☑ go test -short ./... 全绿
|
||||
□ TEST_DATABASE_URL 下治理 PG 集成全绿(CI)
|
||||
□ 真实 PI Agent 三工作流治理 E2E 实录(本轮 stub/short 已绿,PI 待 CI token)
|
||||
☑ lifecycle fix SQL 已在 dev 执行
|
||||
☑ test/dev health schema_version=25
|
||||
☑ main 环境部署冒烟(本地 8000 health/ready schema 25)
|
||||
□ 前端:版本冲突刷新、终止 preview 人工抽检
|
||||
```
|
||||
|
||||
**结论**: P0 授权、冷启动序列、Go 门禁、三环境本地冒烟已闭环。**发布 blocker 剩余 CI 真实 PI E2E 与前端人工抽检**。
|
||||
本文档已迁至 [remediation/gap-matrix.md](remediation/gap-matrix.md)。请勿在此编辑。
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,525 +1,3 @@
|
||||
# 三工作流严格治理与现有系统融合整改方案
|
||||
# 已迁移
|
||||
|
||||
- 日期:2026-09-12
|
||||
- 状态:核心业务决策已确认 / 可进入实施拆分
|
||||
- 范围:工作流定义、项目实例、阶段门禁、文档三权、通知与对话推进、运行时授权、数据迁移和验收
|
||||
- 本文性质:当前代码与开发数据库的只读核验结论及整改设计;本轮未修改业务代码
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
系统面向项目创建者和项目成员时,只应存在以下 **3 个可选择工作流**:
|
||||
|
||||
1. **商务对接流程**:7 个文档,3 个阶段;
|
||||
2. **智能产品经理流程**:1 个输出文档,1 个阶段;
|
||||
3. **智能测试工程师流程**:1 个输出文档,1 个阶段。
|
||||
|
||||
商务对接流程的文档数量可以定案为 **7 个,不是 6 个**。前端模板工厂和测试固定断言了 7 个任务键,后端标准任务目录也包含同一组 7 个商务文档,历史专项测试报告同样把它们定义为标准全生命周期交付物。[^biz-seven-test][^biz-seven-backend][^biz-seven-report]
|
||||
|
||||
当前系统尚未满足这一目标,且不是简单改几个显示名称即可解决:
|
||||
|
||||
- 启动代码实际发布 5 个默认工作流,除目标三项外还包含“医疗器械研发”和“非医疗纯软件”;[^bootstrap-five]
|
||||
- 当前开发库已有 92 个工作流定义,其中大量为测试定义;三个目标工作流仍都是单阶段的 schema v1;
|
||||
- 仓库虽然有三个 schema v2 清单,但商务清单只有 5 个文档,漏了 `feasibility_dev` 和 `user_requirements`;[^main-v2-missing]
|
||||
- 三个 v2 清单仅被嵌入和登记,没有进入启动发布链;已有发布版又会让 seed 逻辑直接退出,因此现有库不会自动升级;[^manifest-loader][^seed-no-upgrade]
|
||||
- 旧运行入口会把多阶段版本压成“第一个阶段的第一个任务”,与项目实例运行时并存,形成双轨权威;[^catalog-flatten]
|
||||
- 配置页面允许勾选关闭文档,但后端校验禁止关闭所有 `required/blocking` 文档;当前清单又把所有文档都标成这两类,因此界面能力实际上不可用;[^plan-disable-conflict]
|
||||
- 智能测试工程师当前被 manifest、执行服务和前端提示硬绑定到产品经理/SRS,与已确认的两个智能工作流独立运行原则冲突;[^test-upstream][^test-hard-dependency]
|
||||
- 阶段推进虽然先检查批准状态,但事务内会把所有启用任务强制写成 `approved`,并且最后阶段完成后没有把项目恢复到可选择下一工作流的状态;[^advance-forces-approved][^project-lifecycle-gap]
|
||||
- 对话中的“推进阶段”仍调用旧商务成熟度执行器,并没有调用项目工作流实例的阶段推进服务;[^dialogue-old-advance]
|
||||
|
||||
因此本次整改的核心是:**以已激活项目工作流实例的冻结快照作为唯一运行时权威**。工作流目录、项目配置、文档三权、任务启动、审批、阶段门禁、通知和对话都必须围绕同一个实例标识运行,旧的直接切换和扁平执行入口退出生产路径。
|
||||
|
||||
## 2. 已确认的业务基线
|
||||
|
||||
### 2.1 唯一允许对项目展示和选择的工作流
|
||||
|
||||
| 稳定内部 key | 对外名称 | 阶段数 | 输出文档数 | 说明 |
|
||||
|---|---|---:|---:|---|
|
||||
| `main` | 商务对接流程 | 3 | 7 | 保留现有 key 以避免破坏历史数据,只改正式名称 |
|
||||
| `product_manager` | 智能产品经理流程 | 1 | 1 | 输出《系统需求规格书》 |
|
||||
| `test_manager` | 智能测试工程师流程 | 1 | 1 | 保留现有 key,只把“测试经理”统一更名为“测试工程师” |
|
||||
|
||||
“系统只需要三个流程”的含义应同时落实到三个层面:
|
||||
|
||||
- 项目设置 API 只返回这 3 个可选项;
|
||||
- 前端任何入口只展示这 3 个可选项;
|
||||
- 服务端只允许为这 3 个正式、已发布版本创建项目工作流实例。
|
||||
|
||||
后台可以保留历史定义和草稿以满足审计,但必须标记为 `retired` 或 `project_selectable=false`,不能继续出现在项目目录中。不能仅靠前端白名单隐藏,因为当前设置服务会枚举数据库里全部有发布版本的定义。[^settings-all-definitions]
|
||||
|
||||
### 2.2 商务对接流程:7 个文档,3 个阶段
|
||||
|
||||
沿用系统已经形成的 V0.1 / V0.5 / V1.0 业务阶段和模板归属,目标定义如下。当前模板工厂已按 `1 + 5 + 1` 归档这 7 个文档。[^template-stage-map]
|
||||
|
||||
| 阶段 | 顺序 | task key | 正式文档名 | 默认状态 | 阶段门禁 |
|
||||
|---|---:|---|---|---|---|
|
||||
| V0.1 需求摸底 | 10 | `intake` | 用户初始需求收集表 | 启用 | 启用时必须批准 |
|
||||
| V0.5 方案与可行性 | 20 | `research` | 调研报告 | 启用 | 启用时必须批准 |
|
||||
| V0.5 方案与可行性 | 21 | `feasibility_dev` | 设计开发可行性评估报告 | 启用 | 启用时必须批准 |
|
||||
| V0.5 方案与可行性 | 22 | `feasibility_reg` | 注册路径可行性评估报告 | 启用 | 启用时必须批准 |
|
||||
| V0.5 方案与可行性 | 23 | `user_requirements` | 用户需求表 | 启用 | 启用时必须批准 |
|
||||
| V0.5 方案与可行性 | 24 | `prelim_design` | 系统初步设计方案 | 启用 | 启用时必须批准 |
|
||||
| V1.0 商务报价 | 30 | `cdo_quote` | CDO 报价单 | 启用 | 启用时必须批准 |
|
||||
|
||||
当前后端商务阶段只执行 `intake`、`research`、`feasibility_reg`、`prelim_design`、`cdo_quote` 五项,正好缺少另外两项,必须同步补齐阶段执行映射和 executor 注册。[^biz-stage-five][^executor-missing]
|
||||
|
||||
### 2.3 智能产品经理流程
|
||||
|
||||
| 阶段 | task key | 唯一输出文档 | 默认状态 | 门禁 |
|
||||
|---|---|---|---|---|
|
||||
| 系统需求基线 | `system_reqs` | 系统需求规格书 | 启用 | 文档批准后,创建者确认完成工作流 |
|
||||
|
||||
### 2.4 智能测试工程师流程
|
||||
|
||||
| 阶段 | task key | 唯一输出文档 | 默认状态 | 门禁 |
|
||||
|---|---|---|---|---|
|
||||
| 系统验证策划 | `test_manager` | 系统验证方案及计划 | 启用 | 文档批准后,创建者确认完成工作流 |
|
||||
|
||||
**智能产品经理流程和智能测试工程师流程相互解耦。** 智能测试工程师流程不再要求项目曾运行智能产品经理流程,也不再要求必须存在该流程输出的《系统需求规格书》。它直接从当前项目可用于工作流的对话、文档、上传材料、项目事实和决策记录中提取需求及验证依据,独立生成《系统验证方案及计划》。
|
||||
|
||||
如果项目中恰好存在已批准的《系统需求规格书》,它只是项目输入集合中的一项高权威来源,不是启动前置条件,也不产生流程级耦合。当前 manifest、执行服务、血缘逻辑和前端提示仍硬编码了这一依赖,整改时必须一起删除。[^test-upstream][^test-hard-dependency]
|
||||
|
||||
### 2.5 两个智能工作流的统一项目上下文输入
|
||||
|
||||
智能产品经理和智能测试工程师使用同一个“项目上下文快照服务”,但采用不同的分析目标和输出模板:
|
||||
|
||||
| 输入类别 | 纳入内容 | 建议权威等级 |
|
||||
|---|---|---|
|
||||
| 项目事实 | 项目名称、客户、产品类型、预期用途、目标市场、结构化事实黑板 | 已确认事实 |
|
||||
| 项目决策 | 创建者确认事项、里程碑决策、已关闭的待确认项 | 已确认决策 |
|
||||
| 项目文档 | 当前有效版本的受控文档、项目共享文档、上传材料 | 按批准状态和来源分级 |
|
||||
| 项目对话 | 所有已进入项目共享知识边界的成员对话及其附件 | 原始沟通证据 |
|
||||
| 历史输出 | 商务、产品、测试或自由任务形成的项目交付物 | 按状态和版本分级 |
|
||||
| 知识依据 | 系统检索到的法规、标准和内部知识库命中 | 外部参考依据 |
|
||||
|
||||
这里的“所有”是指 **当前项目知识边界内全部有资格被工作流使用的内容**,不是把数据库中所有原文无差别拼接到一次模型调用中。建议遵循以下规则:
|
||||
|
||||
1. 只纳入当前项目,绝不跨项目召回;
|
||||
2. 私人草稿、个人私聊只有在明确“共享到项目”后才进入项目级工作流输入,避免流程执行扩大原有可见范围;
|
||||
3. 任务启动时生成不可变 `project_context_snapshot`,记录截止时间、来源 ID、版本、内容 hash、权限判定和引用位置;
|
||||
4. 全量来源先建立清单,再按任务目标检索相关片段;已确认事实和已批准文档必须进入固定核心上下文,普通对话按相关性分批读取;
|
||||
5. 冲突时不静默覆盖,优先级建议为:创建者确认事实/决策 > 当前已批准文档 > 用户上传原始材料 > 里程碑记录 > 普通项目对话 > 智能体历史总结;
|
||||
6. 输出必须带 source manifest。智能测试工程师需在唯一输出文档内部生成“需求/风险—测试项—来源”追溯表,不额外创建第二个受控输出文档;
|
||||
7. 任务运行后项目来源发生变化时,依据被引用来源的 hash 判断 `input_changed/stale`,而不是只监听《系统需求规格书》。未被本次输出引用的无关对话变化不应把文档误标为 stale。
|
||||
|
||||
现有 Squad 工作区已经支持 project context、materials、prior docs、knowledge hits 等输入槽位,也会建立带权威等级的 context 索引;产品经理还已有从项目事实和里程碑生成输入材料的局部实现。因此应把这些能力上移为通用项目上下文快照服务,而不是为测试流程继续维护单一 SRS 特例。[^context-input-foundation]
|
||||
|
||||
## 3. 不可违反的业务规则
|
||||
|
||||
### 3.1 选择、启动和切换
|
||||
|
||||
1. 只有项目创建者可以选择、配置、激活、推进或受控终止项目工作流。
|
||||
2. 一个项目同一时刻最多只能有一个 live 实例。
|
||||
3. 在 `active`、`awaiting_stage_confirmation` 或 `termination_requested` 状态下,不允许选择或切换工作流。
|
||||
4. “切换工作流”不是修改当前实例的 `workflow_key`,而是当前实例 `completed` 或 `terminated` 后创建一个新的 planning 实例。
|
||||
5. 激活时冻结工作流版本、阶段、文档开关、模板版本、执行器、质量门禁和三权责任人。运行中不可静默修改。
|
||||
6. 管理员不因系统身份自动替代项目创建者执行推进;如以后引入 break-glass,必须单独设计理由、再认证和审计,且不能代替文档签署人。
|
||||
|
||||
目标状态机:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> planning: 创建者选择并配置
|
||||
planning --> active: 预览后确认激活
|
||||
active --> awaiting_stage_confirmation: 当前阶段所有启用文档已批准
|
||||
awaiting_stage_confirmation --> active: 创建者确认进入下一阶段
|
||||
awaiting_stage_confirmation --> completed: 创建者确认完成最后阶段
|
||||
active --> termination_requested: 创建者申请终止
|
||||
termination_requested --> terminated: 二次确认并记录原因
|
||||
completed --> planning: 创建下一工作流实例
|
||||
terminated --> planning: 创建下一工作流实例
|
||||
```
|
||||
|
||||
数据库已经为一个 planning 实例和一个 live 实例设置了部分唯一索引,也预留了 `awaiting_stage_confirmation`、`terminated` 等状态,适合沿此模型完善,不必另造一套表。[^instance-schema]
|
||||
|
||||
### 3.2 文档启用与禁用
|
||||
|
||||
项目创建者可以在 planning 状态逐文档启用或禁用。严格语义如下:
|
||||
|
||||
| 文档状态 | 三权配置 | 可创建/启动编制 | 可提交审核 | 可审核 | 可批准 | 是否计入阶段门禁 |
|
||||
|---|---|---:|---:|---:|---:|---:|
|
||||
| enabled | 作者、审核人、批准人均必填且互斥 | 是,仅作者或明确执行人 | 是,仅作者 | 是,仅审核人 | 是,仅批准人 | 是 |
|
||||
| disabled | 必须为空 | 否 | 否 | 否 | 否 | 否 |
|
||||
|
||||
关键约束:
|
||||
|
||||
- `default_enabled` 只表示默认值,不表示不可关闭;
|
||||
- `blocking_when_enabled=true` 表示文档一旦启用,未批准就阻断阶段;
|
||||
- 新增明确字段 `creator_configurable=true/false`,不要继续混用现有 `required`、`blocking`、`default_enabled` 三个布尔值表达四种含义;
|
||||
- 禁用后实例状态写为 `skipped_disabled`,不创建 DocGov 文档、不生成三权行,也不允许通过 task key、对话、SSE、Agent tool 或旧 API 旁路启动;
|
||||
- 对禁用文档发起动作时统一返回 `409 DOC_TASK_DISABLED`;对启用文档但责任人不匹配返回 `403 DOC_DUTY_FORBIDDEN`;
|
||||
- 激活计划必须至少包含一个启用文档。这样一文档流程仍可在配置时关闭唯一文档,但关闭后不能激活一个没有产出的空工作流。
|
||||
|
||||
现有数据结构已经能表达 `enabled` 和三权,且持久化时会跳过禁用文档的职责写入;可复用这部分。问题在于定义校验把 required/blocking 文档一律视为不可关闭,需要先修正语义。[^plan-structure][^duty-write-enabled-only]
|
||||
|
||||
### 3.3 阶段完成和推进
|
||||
|
||||
阶段就绪的唯一业务判定应为:
|
||||
|
||||
```text
|
||||
stage_ready = 当前阶段处于 active
|
||||
AND 当前阶段至少有一个 enabled 文档
|
||||
AND 每个 enabled 文档的当前受控版本都为 approved
|
||||
AND 没有正在执行、待审核、待批准或 stale 的同任务实例
|
||||
```
|
||||
|
||||
推进动作必须满足:
|
||||
|
||||
- 服务端在同一数据库事务中锁定 workflow instance 和 stage instance;
|
||||
- 重新计算门禁,不能只信几秒前的 readiness 响应;
|
||||
- 校验操作者仍是项目创建者;
|
||||
- 校验 `expected_config_revision` 和幂等键;
|
||||
- 只改变阶段和实例状态,绝不把文档“补写”为 approved;
|
||||
- 进入下一启用阶段;若没有下一阶段,则把实例标为 completed,并把项目切回“可配置下一个工作流”的状态;
|
||||
- 同事务关闭对应 `stage_advance_request`,写审计和 outbox 事件。
|
||||
|
||||
当前 readiness 已经忽略禁用任务、检查启用必需文档是否批准,并限制创建者推进,这一骨架可以保留;但它按 `project_id + task_key` 汇总文档状态,仍需升级到 `doc_task_instance_id + document_version_id`,避免跨阶段或重复实例串线。[^readiness-current][^approval-key-too-wide]
|
||||
|
||||
### 3.4 主动提醒和对话推进
|
||||
|
||||
系统在 readiness 从 false 变为 true 时生成一次 `stage.ready_to_advance` 事件,并只通知项目创建者。已有 outbox、站内通知、去重键以及 24 小时再次提醒机制可以复用。[^notify-ready][^notify-reminder]
|
||||
|
||||
建议闭环:
|
||||
|
||||
1. 最后一份启用文档批准;
|
||||
2. 事务后事件处理器重新计算 readiness;
|
||||
3. 实例进入 `awaiting_stage_confirmation`;
|
||||
4. 创建者收到站内消息和可操作确认卡:阶段名、启用/已批准文档清单、下一阶段或“完成工作流”;
|
||||
5. 创建者点击按钮,或在项目对话中说“推进到下一阶段 / 确认推进”;
|
||||
6. 两种入口都调用同一个 `AdvanceStage` 应用服务;
|
||||
7. 成功后通知状态改为 acted,推进请求改为 confirmed;若条件在确认前失效,则返回最新阻断项并把旧请求标为 superseded。
|
||||
|
||||
当前前端已经每 15 秒拉取通知并显示“确认推进”按钮,但对话入口仍走旧的 `bizdev.ExecuteStage`,所以需要把自然语言意图解析与执行彻底分开:识别器只产生命令,实例服务才拥有推进权。[^stage-banner][^dialogue-old-advance]
|
||||
|
||||
## 4. 当前系统与目标的差距
|
||||
|
||||
### 4.1 定义和目录
|
||||
|
||||
| 编号 | 当前事实 | 风险 | 整改 |
|
||||
|---|---|---|---|
|
||||
| WF-CAT-01 | Bootstrap 发布 5 个工作流 | 项目会看到目标外流程 | 只发布三项;其余退役且不可选 |
|
||||
| WF-CAT-02 | 设置服务返回所有有发布版的定义 | 测试/历史流程进入项目 | 增加 `project_selectable`,查询端白名单 + 状态双重校验 |
|
||||
| WF-CAT-03 | 开发库有 92 个定义,88 个 key 为 `pg_*` 或 `test_*` | 测试污染业务目录 | 测试强制独立数据库/schema,fixture 必须清理 |
|
||||
| WF-DEF-01 | 三个正式 key 当前均为 schema v1 单阶段 | 实际运行不是目标结构 | 以新版本发布 schema v2/v3,禁止覆盖旧版本 |
|
||||
| WF-DEF-02 | `main.v2.json` 只有 5 个文档 | 商务流程缺 2 个输出 | 补齐 7 个并增加 executor、模板和质量门禁校验 |
|
||||
| WF-DEF-03 | v2 manifest 未进入 bootstrap | 仓库文件与运行数据库不一致 | 建立 manifest 迁移器,按 hash 创建并发布新版本 |
|
||||
| WF-DEF-04 | seed 发现任何 published 就跳过 | 永远停留旧版本 | 按内容 hash 和目标版本升级,写版本迁移审计 |
|
||||
| WF-DEF-05 | DBCatalog 压扁完整定义 | 多阶段配置不能驱动运行 | 删除生产 flatten 路径,运行只读取冻结实例 |
|
||||
| WF-DEF-06 | 测试流程声明 product_manager 上游,执行服务又硬查 approved SRS | 两个智能工作流不能独立运行 | 删除流程级依赖;改用统一项目上下文快照和多来源血缘 |
|
||||
|
||||
### 4.2 项目实例和生命周期
|
||||
|
||||
| 编号 | 当前事实 | 风险 | 整改 |
|
||||
|---|---|---|---|
|
||||
| WF-INS-01 | planning / active 和唯一 live 骨架已存在 | 可复用但未闭环 | 扩展 awaiting/completed/terminated 完整转换 |
|
||||
| WF-INS-02 | 完成最后阶段只更新实例 | 项目仍为 active,无法配置下一流程 | 同事务更新项目可选择状态并清空 current live 指针 |
|
||||
| WF-INS-03 | 无受控终止 API | 异常流程永久锁死或只能改库 | 增加申请、影响预览、创建者二次确认和终止原因 |
|
||||
| WF-INS-04 | 激活 token 明文保存,消费与激活分事务 | 失败后 token 已失效或可泄露 | 只存 hash,并在激活事务内锁定、消费 |
|
||||
| WF-INS-05 | 冻结子任务只写 key/enabled/status | executor、模板、质量门禁仍依赖可变定义 | 激活时把完整运行元数据写入实例表并以实例表为权威 |
|
||||
|
||||
数据库已添加 executor/template/quality gate 列,但当前实例写入 SQL 仍只插入 task key、enabled 和 status,证明冻结快照尚未真正成为执行权威。[^instance-runtime-metadata]
|
||||
|
||||
### 4.3 文档、三权和运行时授权
|
||||
|
||||
| 编号 | 当前事实 | 风险 | 整改 |
|
||||
|---|---|---|---|
|
||||
| WF-DOC-01 | 启用文档要求三权且互斥 | 基础规则正确 | 再校验三人均为 active 项目成员且账户有效 |
|
||||
| WF-DOC-02 | 禁用文档不会写三权 | 基础持久化正确 | 增加 `skipped_disabled` 和全入口拒绝 |
|
||||
| WF-DOC-03 | 访问过滤按 task key 判断 | 同 key 重复实例可能串权 | 所有动作使用 `doc_task_instance_id` |
|
||||
| WF-DOC-04 | 无 live 实例时访问过滤默认不限制 | 完成后旧任务入口可能恢复可用 | 正式项目按治理模式 fail closed;legacy 仅限显式迁移标记 |
|
||||
| WF-DOC-05 | 运行入口仍接受 task key 并查扁平目录 | 可能绕过阶段和冻结绑定 | 请求只传 doc task instance id,服务端解析 executor/template/duty |
|
||||
| WF-DOC-06 | DocGov 状态机可验证具体审核/批准人 | 可复用 | 文档必须外键绑定 doc task instance 和版本 |
|
||||
|
||||
现有阶段访问代码确实会从 live 快照中排除禁用任务,这是可保留的基础;但当没有 live 实例或实例 completed 时会返回 unrestricted,因此不能把它视为禁用文档全生命周期的完整保障。[^stage-access]
|
||||
|
||||
### 4.4 前端、通知和对话
|
||||
|
||||
| 编号 | 当前事实 | 风险 | 整改 |
|
||||
|---|---|---|---|
|
||||
| WF-UI-01 | 旧切换器硬编码三项,但名称不一致 | 用户认知混乱 | 统一为三个正式名称,数据来自服务端目录 |
|
||||
| WF-UI-02 | 新治理 API 失败时回退旧直接切换 UI | 可重新打开不合规路径 | 删除回退;治理不可用时只读并明确报错 |
|
||||
| WF-UI-03 | 旧切换在版本冲突后自动重试 | 可能覆盖用户最新选择 | 展示冲突并要求重新确认,不自动提交高风险操作 |
|
||||
| WF-UI-04 | 项目设置只显示 stage/task key | 不利于业务确认 | 显示正式阶段名、文档名、启用状态、三权和影响摘要 |
|
||||
| WF-UI-05 | live 配置缺少完整只读审计视图 | 创建者不清楚冻结内容 | 展示版本、hash、激活人/时间、所有 enabled/disabled 和职责 |
|
||||
| WF-NOTIFY-01 | readiness 通知和 24h 提醒已存在 | 基础可复用 | 增加状态转换、已读/已处理、失效和重算 |
|
||||
| WF-DLG-01 | 对话推进旧商务阶段 | 可越过新实例门禁 | 对话调用同一实例 AdvanceStage command |
|
||||
| WF-CTX-01 | 产品经理仅在无材料时拼装部分项目事实;测试工程师只注入 SRS | “全部项目内容”没有统一、可复现的输入语义 | 建立项目上下文快照、来源清单、权限过滤、冲突优先级和 hash 血缘 |
|
||||
|
||||
旧前端切换器在治理不可用时仍调用 `/active-workflow`,并在冲突后自动取新版本再次切换;这两个行为都应删除。[^legacy-switch-ui] 旧服务端路由在迁移完成后应返回 `410 WORKFLOW_SWITCH_API_RETIRED`,而不是继续作为备用入口。[^legacy-route]
|
||||
|
||||
### 4.5 开发数据库现场快照
|
||||
|
||||
2026-09-12 对当前 `shuimu-context-pg-dev / agent_system_dev` 做只读查询得到:
|
||||
|
||||
```text
|
||||
workflow_definitions = 92
|
||||
published workflow versions = 92
|
||||
main = version 1, schema 1, 1 stage
|
||||
product_manager = version 1, schema 1, 1 stage
|
||||
test_manager = version 1, schema 1, 1 stage
|
||||
project_workflow_instances: active 32, completed 47
|
||||
projects.lifecycle_status: active 97, planning 51
|
||||
completed 实例已存在、无 live 实例但项目仍为 active:47 个
|
||||
测试命名定义(pg_* / test_*):88 个
|
||||
```
|
||||
|
||||
这些数字主要反映当前开发环境和集成测试污染,不能直接当成生产数据;但它们证明目录查询没有隔离正式定义与测试定义,也直接复现了“实例已完成而项目仍 active”的生命周期断点。PG 测试在未设置 `TEST_DATABASE_URL` 时默认连接开发库,部分定义发布测试又没有清理工作流定义,因此必须纳入整改。[^test-db-default][^test-definition-no-cleanup]
|
||||
|
||||
## 5. 目标技术模型
|
||||
|
||||
### 5.1 单一运行权威
|
||||
|
||||
```text
|
||||
Published Workflow Version
|
||||
│ 创建 planning plan
|
||||
▼
|
||||
Project Workflow Instance + immutable config snapshot
|
||||
│ 激活时物化
|
||||
├── Stage Instances
|
||||
│ └── Doc Task Instances
|
||||
│ ├── frozen executor/template/quality gate
|
||||
│ ├── duty assignments
|
||||
│ ├── controlled document versions
|
||||
│ └── task runs
|
||||
├── Stage Advance Requests / Notifications
|
||||
└── Audit / Outbox Events
|
||||
```
|
||||
|
||||
激活后,任何运行请求不得再从“最新发布定义”、前端 task key 或 legacy catalog 推导行为。最新定义只用于创建未来实例;已运行实例永远引用自己的冻结数据。
|
||||
|
||||
### 5.2 定义 schema 建议
|
||||
|
||||
文档任务应至少明确以下字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "research",
|
||||
"title": "调研报告",
|
||||
"default_enabled": true,
|
||||
"creator_configurable": true,
|
||||
"blocking_when_enabled": true,
|
||||
"executor_key": "bizdev.research.v1",
|
||||
"quality_gate_key": "quality.generic.v1",
|
||||
"template": {"asset_key": "research", "version": 1},
|
||||
"output_doc_type": "research",
|
||||
"output_doc_title": "调研报告"
|
||||
}
|
||||
```
|
||||
|
||||
发布校验必须增加:
|
||||
|
||||
- workflow key 属于三个正式 key 之一,且对外名称准确;
|
||||
- 阶段 key、position、任务 key 均唯一且非空;
|
||||
- 每个阶段至少一个文档任务;
|
||||
- executor、quality gate 和 ready 模板版本全部存在;
|
||||
- 三个正式流程精确满足 7 / 1 / 1 文档清单;
|
||||
- 三个正式工作流均不声明流程级 `required_upstream_workflow`;
|
||||
- 项目上下文输入策略、来源权限和冲突优先级完整;
|
||||
- 禁用策略、完成策略和参与策略完整;
|
||||
- 发布后版本不可原地修改。
|
||||
|
||||
当前 v2 校验只检查 schema 版本、阶段位置、executor/quality gate 注册和输出类型,尚不足以守住上述业务契约。[^validator-v2]
|
||||
|
||||
### 5.3 数据结构增量
|
||||
|
||||
优先扩展现有表,不重复建模:
|
||||
|
||||
- `workflow_definitions`:增加 `project_selectable`、`catalog_order`、`official_code`;
|
||||
- `workflow_versions.definition_json`:采用新禁用语义并保留版本 hash;
|
||||
- `project_workflow_instances`:增加 `completed_at/by`、`terminated_at/by/reason`、`previous_instance_id`;
|
||||
- `project_stage_instances`:增加 `ready_at`、`completed_at/by`;
|
||||
- `project_doc_task_instances`:持久化 `executor_key`、`quality_gate_key`、模板 asset/version、output type/title;禁用任务状态为 `skipped_disabled`;
|
||||
- `documents`:增加 `doc_task_instance_id`,受控文档版本唯一绑定;
|
||||
- `project_context_snapshots`:记录项目、任务、截止时间、汇总 hash、创建人和冻结状态;
|
||||
- `project_context_snapshot_sources`:逐项记录 source type/id/version/hash、权限范围、权威等级、是否实际引用;
|
||||
- `task_runs`:增加 `workflow_instance_id`、`stage_instance_id`、`doc_task_instance_id`、`context_snapshot_id`;
|
||||
- `document_lineages`:从单一“上游 SRS”扩展为多来源 lineage,允许对话、材料、事实、决策和文档版本作为来源;
|
||||
- `stage_advance_requests`:保留 readiness revision,补 `idempotency_key`、`superseded_at`;
|
||||
- 审计事件:至少记录 plan saved、activated、document disabled/enabled、duty assigned、stage ready、stage advanced、workflow completed/terminated。
|
||||
|
||||
### 5.4 API 收敛
|
||||
|
||||
建议正式接口:
|
||||
|
||||
| 方法与路径 | 用途 | 关键约束 |
|
||||
|---|---|---|
|
||||
| `GET /api/v1/workflows/catalog` | 返回严格三项正式目录 | 只含 project_selectable + published |
|
||||
| `GET /api/v1/projects/{id}/settings` | 规划或冻结配置视图 | 项目访问控制 |
|
||||
| `PUT /api/v1/projects/{id}/workflow-plan` | 选择流程、开关文档、设置三权 | 仅创建者、仅 planning、乐观锁 |
|
||||
| `POST /api/v1/projects/{id}/activation-preview` | 完整影响与校验 | 无空流程、三权和上下文策略通过 |
|
||||
| `POST /api/v1/projects/{id}/workflow-instances/activate` | 冻结并激活 | 创建者二次确认、原子 token |
|
||||
| `GET /api/v1/workflow-instances/{id}` | 运行和历史详情 | 项目 + 阶段可见性 |
|
||||
| `GET /api/v1/workflow-instances/{id}/stages/{key}/readiness` | 门禁详情 | 返回所有启用文档状态 |
|
||||
| `POST /api/v1/workflow-instances/{id}/stages/{key}/advance` | 创建者推进或完成 | 事务内重算、幂等 |
|
||||
| `POST /api/v1/workflow-instances/{id}/termination-preview` | 终止影响 | 未决任务、文档和通知清单 |
|
||||
| `POST /api/v1/workflow-instances/{id}/terminate` | 受控终止 | 创建者、原因、二次确认 |
|
||||
| `POST /api/v1/doc-task-instances/{id}/runs` | 启动编制 | enabled + active stage + duty |
|
||||
|
||||
旧 `/projects/{id}/active-workflow` 和依赖扁平 workflow key 的 run 接口先记录迁移告警,完成客户端切换后返回 410。
|
||||
|
||||
## 6. 实施顺序
|
||||
|
||||
### Phase 0:冻结错误扩散和数据盘点
|
||||
|
||||
1. 给项目目录增加服务端正式白名单,立即只暴露三个目标 key。
|
||||
2. 禁止测试默认连接开发库;CI 必须显式提供隔离的 `TEST_DATABASE_URL`。
|
||||
3. 备份并分类 92 个定义及其引用:正式、历史、测试、被实例引用。
|
||||
4. 未被任何实例引用的测试定义在开发环境清理;被引用定义只退役,不物理删除。
|
||||
5. 修复开发环境中 completed instance 与 project lifecycle 不一致的数据,但先输出 dry-run 清单。
|
||||
|
||||
### Phase 1:发布三个唯一正式定义
|
||||
|
||||
1. 修订三个 manifest 的正式名称与 schema;商务流程补齐 7 个文档。
|
||||
2. 为 `feasibility_dev` 和 `user_requirements` 注册专用 executor,或明确映射到通用任务 executor;禁止使用含混的法规 executor 代替。
|
||||
3. 从 `test_manager` manifest、默认目录和校验模型中删除 `required_upstream_workflow=product_manager`,使三个流程在流程级完全独立。
|
||||
4. 增加严格发布校验和 7 / 1 / 1 契约测试。
|
||||
5. 实现 hash 驱动的版本升级:已有 v1 时创建 v2/v3,而不是退出或覆盖。
|
||||
6. `medical_device_development`、`non_medical_software` 及其他定义全部 `project_selectable=false` 并退役。
|
||||
|
||||
### Phase 2:补齐实例状态机和禁用语义
|
||||
|
||||
1. 重构 plan validator:creator-configurable 文档可关闭;启用文档三权必填;空工作流不可激活。
|
||||
2. 校验三权人员为有效项目成员、账户有效且三权互斥。
|
||||
3. 激活时完整物化运行元数据,以实例为唯一权威。
|
||||
4. 阶段推进事务内重算门禁,删除“推进时强制批准文档”的 SQL。
|
||||
5. 完成最后阶段时同步更新项目状态,使其可创建下一 planning 实例。
|
||||
6. 实现受控终止,保证 live 实例不会永久锁住项目。
|
||||
|
||||
### Phase 3:运行、文档治理和权限合流
|
||||
|
||||
1. 建立通用项目上下文快照服务,覆盖项目事实、项目级对话、文档、材料、决策、历史输出和知识命中。
|
||||
2. 产品经理和测试工程师分别从同一快照服务取数;删除测试任务中“查找已批准 system_reqs,否则拒绝”的特例。
|
||||
3. 所有任务启动改用 `doc_task_instance_id`;服务端解析 task/executor/template/stage/duty/context snapshot。
|
||||
4. 文档创建、查看、编辑、提交、审核、批准均校验同一 doc task instance。
|
||||
5. disabled、非当前阶段、非责任人、实例非 live 均 fail closed。
|
||||
6. SSE、异步 task run、恢复/取消、RAG 检索、Agent tools 使用同一策略决策。
|
||||
7. 审批回调按具体文档版本更新具体 doc task instance,不再按项目 + task key 批量更新。
|
||||
8. 把 SRS 单来源 lineage 改成 source manifest 多来源血缘;只在实际引用来源变化时标记输出待复核。
|
||||
|
||||
### Phase 4:通知、对话和前端闭环
|
||||
|
||||
1. readiness 边沿触发状态和通知,补 read/acted/dismissed API。
|
||||
2. 把对话“推进/完成工作流”绑定到项目实例 command;保留明确确认卡。
|
||||
3. 项目设置只显示三项,按正式名称显示阶段和文档。
|
||||
4. active/awaiting 时显示冻结只读视图,隐藏所有切换动作。
|
||||
5. completed/terminated 后显示“配置下一个工作流”,而不是修改旧实例。
|
||||
6. 删除旧切换回退、冲突自动重试和 `WorkflowPrerequisiteBanner` 的产品经理前置提示。
|
||||
7. 在运行预览中展示项目上下文截止时间、来源数量、被排除的私有/无权内容和冲突项。
|
||||
|
||||
### Phase 5:迁移和发布
|
||||
|
||||
1. 新项目只允许使用新的三个正式版本。
|
||||
2. 尚未激活的 planning v1 计划自动重建为新版本草稿,并要求创建者重新确认三权。
|
||||
3. 已激活 v1 实例不静默改写:真实业务实例由创建者选择继续兼容完成或受控终止后重建;开发/测试垃圾实例按确认后的清理脚本处理。
|
||||
4. 先 shadow 计算新旧 readiness 差异,再开启新推进服务。
|
||||
5. 通过全套验收后关闭 legacy route 和 flatten catalog。
|
||||
|
||||
## 7. 验收标准
|
||||
|
||||
### 7.1 目录和定义
|
||||
|
||||
- 任意项目、任意普通用户或管理员在项目选择页都只能看到 3 个工作流。
|
||||
- 正式名称精确为“商务对接流程 / 智能产品经理流程 / 智能测试工程师流程”。
|
||||
- 定义快照精确为 7 / 1 / 1;缺一、多一、重复 key、模板未 ready 或 executor 未注册均无法发布。
|
||||
- 三个正式定义均没有流程级上游依赖;产品经理和测试工程师可被分别独立选择和运行。
|
||||
- 服务重启、数据库迁移和旧数据存在时,目录结果仍稳定为三项。
|
||||
|
||||
### 7.2 选择和冻结
|
||||
|
||||
- 只有项目创建者可保存、激活和推进;普通成员、系统管理员默认均被拒绝。
|
||||
- live 实例存在时,UI、API 和对话三个入口均不能切换。
|
||||
- 工作流完成或受控终止后,创建者可以配置下一实例;旧实例保持只读可追溯。
|
||||
- 两个浏览器同时配置或推进时只有一个成功,另一个收到版本冲突并重新确认。
|
||||
|
||||
### 7.3 文档开关和三权
|
||||
|
||||
- 启用文档缺任一职责、职责重复、责任人非 active 项目成员时不能激活。
|
||||
- 禁用文档没有职责行、没有受控文档、没有运行按钮,也不能通过手工 API、SSE 或对话启动。
|
||||
- 对禁用文档的编制、提交、审核、批准请求全部稳定返回 `DOC_TASK_DISABLED`。
|
||||
- 再启用只允许发生在 planning;激活后不能原地改变。
|
||||
|
||||
### 7.4 阶段门禁和提醒
|
||||
|
||||
- 当前阶段 N 个启用文档中任一未批准,创建者按钮和对话推进均被阻断并返回清单。
|
||||
- 全部批准后只产生一次首提醒;24 小时未处理才产生一次升级提醒。
|
||||
- readiness 后文档被驳回或标 stale 时,旧推进请求失效,确认动作不能成功。
|
||||
- 推进事务不会修改任何文档审批状态。
|
||||
- 最后一阶段确认后实例为 completed,项目立即可配置下一流程。
|
||||
|
||||
### 7.5 安全、恢复和真实链路
|
||||
|
||||
- 跨项目、非成员、非职责人、未来阶段成员、已退出成员全部有服务端负例。
|
||||
- API、SSE、异步任务、断线恢复、搜索、导出、RAG 和 Agent tool 的判定一致。
|
||||
- 服务重启后能恢复 live 实例、当前阶段、禁用状态、职责和 pending 推进请求。
|
||||
- 使用真实 PostgreSQL 和真实 PI Agent 分别跑完商务 7 文档、产品 1 文档、测试 1 文档链路。
|
||||
- 项目从未运行产品经理流程且不存在 SRS 时,测试工程师仍可依据项目对话、文档和材料成功生成唯一测试方案;输出包含逐项来源追溯和待确认清单。
|
||||
- 项目已有 SRS 时,该文档被当作高权威来源纳入,但移除它不会导致工作流定义级依赖错误;是否需要重新生成由本次 source manifest 判断。
|
||||
- 项目私聊/个人草稿未共享时不进入上下文;共享后可被新快照发现。跨项目内容在检索和快照层都有负例。
|
||||
- 同一组项目输入分别启动产品经理和测试工程师时,两者快照可复现、来源清单一致,输出目标和模板不同。
|
||||
- 测试结束后业务数据库中不残留 `pg_*`、`test_*` 定义或测试项目。
|
||||
|
||||
## 8. 已确认的业务决策及实施解释
|
||||
|
||||
2026-09-12 已确认以下决策,后续实现和验收以此为准:
|
||||
|
||||
1. **允许关闭单文档流程的唯一文档,但空工作流不能激活。** 配置可以保存,激活预览必须明确阻断并提示重新启用文档或选择其他工作流。
|
||||
2. **智能产品经理和智能测试工程师解耦。** 两者都直接使用当前项目知识边界内的对话、文档、材料、事实和决策。任何一方的产出都不是另一方的启动前置;已有 SRS 仅作为高权威输入来源。
|
||||
3. **开放项目创建者受控终止工作流。** 必须二次确认、填写原因、处理或取消在途任务并形成审计;completed 和 terminated 都允许创建下一工作流实例,但历史含义必须区分。
|
||||
|
||||
这些决策合理且彼此一致。第 2 项的实施建议是“流程解耦、数据可组合、来源可追溯”,而不是取消质量控制:测试工程师必须自己从项目上下文抽取需求和风险,生成文档内追溯矩阵,并将缺少判据的内容列为待确认,不能因为没有 SRS 就编造需求。
|
||||
|
||||
商务流程按 7 个文档落地、系统只暴露三个正式流程、运行中不可切换、阶段推进必须由创建者确认、禁用文档不得参与任何编审批动作,也均为已确认要求。
|
||||
|
||||
## 9. 建议的实施交付拆分
|
||||
|
||||
建议按以下 8 个可独立评审的变更集提交,避免一次大改难以回滚:
|
||||
|
||||
1. 正式目录隔离与测试数据库隔离;
|
||||
2. 三个正式 manifest、严格 validator 和版本升级器;
|
||||
3. planning 配置、文档开关和成员/三权校验;
|
||||
4. 激活冻结与完整实例物化;
|
||||
5. doc task instance 驱动的执行、DocGov 和统一授权;
|
||||
6. 原子 readiness / advance / complete / terminate 状态机;
|
||||
7. 通知、对话命令与前端只读/下一流程体验;
|
||||
8. 数据迁移、兼容退出、真实 PG/PI Agent E2E 和发布门禁。
|
||||
|
||||
每个变更集都应包含正向测试、越权负例、并发负例和重启恢复验证。只有第 8 项完成后,才应删除旧兼容路径并宣布三工作流治理正式生效。
|
||||
|
||||
## 10. 来源与证据
|
||||
|
||||
[^biz-seven-test]: `web/src/engine/templateFactory.test.ts:8-33`,测试精确断言 7 个任务键;读取于 2026-09-12。
|
||||
[^biz-seven-backend]: `internal/squad/service.go:128-138`,后端标准任务目录包含 7 个商务任务及产品、测试任务;读取于 2026-09-12。
|
||||
[^biz-seven-report]: `.doc/test-reports/2026-09-08-project-init-template-cloning-test-report.md:12-25,51-60`,历史专项测试把商务全生命周期固定为 7 个受控交付物;读取于 2026-09-12。
|
||||
[^bootstrap-five]: `internal/workflowdef/bootstrap.go:63-74,78-115`,启动种子包含三个旧流程及两个额外行业流程;读取于 2026-09-12。
|
||||
[^main-v2-missing]: `internal/workflowdef/manifests/main.v2.json:1-50`,清单只定义 intake、research、feasibility_reg、prelim_design、cdo_quote;读取于 2026-09-12。
|
||||
[^manifest-loader]: `internal/workflowdef/manifest_loader.go:9-32` 仅提供嵌入读取和文件名映射;仓库检索未发现 `V2ManifestFiles` 的运行时调用;读取于 2026-09-12。
|
||||
[^seed-no-upgrade]: `internal/workflowdef/store.go:364-372`,已有任意 latest published version 时直接返回;读取于 2026-09-12。
|
||||
[^catalog-flatten]: `internal/workflowdef/catalog.go:27-41,50-82`,数据库目录将版本压为首阶段首任务;读取于 2026-09-12。
|
||||
[^plan-disable-conflict]: `internal/projectinstance/validator.go:37-90,105-139`,required 或 blocking 任务关闭时校验失败;读取于 2026-09-12。
|
||||
[^advance-forces-approved]: `internal/projectinstance/stage_store.go:71-158`,推进事务把启用任务状态强制更新为 approved;读取于 2026-09-12。
|
||||
[^project-lifecycle-gap]: `internal/projectinstance/stage_store.go:128-158` 只完成实例,`internal/projectinstance/service.go:119-135` 又只允许 planning 项目保存下一计划;读取于 2026-09-12。
|
||||
[^dialogue-old-advance]: `internal/coordinator/engine.go:672-811`,对话推进调用 `bizdevSvc.ExecuteStage` 并直接改变旧成熟度上下文;读取于 2026-09-12。
|
||||
[^settings-all-definitions]: `internal/projectinstance/service.go:94-113`,项目设置枚举全部有 latest published version 的定义;读取于 2026-09-12。
|
||||
[^template-stage-map]: `web/src/engine/templateFactory.ts:37-39,87-89,158-160,228-230,286-288,331-333,392-394`,7 个商务模板当前归属为 V0.1 一项、V0.5 五项、V1.0 一项;读取于 2026-09-12。
|
||||
[^biz-stage-five]: `internal/bizdev/service.go:204-223`,旧商务阶段仅映射 1 + 3 + 1 个任务;读取于 2026-09-12。
|
||||
[^executor-missing]: `internal/workflow/registry.go:5-15`,商务 executor 缺少 feasibility_dev 和 user_requirements;读取于 2026-09-12。
|
||||
[^test-upstream]: `internal/workflowdef/manifests/test_manager.v2.json:1-23`,测试流程声明 product_manager 前置依赖;读取于 2026-09-12。
|
||||
[^test-hard-dependency]: `internal/bizdev/service.go:349-380,673-687`,测试任务硬查同项目 approved SRS、自动注入并记录单一 SRS 血缘;读取于 2026-09-12。
|
||||
[^context-input-foundation]: `internal/squad/service.go:35-55`、`internal/squad/workspace.go:262-408` 和 `internal/bizdev/service.go:250-294`,现有运行参数及工作区已支持项目、材料、前序文档、知识和部分项目事实输入;读取于 2026-09-12。
|
||||
[^instance-schema]: `deploy/postgres/goose/00017_2026-09-12-project-workflow-instances.sql:13-52`,实例状态和 one planning/one live 唯一索引;读取于 2026-09-12。
|
||||
[^plan-structure]: `internal/projectinstance/types.go:21-48`,计划已包含文档 enabled 和三权;读取于 2026-09-12。
|
||||
[^duty-write-enabled-only]: `internal/projectinstance/store.go:244-280`,禁用文档不会写职责行;读取于 2026-09-12。
|
||||
[^readiness-current]: `internal/projectinstance/gate.go:5-53` 和 `internal/projectinstance/stage_service.go:15-63`,现有门禁忽略禁用任务并限制创建者;读取于 2026-09-12。
|
||||
[^approval-key-too-wide]: `internal/projectinstance/stage_store.go:176-191`,批准同步按 project_id + task_key 更新;读取于 2026-09-12。
|
||||
[^notify-ready]: `internal/server/workflow_approval_hook.go:17-44` 和 `internal/notification/service.go:38-107`,批准回调、推进请求、outbox 与创建者通知;读取于 2026-09-12。
|
||||
[^notify-reminder]: `internal/notification/reminder.go:35-91,94-171`,24 小时提醒和 confirmed 状态;读取于 2026-09-12。
|
||||
[^stage-banner]: `web/src/components/workflow/StageAdvanceBanner.tsx:29-95,111-151`,前端轮询 readiness/通知并提供确认按钮;读取于 2026-09-12。
|
||||
[^instance-runtime-metadata]: `deploy/postgres/goose/00023_2026-09-12-instance-integrity.sql:8-11` 已添加运行元数据列,而 `internal/projectinstance/store.go:254-259` 插入时未写这些列;读取于 2026-09-12。
|
||||
[^stage-access]: `internal/projectinstance/stage_access.go:15-71,90-104`,live 实例中排除禁用任务,但无 live/completed 时不限制;读取于 2026-09-12。
|
||||
[^legacy-switch-ui]: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:16-23,38-76,173-236`,旧名称、旧直切换和冲突自动重试仍存在;读取于 2026-09-12。
|
||||
[^legacy-route]: `internal/server/server.go:157-169`,新项目实例 API 与旧 active-workflow/run API 同时暴露;读取于 2026-09-12。
|
||||
[^validator-v2]: `internal/workflowdef/validator_v2.go:9-47`,现有 v2 校验范围有限;读取于 2026-09-12。
|
||||
[^test-db-default]: `internal/projectinstance/pg_integration_test.go:19-49` 和 `internal/server/workflow_governance_pg_test.go:26-61`,未设置 TEST_DATABASE_URL 时连接本地开发库;读取于 2026-09-12。
|
||||
[^test-definition-no-cleanup]: `internal/workflowdef/publish_test.go:37-72`,发布测试创建带时间戳定义但未注册清理;读取于 2026-09-12。
|
||||
|
||||
开发数据库数字来源:2026-09-12 在本机容器内对 `workflow_definitions`、`workflow_versions`、`project_workflow_instances` 和 `projects` 执行只读聚合查询。该快照仅用于诊断当前开发环境,不代表生产环境。
|
||||
本文档已迁至 [remediation/2026-09-12-three-workflows-strict-governance-remediation.md](remediation/2026-09-12-three-workflows-strict-governance-remediation.md)。请勿在此编辑。
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
# 项目文档总地图
|
||||
|
||||
> Agent 协作纪律见仓库根 [AGENTS.md](../AGENTS.md)。
|
||||
> 当前焦点见 [ops/CURRENT.md](ops/CURRENT.md)。
|
||||
|
||||
---
|
||||
|
||||
## 文档 taxonomy(禁止随意新建路径)
|
||||
|
||||
```text
|
||||
.doc/
|
||||
README.md ← 本文件(总地图)
|
||||
status/ ← 模块/功能完成度 SSOT
|
||||
audit/ ← 问题发现与分析
|
||||
remediation/ ← 整改方案与发布缺口
|
||||
archive/ ← 历史(只增不删)
|
||||
ops/ ← 活协作(任务、交接、调研)
|
||||
system-design/ ← 模块架构深读
|
||||
adr/ ← 架构决策
|
||||
backlog/ ← 产品 backlog(非阻塞)
|
||||
test-reports/ ← 验收报告(+ assets/ 附件)
|
||||
test-fixtures/ ← 测试拓扑说明
|
||||
|
||||
仓库根(入口,非内容库)
|
||||
AGENTS.md | PROJECT.md | CLAUDE.md | CODEX.md | GEMINI.md | ANTIGRAVITY.md | KIMI.md
|
||||
```
|
||||
|
||||
**红线**:不得在 `.doc/` 根目录新建大包 Markdown;不得在 `docs/` 随意新建子目录。新文档必须落入上表之一。
|
||||
|
||||
---
|
||||
|
||||
## 快速入口
|
||||
|
||||
| 我要… | 读这里 |
|
||||
|--------|--------|
|
||||
| 当前在做什么 | [ops/CURRENT.md](ops/CURRENT.md) |
|
||||
| 模块完成度 | [status/FEATURE-MATRIX.md](status/FEATURE-MATRIX.md) |
|
||||
| 发布 blocker | [remediation/gap-matrix.md](remediation/gap-matrix.md) |
|
||||
| 审计/问题分析 | [audit/INDEX.md](audit/INDEX.md) |
|
||||
| 整改方案 | [remediation/INDEX.md](remediation/INDEX.md) |
|
||||
| 历史归档 | [archive/README.md](archive/README.md) |
|
||||
| 架构设计 | [system-design/README.md](system-design/README.md) |
|
||||
| 测试报告 | [test-reports/](test-reports/) |
|
||||
| 历史功能设计 | [archive/design/superpowers/](archive/design/superpowers/) |
|
||||
|
||||
---
|
||||
|
||||
## backlog 分工
|
||||
|
||||
| 路径 | 用途 |
|
||||
|------|------|
|
||||
| `backlog/` | 产品侧非阻塞 backlog |
|
||||
| `ops/long-term/` | Agent/工程技术债 backlog |
|
||||
|
||||
---
|
||||
|
||||
## 文档生命周期
|
||||
|
||||
```text
|
||||
audit(问题)→ remediation(方案)→ ops/short-term(任务)
|
||||
→ test-reports(验收)→ archive(关闭证据)
|
||||
```
|
||||
|
||||
状态字段:`planned | in_progress | blocked | done | cancelled`
|
||||
@@ -0,0 +1,11 @@
|
||||
# 历史归档
|
||||
|
||||
已完成、supersede 或关闭的文档证据。**禁止删除**,仅迁移至此。
|
||||
|
||||
| 子目录 | 内容 |
|
||||
|--------|------|
|
||||
| `audit/` | 已关闭审计大包 |
|
||||
| `remediation/` | 已关闭整改大包 |
|
||||
| `ops/` | done 的 short-term / checklist / handoff |
|
||||
| `design/superpowers/` | 历史功能 spec/plan |
|
||||
| `reference/` | 被 PROJECT 替代的参考长文 |
|
||||
@@ -0,0 +1,268 @@
|
||||
# Chat Agent System 功能缺陷深度审计与整改方案
|
||||
|
||||
## 执行摘要
|
||||
|
||||
系统已经具备较完整的业务原型:多轮对话、意图识别、项目工作流、智能体小队、RAG、受控文档、自由文档、长任务流、聊天历史、摘要与导出等模块均有代码和测试资产。架构方向也基本正确:对话、项目协调、执行三层分离,确定性权限和状态转换应由服务端控制。[^1]
|
||||
|
||||
但当前版本不应按“多人生产协作系统”发布。核心原因不是功能数量不足,而是四条基础链路尚未闭环:
|
||||
|
||||
1. **身份与授权链路失守**:大量业务接口不要求登录,或直接信任 `X-User-ID`、查询参数、请求体中的用户与角色;攻击者可伪造身份访问或修改会话、项目、文档、任务和资产。这与系统设计中的多用户隔离目标直接冲突,也属于典型的对象级授权缺失(BOLA/IDOR)。[^2][^3]
|
||||
2. **数据库发布链路失效**:生产 Compose 仅挂载一个明显过时的 `system_init.sql`,而新增能力依赖十余张表和多批迁移;Docker 初始化脚本又只在空数据卷首次启动时执行。当前 dev 实库检查已证实缺少工作流、自由文档等 7 张关键表及消息导出 4 个关键字段。[^4][^5][^6]
|
||||
3. **前端交付链路不完整**:生产应用镜像只编译并复制 Go 二进制,没有构建或复制 `web/dist`;服务端虽然尝试托管 SPA,但容器内没有对应资产,因此按现有 Dockerfile 部署时首页会返回 404。[^7][^8]
|
||||
4. **长任务恢复链路不持久**:任务运行和 SSE 事件只保存在进程内存中,保留时间仅一小时;进程重启后查询、重连、取消均失效。更严重的是,代码先发送 `done` 事件,再执行最终落库;最终落库失败时客户端已经把任务视为成功。[^9]
|
||||
|
||||
综合判断:系统目前处于“功能丰富的集成原型 / dev 验证阶段”,不具备生产发布条件。建议立即冻结外网暴露和 main 发布,将下述 P0 项全部关闭后再进入真实 Agent 联调。
|
||||
|
||||
## 审计范围与证据强度
|
||||
|
||||
本次覆盖 Go 后端、React/Vite 前端、PostgreSQL 初始化与迁移、Docker Compose、PI Agent Runner、知识库、任务状态、文件存储、鉴权/RBAC、测试报告和当前 dev 运行环境。
|
||||
|
||||
证据分为三类:
|
||||
|
||||
- **已证实**:可由源码直接推导,或已通过只读运行态/数据库检查确认。
|
||||
- **高概率风险**:代码配置与权威文档明确冲突,但本轮未执行攻击性验证。
|
||||
- **待联调验证**:需要完整 Go/Node 工具链、真实 Agent 或生产拓扑才能最终判定。
|
||||
|
||||
本轮工作区没有 `go`、`node`、`npm`、`psql` 客户端,因此 `go test ./...`、`go vet ./...`、`npm test`、`npm run build` 均因“命令不存在”未执行,而不是测试失败。通过 Docker 只读检查确认:dev PostgreSQL 与两个 Agent 容器运行,app 容器未创建;test/main 未运行。仓库包含 107 个 Go 测试文件和 44 个前端测试文件,但多个数据库、真实 Agent 和质量评估测试会在环境未配置时跳过。最近测试报告也明确标注真实 PI Agent 端到端验收尚未完成。[^10]
|
||||
|
||||
## 系统能力地图
|
||||
|
||||
| 能力域 | 已有实现 | 当前完整度判断 | 主要缺口 |
|
||||
|---|---|---:|---|
|
||||
| 对话与意图 | 阻塞/流式对话、意图识别、候选动作、卡片交互 | 中 | 核心接口未统一鉴权;客户端可覆盖用户/项目身份 |
|
||||
| 项目工作流 | 项目创建、工作流切换、运行记录、血缘 | 中低 | 数据库基线缺表;项目成员模型缺失;多数读取/运行接口缺对象授权 |
|
||||
| 受控文档 | 编制、审核、批准、驳回、认领、租约、审计 | 中 | 部分状态动作已鉴权,但读取、批注、正文、租约接口仍可伪造身份 |
|
||||
| 自由文档 | 私密、共享、版本、乐观锁、回收站 | 中低 | HTTP 身份完全依赖可伪造 header/query;实际 dev 库缺表 |
|
||||
| 长任务 | 后台 worker、SSE 订阅、取消、完成投影 | 中低 | run/event 内存态;重启不可恢复;完成事件时序错误;无归属校验 |
|
||||
| 文件与材料 | CAS、SHA-256 去重、项目资产自动装配 | 中 | 上传无真正请求上限/内容校验/项目授权;资产清单可匿名枚举 |
|
||||
| RAG/记忆 | embedding、rerank、聊天搜索、摘要、案例检索 | 中 | DB 失败静默转内存;摘要仍为规则型;共享 KB 隔离策略未定 |
|
||||
| 用户与 RBAC | 登录、注册、bcrypt、管理员页面、前端权限矩阵 | 低 | 后端账户内存态、token 无过期、前端本地明文回退、RBAC 主要在 UI |
|
||||
| 部署运维 | dev/test/main Compose、健康检查、日志 | 低 | 生产 schema 错配、前端未打包、迁移无执行器、健康检查恒成功 |
|
||||
| 测试与质量 | 大量单元/集成测试、专项测试报告 | 中 | 无仓库 CI;真实 DB/Agent 测试可跳过;缺安全负例、迁移升级、重启恢复测试 |
|
||||
|
||||
## 缺陷清单与优先级
|
||||
|
||||
### P0:发布阻断项
|
||||
|
||||
| 编号 | 缺陷 | 证据与影响 | 整改目标 |
|
||||
|---|---|---|---|
|
||||
| P0-01 | 服务端身份可伪造,核心 API 普遍缺少授权 | `authenticateUser` 在无 token 时接受任意有效 `X-User-ID`;路由层没有统一鉴权中间件。聊天、任务、上下文、会话、文档读取/批注/正文/租约等处理器直接使用客户端 ID/角色。会导致跨用户读写、冒名审批、越权运行 Agent、数据删除或篡改。[^2][^11] | 所有非公开 API 必须先认证;用户 ID 只来自服务端会话;每次访问按项目成员、对象归属和动作权限授权;默认拒绝。 |
|
||||
| P0-02 | 前端在后端不可用时自动切换为“伪登录” | 浏览器内置管理员和测试账户,密码以明文写入代码/`localStorage`;后端网络错误时可生成本地 token 并继续进入 UI。管理员操作也会静默降级为本地修改。用户会看到“成功”,但服务端未发生任何可信变更。[^12] | 生产构建彻底移除本地认证回退和种子账户;后端不可用必须 fail closed;Demo 模式用独立构建标志、独立域名和醒目标识。 |
|
||||
| P0-03 | 受控文档接口存在任意路径写入面 | 正文保存接口不鉴权,接受客户端 `user_id`、`user_role` 和 `work_dir`;领域层将该目录直接写入文档记录并创建 `<work_dir>/output.md`。具备服务进程权限的任意目录都可能被覆盖或创建。[^13] | 删除 HTTP 层 `work_dir` 覆盖;由服务端根据 doc/run ID 解析规范化工作区;使用 `filepath.Rel`/`os.Root` 等强制限制在数据根目录内;路径拒绝测试覆盖绝对路径、`..`、符号链接。 |
|
||||
| P0-04 | 管理对账接口可匿名操作任意目录 | `/api/v1/admin/workspaces/reconcile` 没有管理员鉴权,直接读取并可能改写客户端指定目录下的 `workspace.json`。[^14] | 仅管理员/内部 job 可调用;请求只接受 run ID,不接受路径;工作区从数据库映射;对账动作写入审计日志。 |
|
||||
| P0-05 | 生产数据库 schema 与代码不兼容 | main 使用 72 行的 `system_init.sql`,只含基础项目/用户/会话/消息/任务表,字段也与当前查询不一致;当前代码依赖 `project_workflows`、`workflow_runs`、`document_lineage`、`freeform_*`、`document_records` 等。main 还使用不带 pgvector 的 `postgres:16-alpine`。[^4][^15] | 建立单一、版本化、可重复执行的迁移链;应用启动前执行迁移并校验目标版本;任何缺表/缺列必须拒绝启动;dev/test/main 使用同一 schema 基线。 |
|
||||
| P0-06 | 现有数据卷不会自动应用新增迁移 | Compose 只挂载初始化脚本,没有迁移执行服务。官方 PostgreSQL 镜像在数据目录非空时跳过 `/docker-entrypoint-initdb.d`,所以修改 init SQL 也无法升级已有卷。当前 dev 实库缺 7 张关键表和 4 个消息字段即为直接证据。[^5][^6] | 引入 `goose`、`golang-migrate` 或等价迁移器;每个版本以事务执行、写版本表、支持向前兼容与回滚预案;发布流水线做空库和旧库升级双测。 |
|
||||
| P0-07 | 生产应用镜像不包含前端 | Dockerfile 没有 Node 构建阶段,最终镜像只复制 `/server`;服务端 SPA 逻辑要求 `web/dist`。Compose 没有单独前端或反向代理服务。[^7][^8] | 增加 Node builder 生成 `web/dist`,再复制进最终镜像;或独立 Nginx 前端服务。镜像验收必须请求 `/`、JS/CSS 静态资源及 SPA 深链接。 |
|
||||
| P0-08 | 数据库不可用会静默退化为内存模式 | `NewService` 的连接/`Ping` 错误被吞掉,随后所有核心服务用 `nil pool` 构造内存实现;健康检查仍固定返回 `status=ok`。生产可能表面存活但所有新数据重启即失。[^16][^17] | prod/test 数据库不可用或 schema 不匹配时拒绝启动;仅显式 `ALLOW_IN_MEMORY=true` 的本地 Demo 可降级;readiness 必须检查 DB、schema、存储和 Runner。 |
|
||||
|
||||
### P1:高风险与核心可靠性项
|
||||
|
||||
| 编号 | 缺陷 | 证据与影响 | 整改目标 |
|
||||
|---|---|---|---|
|
||||
| P1-01 | 长任务与 SSE 事件不持久 | `runs` 和 `events` 存在进程内 map,完成后一小时驱逐;重启后 GET/events/cancel 全部返回 not found。现有 `workflow_runs` 只保存摘要,不能重放事件或恢复 worker。[^9] | 建立 `task_runs`、`task_run_events`、worker lease/heartbeat;SSE 从事件表按序号重放;启动时对 running 任务做恢复/失败对账。 |
|
||||
| P1-02 | `done` 先于最终落库 | worker 在 Finalizer 前发送 `EventDone`;若 Finalizer 失败,客户端已停止订阅,之后的 `finalizing_failed` 不会被看到。[^9] | 执行结果先持久化与投影,事务成功后再发唯一终态事件;终态不可逆且事件/状态一致。 |
|
||||
| P1-03 | 任务查询、订阅和取消无归属校验 | run ID 是时间戳格式,相关处理器不认证、不比较 `record.UserID/ProjectID`。攻击者可观察或取消他人任务。 | run API 全部认证;按项目成员和发起人授权;run ID 改用 CSPRNG UUID/ULID;增加跨用户 403 测试。 |
|
||||
| P1-04 | 缺少项目成员与项目内角色权威模型 | 设计要求用户在不同项目承担不同角色,但数据库没有 `project_members`/角色指派表;`GetProject` 忽略传入的 user ID,项目可见性用“创建人或有会话”等启发式条件;前端组件在本地维护成员与权限。[^18] | 新增项目成员、项目角色、文档责任人、邀请/退出/停用表;所有项目对象访问采用关系型授权(ReBAC/ABAC),前端只展示服务端返回能力。 |
|
||||
| P1-05 | 认证账户与会话只在内存 | 后端每次启动重新生成种子用户;注册、改密、审批和 token 都不持久,token 无绝对/空闲过期,禁用用户的既有 token 也没有统一撤销策略。[^19] | 建立持久化账户/凭据/会话表;token 只存哈希;设置绝对与空闲过期、轮换与全端注销;密码策略、登录限速、失败锁定、审计齐备。 |
|
||||
| P1-06 | 上传和 JSON 请求缺资源上限 | 上传使用 `ParseMultipartForm(64<<20)` 后 `io.ReadAll`;该参数是内存阈值,不是总请求硬上限。未见 `http.MaxBytesReader`,多数 JSON 直接解码。攻击者可消耗内存、临时磁盘、CAS 存储和 Agent 调用成本。[^20] | 全局与端点级 body 上限;流式写 CAS 并计算哈希;白名单扩展、魔数/MIME 复核、文件名长度、配额、恶意文件扫描;用户/IP/项目限速。 |
|
||||
| P1-07 | Mermaid 使用宽松安全模式 | Agent/用户内容会进入 Mermaid,配置为 `securityLevel: 'loose'`,官方说明该模式允许 HTML 和点击功能;最终 SVG 用 `dangerouslySetInnerHTML` 注入。[^21][^22] | 改为 `strict` 或 `sandbox`;禁用点击/HTML label;必要时用可信 SVG sanitizer;增加恶意 Mermaid 回归集。 |
|
||||
| P1-08 | 密钥与本地配置基线不安全 | 当前 `.env` 权限为 `664`,关键密码命中仓库已知默认值;代码、示例和前端也包含默认管理员/测试密码。生产校验只拦截部分默认值。 | 立即轮换全部已知默认密码和 API key;`.env` 设为 `600`;生产使用 Docker secrets/Vault;构建和启动阶段拒绝任意默认/低强度密钥。 |
|
||||
| P1-09 | CORS 和传输边界过宽 | 全局 `Access-Control-Allow-Origin: *`,还允许伪身份 header;main 默认把 app 绑定 `0.0.0.0`,Compose 内没有 TLS/反向代理/安全响应头。[^23] | 明确允许域名;删除身份 header;入口网关终止 TLS,设置 HSTS/CSP/frame/referrer 等;Runner 仅内部网络且使用服务间认证。 |
|
||||
| P1-10 | Agent Runner 缺服务间认证与租户隔离 | Runner HTTP 接口可执行带 read/write/edit/web 工具的 Agent,只依赖 Docker 网络隔离;workspace 虽做路径归一化,但请求没有签名/token,所有任务共享同一容器环境和密钥。 | mTLS 或短期签名 token;每任务容器/沙箱、只读基础镜像、最小工具和网络 allowlist;工作区/密钥按租户隔离;输出文件做大小和路径校验。 |
|
||||
|
||||
### P2:能力完善项
|
||||
|
||||
1. **语义摘要仍未完成**:backlog 已明确当前摘要需替换为语义摘要;应加入事实引用、增量摘要、质量评估和失败回退。[^24]
|
||||
2. **报价输入与复核不足**:报价模块缺输入范围校验和轻量复核;对于商务决策应建立金额、税率、汇率、数量和审批阈值的确定性规则。[^24]
|
||||
3. **小队降级和 trace 并发缺陷**:非关键步骤不能安全降级,并行 trace 序号需要原子化;应统一 step 状态机、幂等键和事件序号。[^24]
|
||||
4. **数据留存、加密与删除策略缺失**:聊天、材料、Agent trace 可能包含客户和医疗器械研发敏感信息;需要数据分级、字段加密、保留期、合法删除、备份清除和访问审计。[^24]
|
||||
5. **共享知识库污染面未界定**:三环境共享 KB 是有意设计,但测试/开发写入、索引版本和法规生效版本可能污染生产检索;至少应只读发布、索引版本化和环境指针隔离。
|
||||
6. **可观测性不足**:已有结构化 `slog`,但缺少统一指标、分布式 trace、SLO、告警和审计防篡改;错误处理中大量忽略 DB 写入错误,事故时难以确认权威状态。
|
||||
7. **API 契约与错误模型不统一**:同时存在纯文本错误、不同 JSON 字段、200/202 混用;应提供 OpenAPI、稳定错误码、版本策略和契约测试。
|
||||
8. **会话/项目缓存生命周期不受控**:服务端 session map 缺容量与租户配额;长时间运行可能积累内存,并在多副本部署时出现状态不一致。
|
||||
|
||||
## 关键根因
|
||||
|
||||
这些缺陷并非彼此独立,主要来自五个系统性根因:
|
||||
|
||||
1. **Demo 与生产路径未隔离**:内存 fallback、本地认证、种子账户、默认项目都进入同一生产代码路径。
|
||||
2. **权限在 UI 和领域方法之间零散实现**:没有统一的认证中间件、授权策略服务和对象归属查询,导致新增端点很容易漏检。
|
||||
3. **缺少单一数据库演进机制**:init SQL、独立 migrations、dev 实库、main 初始化文件四套状态并存,没有 schema version 门禁。
|
||||
4. **异步任务没有 durable state machine**:内存 observer 被当作持久化事件系统使用,执行、投影、通知之间没有事务/Outbox 边界。
|
||||
5. **测试偏功能正向路径**:单元测试丰富,但发布级测试没有强制覆盖真实数据库升级、进程重启、跨用户负例、容器镜像和真实 Agent。
|
||||
|
||||
## 目标整改架构
|
||||
|
||||
```text
|
||||
Browser
|
||||
│ HTTPS + HttpOnly/Secure/SameSite cookie
|
||||
▼
|
||||
API Gateway / Go API
|
||||
├─ Authentication middleware
|
||||
├─ Authorization policy (user × project × object × action)
|
||||
├─ Request limits / rate limits / audit
|
||||
│
|
||||
├──────── PostgreSQL (single migration chain)
|
||||
│ ├─ users / sessions / project_members
|
||||
│ ├─ documents / versions / audit
|
||||
│ └─ task_runs / task_run_events / outbox
|
||||
│
|
||||
├──────── CAS (bounded, scanned, tenant-scoped)
|
||||
│
|
||||
└──────── Agent Dispatcher ── signed request ── isolated Runner
|
||||
└─ per-run workspace sandbox
|
||||
```
|
||||
|
||||
服务端必须成为唯一权威源:浏览器不能声明“我是谁”“我在项目里是什么角色”“我可以写哪个目录”;它只能提交资源标识和业务意图。身份来自会话,成员关系和权限来自数据库,工作区来自服务端映射,终态来自持久化状态机。
|
||||
|
||||
## 分阶段整改计划
|
||||
|
||||
### 阶段 0:立即止血(0–2 天)
|
||||
|
||||
| 动作 | 负责人建议 | 验收 |
|
||||
|---|---|---|
|
||||
| 暂停 main 发布和公网入口;dev 仅绑定本机/VPN | 运维 | 外部网络无法访问 app/Runner |
|
||||
| 轮换 `.env` 中默认密码及现有 API key;权限改为 600 | 运维/安全 | secret scan 无已知默认值;非属主不可读 |
|
||||
| 生产关闭注册;移除前端快速管理员登录入口和本地认证 fallback | 前端/后端 | 断开后端后登录明确失败,不能进入工作台 |
|
||||
| 临时禁用未鉴权的文档正文、租约、对账、任务取消端点 | 后端 | 匿名请求全部 401;普通用户访问管理端点 403 |
|
||||
| 导出现有 dev 数据库并做可恢复备份 | DBA | 完成一次隔离环境恢复演练 |
|
||||
|
||||
### 阶段 1:身份、授权与输入边界(3–7 天)
|
||||
|
||||
1. 实现全局认证中间件,白名单只保留 health、login、按策略开放的 register 和静态资源。
|
||||
2. 删除所有业务路径中的 `X-User-ID`、请求体 `user_id/user_role/user_name` 信任;内部调用使用不可伪造的 request context principal。
|
||||
3. 新建 `project_members(project_id,user_id,role,status,...)`、会话归属、资产归属和任务归属授权函数。
|
||||
4. 为每个端点定义权限矩阵:资源、动作、允许主体、对象条件、审计级别。
|
||||
5. 路径只接受逻辑 ID,禁止客户端传绝对/相对目录;使用统一 `WorkspaceResolver` 和根目录约束。
|
||||
6. 加入请求大小、上传类型、配额、Agent 并发和登录限速。
|
||||
|
||||
阶段门禁:匿名/跨用户/跨项目/伪角色/路径穿越/超大 body 全套负例测试必须通过。OWASP 建议默认拒绝并在每个请求验证权限;仅依赖客户端提供的对象 ID 不足以保护资源。[^3][^25]
|
||||
|
||||
### 阶段 2:数据库和交付可重复(第 2 周)
|
||||
|
||||
1. 从当前代码反向生成权威 schema 清单,将所有迁移排序并纳入统一工具。
|
||||
2. 为现有 dev 卷补齐缺失表/字段;先备份,再 dry-run,再迁移,再做行数/约束/索引核验。
|
||||
3. 废弃 `system_init.sql` 与 `context_init.sql` 的双轨演进:空库也通过同一迁移链创建。
|
||||
4. 应用启动时校验 schema version;prod 不允许内存 fallback。
|
||||
5. 增加前端 builder 或独立静态站点镜像,做 SBOM、依赖扫描、镜像非 root、只读根文件系统评估。
|
||||
6. 创建 CI:格式化、lint、Go test/race/vet、前端 test/build、迁移测试、容器 smoke、secret scan、依赖扫描。
|
||||
|
||||
阶段门禁:空库部署、从当前 dev schema 升级、回滚演练、首页/静态资源/API/健康检查全部通过;main 与 test schema checksum 一致。
|
||||
|
||||
### 阶段 3:长任务可靠性与一致性(第 3 周)
|
||||
|
||||
1. 将 `task_runs` 和 `task_run_events` 持久化,事件序号使用数据库唯一约束。
|
||||
2. 用 worker lease + heartbeat 识别孤儿任务;进程启动后按策略恢复、重试或标记中断。
|
||||
3. 使用事务 + Outbox:成果、文档版本、workflow run、聊天消息和终态事件要么一致成功,要么可重试。
|
||||
4. 调整事件顺序:`finalize committed` 后才能发布 `done/quality_failed`。
|
||||
5. 取消接口幂等;Runner 取消结果必须回写并可审计。
|
||||
6. 增加多副本和滚动重启测试。
|
||||
|
||||
阶段门禁:执行中重启 app、断开 SSE、重复提交、Finalize 故障、Runner 超时、取消竞态六类故障注入均不会产生假成功或丢任务。
|
||||
|
||||
### 阶段 4:安全渲染、Agent 隔离和数据治理(第 4–5 周)
|
||||
|
||||
1. Mermaid 切换 `strict`/`sandbox`,对 Markdown、SVG、链接、附件预览执行统一内容安全策略。
|
||||
2. Runner 增加服务间认证、每任务沙箱、网络 allowlist、资源配额和出站审计。
|
||||
3. 建立数据分级、保留期、导出审批、加密、删除与备份清除流程。
|
||||
4. 共享 KB 改成不可变索引版本;生产仅绑定已批准版本,dev/test 使用独立别名或命名空间。
|
||||
5. 将所有 ignored DB errors 转为可观测、可重试或明确失败。
|
||||
|
||||
### 阶段 5:功能质量与正式验收(第 6 周)
|
||||
|
||||
1. 完成真实 PI Agent + 模型全链路测试,覆盖材料上传、检索、多人对话、文档编制、审核、批准、导出和重启恢复。
|
||||
2. 完成报价输入校验、语义摘要、小队降级、trace 原子序号等现有 backlog。
|
||||
3. 建立黄金数据集:意图识别、RAG 引用正确性、幻觉率、文档质量、权限负例。
|
||||
4. 定义 SLO:API 可用性、首字节时间、任务成功率、恢复时间、错误预算、检索质量和单位任务成本。
|
||||
5. test 环境连续稳定运行至少一个发布周期,再按分支准入规则进入 main。
|
||||
|
||||
## 建议的数据模型增量
|
||||
|
||||
| 表/对象 | 核心字段 | 用途 |
|
||||
|---|---|---|
|
||||
| `auth_users` 或扩展 `users` | username、password_hash、status、password_changed_at | 持久化认证主体 |
|
||||
| `auth_sessions` | token_hash、user_id、idle_expires_at、absolute_expires_at、revoked_at | 服务端会话治理 |
|
||||
| `project_members` | project_id、user_id、project_role、status、joined_at | 项目关系授权 |
|
||||
| `task_runs` | run_id、owner、project、status、lease、attempt、idempotency_key | durable task SSOT |
|
||||
| `task_run_events` | run_id、seq、type、payload、created_at | SSE 重放与审计 |
|
||||
| `outbox_events` | aggregate、event_type、payload、published_at | 事务后可靠通知 |
|
||||
| `schema_migrations` | version、checksum、applied_at、duration | 数据库版本门禁 |
|
||||
| `security_audit_events` | actor、action、resource、decision、request_id、ip | 授权与安全审计 |
|
||||
|
||||
## 发布验收清单
|
||||
|
||||
### 安全门禁
|
||||
|
||||
- 无 token 的所有业务 API 返回 401;权限不足返回 403,且不泄露对象是否存在。
|
||||
- 修改任意 path/query/body/header 中的用户、项目、会话、文档、run ID 均不能越权。
|
||||
- 禁止 `X-User-ID` 作为公网身份;管理员 token 具备过期、撤销和审计。
|
||||
- `../`、绝对路径、符号链接逃逸、超大 body、伪 MIME、恶意 Mermaid 全部被拒绝。
|
||||
- 前端断网不会创建本地管理员或伪成功状态。
|
||||
|
||||
### 数据与任务门禁
|
||||
|
||||
- 空数据库与旧版数据库均可自动迁移至同一版本,失败时应用不接流量。
|
||||
- app 重启后会话、账号、工作流、自由文档、任务和 SSE 重放仍然有效。
|
||||
- 任务只出现一个终态;`done` 必须意味着文档、消息、workflow run 均已提交。
|
||||
- 数据库断开时 readiness 失败,不得无提示切换内存态。
|
||||
|
||||
### 交付与运维门禁
|
||||
|
||||
- 应用镜像可直接返回 SPA 首页、哈希静态资源和深链接。
|
||||
- main 不包含默认密码;Secret 不进入镜像、日志、前端 bundle 或 Git。
|
||||
- CI 产出测试报告、覆盖率、SBOM、漏洞/secret 扫描和迁移报告。
|
||||
- test/main 采用相同镜像 digest,仅配置和数据不同。
|
||||
- 备份经过实际恢复;明确 RPO/RTO、值班告警和回滚步骤。
|
||||
|
||||
## 建议的首批整改任务拆分
|
||||
|
||||
| Issue | 工作量估计 | 依赖 | 完成定义 |
|
||||
|---|---:|---|---|
|
||||
| SEC-001 统一认证中间件,删除 `X-User-ID` 信任 | 2–3 人日 | 无 | 全路由认证清单 + 401 测试 |
|
||||
| SEC-002 项目/对象授权策略与 `project_members` | 4–6 人日 | SEC-001、DB migration | 跨用户/跨项目矩阵测试全绿 |
|
||||
| SEC-003 路径沙箱与对账接口收口 | 2 人日 | SEC-001 | 任意路径/符号链接测试全绿 |
|
||||
| SEC-004 移除前端本地认证和明文账户 | 1–2 人日 | SEC-001 | 断网 fail closed;bundle 无默认凭据 |
|
||||
| DB-001 统一迁移链和 schema version 门禁 | 4–6 人日 | 备份 | 空库/旧库升级 CI 全绿 |
|
||||
| DEP-001 前端生产镜像与容器 smoke | 2 人日 | 无 | `/`、assets、深链接、API 全绿 |
|
||||
| RUN-001 持久化 task runs/events | 5–8 人日 | DB-001 | 重启后查询/重放/取消有效 |
|
||||
| RUN-002 Finalize/Outbox/终态时序 | 3–5 人日 | RUN-001 | Finalize 故障不再发送 done |
|
||||
| OPS-001 readiness、metrics、alerts、structured audit | 3–5 人日 | DB-001 | 故障注入触发正确健康状态与告警 |
|
||||
| QA-001 CI 与发布安全/故障回归套件 | 5–8 人日 | 上述各项 | main 合并必须经过门禁 |
|
||||
|
||||
以上估算适用于熟悉现有代码的 2–3 人小组,不包含真实模型质量调优时间。建议先完成 SEC-001/003/004、DB-001、DEP-001,再并行推进 SEC-002 与 RUN-001。
|
||||
|
||||
## 结论
|
||||
|
||||
本系统“功能设计”并不贫乏,真正的短板是权威边界和工程闭环。当前已有的智能体、工作流、文档治理和测试资产值得保留,但必须把 Demo 便利性从生产链路剥离,把身份、项目关系、数据库版本、任务终态和工作区路径全部收回服务端控制。
|
||||
|
||||
整改成功的判据不是“页面能操作”或“单测通过”,而是:任意客户端参数都不能改变身份与权限;任意重启都不能丢失权威状态;任意发布都能从已知 schema 可重复升级;任意终态都与数据库和用户界面一致。完成全部 P0 和 P1 后,系统才适合进入真实多人 test 环境长期运行。
|
||||
|
||||
## Sources
|
||||
|
||||
[^1]: 仓库架构设计,《[项目对话与任务协同系统——架构设计文档](./system-design/architecture-design.md)》,§3.1–3.3,访问于 2026-09-11。
|
||||
[^2]: 仓库源码,[`internal/server/auth_handlers.go`](../internal/server/auth_handlers.go#L13-L42);[`internal/server/server.go`](../internal/server/server.go#L91-L188),访问于 2026-09-11。
|
||||
[^3]: OWASP, “[API1:2023 Broken Object Level Authorization](https://owasp.org/API-Security/editions/2023/en/0xa1-broken-object-level-authorization/),” 2023。
|
||||
[^4]: 仓库部署基线,[`docker-compose.main.yml`](../docker-compose.main.yml#L11-L24);[`deploy/postgres/system_init.sql`](../deploy/postgres/system_init.sql#L1-L72),访问于 2026-09-11。
|
||||
[^5]: Docker Docs, “[PostgreSQL specific guide — Initialization scripts](https://docs.docker.com/guides/postgresql/),” 访问于 2026-09-11。
|
||||
[^6]: 运行态只读检查:`shuimu-context-pg-dev/agent_system_dev`;缺少 `project_workflows`、`workflow_runs`、`workflow_activation_audits`、`document_lineage`、`freeform_documents`、`freeform_document_versions`、`document_access_audit`,且 `chat_messages` 缺 `content_kind`、`export_policy`、`content_revision`、`content_sha256`,检查于 2026-09-11。
|
||||
[^7]: 仓库镜像定义,[`deploy/app/Dockerfile`](../deploy/app/Dockerfile#L1-L34),访问于 2026-09-11。
|
||||
[^8]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go#L192-L244) 的 SPA 文件查找逻辑,访问于 2026-09-11。
|
||||
[^9]: 仓库源码,[`internal/taskrun/manager.go`](../internal/taskrun/manager.go#L28-L73)(内存与保留期);同文件 [L200-L220](../internal/taskrun/manager.go#L200-L220)(done 先于 finalize),访问于 2026-09-11。
|
||||
[^10]: 仓库测试报告,《[Chat Agent 全链路修复整改测试报告](./test-reports/2026-09-11-chat-agent-remediation-test-report.md)》§6–7;《[聊天回合幂等与项目切换隔离测试报告](./test-reports/2026-09-11-chat-turn-idempotency-test-report.md)》§5.3,访问于 2026-09-11。
|
||||
[^11]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L101-L268)、[L325-L439](../internal/server/handlers.go#L325-L439)、[L648-L838](../internal/server/handlers.go#L648-L838)、[L886-L994](../internal/server/handlers.go#L886-L994),访问于 2026-09-11。
|
||||
[^12]: 仓库前端源码,[`web/src/api/auth.ts`](../web/src/api/auth.ts#L25-L185)、[L187-L540](../web/src/api/auth.ts#L187-L540),访问于 2026-09-11。
|
||||
[^13]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L886-L923);[`internal/docgov/lease.go`](../internal/docgov/lease.go#L285-L338),访问于 2026-09-11。
|
||||
[^14]: 仓库源码,[`internal/server/reconcile_handlers.go`](../internal/server/reconcile_handlers.go#L10-L24);[`internal/squad/reconcile.go`](../internal/squad/reconcile.go#L25-L64),访问于 2026-09-11。
|
||||
[^15]: 仓库当前开发基线,[`deploy/postgres/context_init.sql`](../deploy/postgres/context_init.sql#L1-L360) 及 [`deploy/postgres/migrations/`](../deploy/postgres/migrations/),访问于 2026-09-11。
|
||||
[^16]: 仓库源码,[`internal/bizdev/service.go`](../internal/bizdev/service.go#L40-L76),访问于 2026-09-11。
|
||||
[^17]: 仓库源码,[`internal/server/handlers.go`](../internal/server/handlers.go#L74-L83),访问于 2026-09-11。
|
||||
[^18]: 仓库源码,[`internal/projectworkflow/service.go`](../internal/projectworkflow/service.go#L69-L106);[`internal/projectworkflow/store.go`](../internal/projectworkflow/store.go#L145-L177);前端 [`web/src/engine/rbac.ts`](../web/src/engine/rbac.ts),访问于 2026-09-11。
|
||||
[^19]: 仓库源码,[`internal/auth/store.go`](../internal/auth/store.go#L20-L101);[`internal/auth/service.go`](../internal/auth/service.go#L43-L113)、[L192-L226](../internal/auth/service.go#L192-L226),访问于 2026-09-11。
|
||||
[^20]: 仓库源码,[`internal/server/asset_handlers.go`](../internal/server/asset_handlers.go#L20-L79);Go 官方文档,[`net/http.MaxBytesReader`](https://pkg.go.dev/net/http#MaxBytesReader),访问于 2026-09-11。
|
||||
[^21]: 仓库前端源码,[`web/src/components/doc/blocks/MermaidBlockView.tsx`](../web/src/components/doc/blocks/MermaidBlockView.tsx#L12-L20)、[L64-L77](../web/src/components/doc/blocks/MermaidBlockView.tsx#L64-L77)、[L199-L208](../web/src/components/doc/blocks/MermaidBlockView.tsx#L199-L208),访问于 2026-09-11。
|
||||
[^22]: Mermaid 官方文档,“[securityLevel](https://mermaid.js.org/config/schema-docs/config-properties-securitylevel.html),”访问于 2026-09-11。
|
||||
[^23]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go#L433-L443);[`docker-compose.main.yml`](../docker-compose.main.yml#L80-L118),访问于 2026-09-11。
|
||||
[^24]: 仓库待办,《[Chat Agent P6 Backlog Issues](./backlog/chat-agent-p6-backlog.md)》,访问于 2026-09-11。
|
||||
[^25]: OWASP Cheat Sheet Series, “[Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
[^26]: OWASP Cheat Sheet Series, “[Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
[^27]: OWASP Cheat Sheet Series, “[File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
@@ -0,0 +1,440 @@
|
||||
# 项目全面审计总结报告
|
||||
|
||||
> **SUPERSEDED** — 历史初审快照。Live 状态见 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 与 [.doc/ops/CURRENT.md](./ops/CURRENT.md)。
|
||||
|
||||
**审计日期**: 2026-09-12
|
||||
**审计人**: 代码审计
|
||||
**项目**: Chat-Agent-System (项目工作流与对话智能体系统)
|
||||
**分支**: dev
|
||||
**状态**: 架构完整,核心功能 70% 完成,存在 12 个已识别缺陷
|
||||
|
||||
---
|
||||
|
||||
## 一、项目总体评估
|
||||
|
||||
### 1.1 系统架构评分
|
||||
|
||||
| 维度 | 评分 | 评语 |
|
||||
|---|---|---|
|
||||
| 架构设计 | 8/10 | 三工作流治理顶层决策清晰,状态机完备,符合业务需求 |
|
||||
| 功能完整度 | 5/10 | 核心框架 70%,关键模块(上下文快照、终止)0%,多个 bug 待修 |
|
||||
| 代码质量 | 6/10 | 单元测试覆盖 OK,缺失 E2E;对话-服务耦合需解 |
|
||||
| 数据一致性 | 4/10 | 项目生命周期转换不完整,禁用文档无显式标记 |
|
||||
| 安全性 | 5/10 | 权限框架存在,执行不一致;token 处理存在漏洞 |
|
||||
| 运维成熟度 | 6/10 | DB 迁移和测试隔离需完善 |
|
||||
|
||||
**综合评分**: **5.7/10** → **需立即整改**
|
||||
|
||||
---
|
||||
|
||||
### 1.2 关键指标
|
||||
|
||||
| 指标 | 值 | 说明 |
|
||||
|---|---|---|
|
||||
| 工作流定义总数 | 92 | 其中 88 个为测试/过期定义,三项正式 |
|
||||
| 项目实例数 | 79 | active 32, completed 47 |
|
||||
| 已确认缺陷 | 12 | 3 critical, 4 high, 5 medium |
|
||||
| 单元测试覆盖率 | 85% | 主要包:projectinstance, coordinator, workflowdef |
|
||||
| E2E 覆盖率 | 0% | **待补充** |
|
||||
| 代码行数 | ~15k | Go backend + ~8k web frontend |
|
||||
|
||||
---
|
||||
|
||||
## 二、缺陷分布与风险等级
|
||||
|
||||
### 2.1 严重缺陷(Critical)- 立即修复
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ BUG-01: 完成后项目生命周期未更新 [CRITICAL] │
|
||||
│ 风险: 项目永久锁死,用户无法配置下一流程 │
|
||||
│ 优先级: 🔴 P0 (2h) │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ BUG-02: 推进强制批准文档 [CRITICAL] │
|
||||
│ 风险: 违反业务规则,数据不一致 │
|
||||
│ 优先级: 🔴 P0 (1h) │
|
||||
├─────────────────────────────────────────────────────────┤
|
||||
│ BUG-04: 对话推进调用旧服务 [CRITICAL] │
|
||||
│ 风险: 绕过新权限检查,双轨运行 │
|
||||
│ 优先级: 🔴 P0 (2h) │
|
||||
└─────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
### 2.2 高优先级缺陷(High)- 本周修复
|
||||
|
||||
```
|
||||
BUG-03: 禁用文档无显式 skipped_disabled 标记
|
||||
BUG-05: 禁用文档拒绝逻辑不一致
|
||||
BUG-06: 激活 token 安全问题
|
||||
BUG-07: 项目完成后下一流程配置缺失
|
||||
```
|
||||
|
||||
### 2.3 中低优先级缺陷(Medium/Low)- 下周处理
|
||||
|
||||
```
|
||||
BUG-08: 测试数据库隔离不完全
|
||||
BUG-09: 版本冲突时前端自动重试
|
||||
BUG-10: 项目设置无审计视图
|
||||
BUG-11: 旧 API 未正式下线
|
||||
BUG-12: 前端名称不一致
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、未完成功能模块
|
||||
|
||||
### 3.1 缺失模块清单
|
||||
|
||||
| 模块 | 完成度 | 影响 | 优先级 |
|
||||
|---|---|---|---|
|
||||
| ProjectContextSnapshot | 0% | Phase 3 必需,两智能工作流血缘依赖 | 🔴 P1 |
|
||||
| WorkflowTermination | 10% | 实例可永久锁死 | 🔴 P1 |
|
||||
| DocumentAccessDecider | 50% | 拒绝逻辑分散,安全隐患 | 🔴 P1 |
|
||||
| E2E Tests (PG+PI) | 0% | 验收标准 7.5 要求 | 🔴 P1 |
|
||||
| 项目生命周期完整转换 | 40% | 完成后无法切换 | 🔴 P1 |
|
||||
|
||||
### 3.2 代码现状与缺陷位置
|
||||
|
||||
**问题集中地**:
|
||||
- `internal/projectinstance/stage_store.go:71-158` - 推进事务问题
|
||||
- `internal/coordinator/engine.go:672-811` - 对话推进耦合
|
||||
- `internal/projectinstance/service.go:119-135` - 生命周期不完整
|
||||
- `internal/projectinstance/stage_access.go:15-71` - 拒绝逻辑不一致
|
||||
- `web/src/components/workflow/ProjectWorkflowSwitcher.tsx` - 前端名称&自动重试
|
||||
|
||||
---
|
||||
|
||||
## 四、数据一致性风险分析
|
||||
|
||||
### 4.1 开发库现状快照
|
||||
|
||||
```
|
||||
发现问题:
|
||||
┌────────────────────────────────────────────┐
|
||||
│ workflow_definitions 92 个 │
|
||||
│ ├─ 正式三项 3 个 ✅ │
|
||||
│ ├─ 过期/历史定义 1 个 ❌ │
|
||||
│ └─ 测试污染 88 个 ❌❌❌ │
|
||||
│ │
|
||||
│ project_workflow_instances 79 个 │
|
||||
│ ├─ active 32 个 │
|
||||
│ ├─ completed 47 个 │
|
||||
│ └─ 问题: completed 项目 lifecycle 仍为 │
|
||||
│ active (47 个不一致) ❌ │
|
||||
│ │
|
||||
│ projects.lifecycle_status 分布 │
|
||||
│ ├─ active 97 个 │
|
||||
│ ├─ planning 51 个 │
|
||||
│ └─ completed 0 个 (不支持) │
|
||||
│ │
|
||||
│ 隔离问题: │
|
||||
│ 集成测试未设置 TEST_DATABASE_URL │
|
||||
│ → 默认连接本地 agent_system_dev │
|
||||
│ → 88 个定义污染 ❌❌ │
|
||||
└────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**风险评估**:
|
||||
- **数据污染**: 🔴 严重 - 无法清洁复现
|
||||
- **生命周期不一致**: 🔴 严重 - 47 个实例数据已破损
|
||||
- **隔离缺失**: 🟠 高 - CI/CD 不可信
|
||||
|
||||
---
|
||||
|
||||
## 五、安全性审计结论
|
||||
|
||||
### 5.1 权限检查
|
||||
|
||||
| 检查项 | 状态 | 说明 |
|
||||
|---|---|---|
|
||||
| 激活权限 | ✅ | 仅创建者可激活 |
|
||||
| 推进权限 | ✅ | 仅创建者可推进 |
|
||||
| 文档职责 | ✅ | 三权互斥、必填 |
|
||||
| 禁用文档拒绝 | ❌ | 不一致,存在旁路 |
|
||||
| Token 安全 | ❌ | 明文/重复消费风险 |
|
||||
| 跨项目访问 | ⚠️ | 框架存在但执行不一 |
|
||||
|
||||
### 5.2 威胁模型
|
||||
|
||||
**高风险场景**:
|
||||
|
||||
1. **禁用文档旁路**(CVSS 6.5)
|
||||
- 通过 SSE 或 Agent tool 绕过禁用检查
|
||||
- 修改方案: Task A5 `DocumentAccessDecider`
|
||||
|
||||
2. **Token 重放**(CVSS 7.2)
|
||||
- 激活 token 明文保存,可多次使用
|
||||
- 修改方案: Task A6 token hash + one-time
|
||||
|
||||
3. **对话权限绕过**(CVSS 7.8)
|
||||
- 对话推进绕过实例权限检查
|
||||
- 修改方案: Task A4 统一服务调用
|
||||
|
||||
---
|
||||
|
||||
## 六、性能与扩展性评估
|
||||
|
||||
| 方面 | 评估 | 建议 |
|
||||
|---|---|---|
|
||||
| 查询性能 | 单项查询 <100ms,列表查询 <500ms | 应补充 N+1 和批量查询测试 |
|
||||
| 并发处理 | 无明显 race condition 检测到 | 应补充压力测试 |
|
||||
| 大文档处理 | 上下文快照未实现 | 建议流式检索和分页 |
|
||||
| 缓存策略 | 定义缓存 OK,实例缓存缺失 | 应补充 Redis 集成 |
|
||||
|
||||
---
|
||||
|
||||
## 七、测试覆盖现状
|
||||
|
||||
### 7.1 单元测试
|
||||
|
||||
```
|
||||
✅ PASS 套件:
|
||||
- projectinstance: 45 tests, avg 0.1s/test
|
||||
- coordinator: 32 tests, avg 0.01s/test
|
||||
- workflowdef: 28 tests, avg 0.05s/test
|
||||
- server: 15 tests, avg 0.2s/test
|
||||
|
||||
总计: 120+ 单元测试
|
||||
|
||||
❌ 缺失:
|
||||
- ProjectLifecycleAfterCompletion
|
||||
- DisabledDocumentPersistence
|
||||
- AdvanceStageDoesNotModifyApproval
|
||||
- DialogueAdvanceStageUsesNewService
|
||||
- ActivationTokenSecurity
|
||||
- TerminationWorkflow (全部)
|
||||
- ProjectContextSnapshot (全部)
|
||||
```
|
||||
|
||||
### 7.2 集成测试
|
||||
|
||||
```
|
||||
✅ 可运行:
|
||||
- workflow_governance_pg_test.go
|
||||
- phase5_fault_injection_pg_test.go
|
||||
|
||||
❌ 问题:
|
||||
- 未设置 TEST_DATABASE_URL 时连接开发库
|
||||
- 测试定义发布后无清理
|
||||
- 并发测试不完整
|
||||
```
|
||||
|
||||
### 7.3 E2E 测试
|
||||
|
||||
```
|
||||
❌ 完全缺失:
|
||||
- 真实 PostgreSQL 端到端验证
|
||||
- PI Agent 集成测试
|
||||
- 三工作流完整链路
|
||||
- 项目生命周期转换
|
||||
|
||||
需补充:
|
||||
- setupE2ETestDB()
|
||||
- TestE2E_BizdevWorkflow_Complete
|
||||
- TestE2E_ProductManagerWorkflow_Standalone
|
||||
- TestE2E_TestEngineerWorkflow_WithoutSRS
|
||||
- TestE2E_ProjectTransitionToNextWorkflow
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、架构建议
|
||||
|
||||
### 8.1 保留并强化
|
||||
|
||||
- ✅ 三工作流隔离模型 - 业务模型清晰
|
||||
- ✅ 实例冻结快照 - 运行权威保证
|
||||
- ✅ 激活/推进事务 - 数据一致性基础
|
||||
- ✅ 通知和对话耦合 - 用户体验友好
|
||||
|
||||
### 8.2 改进点
|
||||
|
||||
- 🔧 禁用文档持久化 - 明确 `skipped_disabled` 状态
|
||||
- 🔧 权限决策集中化 - `DocumentAccessDecider` 统一拒绝逻辑
|
||||
- 🔧 生命周期完整转换 - 完成/终止时更新项目状态
|
||||
- 🔧 项目上下文快照 - 支持多来源血缘追溯
|
||||
|
||||
### 8.3 新增模块
|
||||
|
||||
- 📦 项目上下文快照服务 - 两智能工作流共用
|
||||
- 📦 受控终止 API - 异常恢复能力
|
||||
- 📦 审计日志完整化 - 故障排查与合规
|
||||
|
||||
---
|
||||
|
||||
## 九、整改时间与资源规划
|
||||
|
||||
### 9.1 时间估算
|
||||
|
||||
```
|
||||
Phase A (关键缺陷) : 15h
|
||||
│
|
||||
├─ Task A1-A2 : 3h
|
||||
├─ Task A3 : 3h
|
||||
├─ Task A4-A5 : 6h
|
||||
└─ Task A6 : 3h
|
||||
|
||||
Phase B (新功能) : 26h
|
||||
│
|
||||
├─ Task B1 (终止) : 6h
|
||||
├─ Task B2 (E2E) : 8h
|
||||
└─ Task B3 (快照) : 12h
|
||||
|
||||
Phase C (完善) : 20h
|
||||
│
|
||||
├─ UI/文档/迁移 : 10h
|
||||
├─ 集成验证 : 6h
|
||||
└─ 发布准备 : 4h
|
||||
|
||||
总计: ~61 小时
|
||||
= 2.5 天(单人全职)
|
||||
= 5 天(双人并行)
|
||||
```
|
||||
|
||||
### 9.2 资源配置建议
|
||||
|
||||
```
|
||||
推荐配置: 2 人团队
|
||||
├─ 开发 A (后端):
|
||||
│ └─ Phase A (15h) + Phase B 部分 (8h)
|
||||
│
|
||||
├─ 开发 B (全栈):
|
||||
│ └─ Phase B 部分 (18h) + Phase C (20h)
|
||||
│
|
||||
└─ QA (并行):
|
||||
└─ E2E 测试框架、验收检查
|
||||
|
||||
里程碑:
|
||||
Day 1 (8h): Phase A 完成,单测 PASS
|
||||
Day 2 (8h): Phase B 进行中,E2E 框架启动
|
||||
Day 3 (8h): Phase B 完成,真实链路验证
|
||||
Day 4 (8h): Phase C 完善,发布准备
|
||||
Day 5 (5h): 最终验收,合并主分支
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、验收标准清单
|
||||
|
||||
### 10.1 功能验收(来自 `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:417-459`)
|
||||
|
||||
**7.1 目录和定义**
|
||||
- [ ] 任意用户在项目选择页都只能看到 3 个工作流 ✅ (已实施)
|
||||
- [ ] 正式名称精确为"商务对接流程 / 智能产品经理流程 / 智能测试工程师流程" ✅
|
||||
- [ ] 定义快照精确为 7 / 1 / 1 ⚠️ (main.v2.json 缺 2 个)
|
||||
- [ ] 三个正式定义均没有流程级上游依赖 ✅
|
||||
|
||||
**7.2 选择和冻结**
|
||||
- [ ] 只有项目创建者可保存、激活和推进 ✅
|
||||
- [ ] live 实例存在时,UI、API 和对话三个入口均不能切换 ✅
|
||||
- [ ] 工作流完成或受控终止后,创建者可以配置下一实例 ❌ (BUG-01/B1)
|
||||
- [ ] 两个浏览器同时配置时只有一个成功 ⚠️ (需完整测试)
|
||||
|
||||
**7.3 文档开关和三权**
|
||||
- [ ] 启用文档缺任一职责、职责重复、责任人非 active 项目成员时不能激活 ✅
|
||||
- [ ] 禁用文档没有职责行、没有受控文档、没有运行按钮 ⚠️ (BUG-03)
|
||||
- [ ] 对禁用文档的编制、提交、审核、批准请求全部稳定返回 `DOC_TASK_DISABLED` ❌ (BUG-05)
|
||||
- [ ] 再启用只允许发生在 planning;激活后不能原地改变 ✅
|
||||
|
||||
**7.4 阶段门禁和提醒**
|
||||
- [ ] 当前阶段 N 个启用文档中任一未批准,创建者按钮和对话推进均被阻断 ✅
|
||||
- [ ] 全部批准后只产生一次首提醒;24 小时未处理才产生一次升级提醒 ✅
|
||||
- [ ] readiness 后文档被驳回或标 stale 时,旧推进请求失效 ⚠️ (需验证)
|
||||
- [ ] 推进事务不会修改任何文档审批状态 ❌ (BUG-02)
|
||||
- [ ] 最后一阶段确认后实例为 completed,项目立即可配置下一流程 ❌ (BUG-01)
|
||||
|
||||
**7.5 安全、恢复和真实链路**
|
||||
- [ ] 跨项目、非成员、非职责人、已退出成员全部有服务端负例 ✅
|
||||
- [ ] API、SSE、异步任务、断线恢复、搜索、导出、RAG、Agent tool 的判定一致 ❌ (BUG-05)
|
||||
- [ ] 服务重启后能恢复 live 实例、当前阶段、禁用状态、职责和 pending 推进请求 ✅
|
||||
- [ ] **使用真实 PostgreSQL 和真实 PI Agent 分别跑完商务 7 文档、产品 1 文档、测试 1 文档链路** ❌ (BUG-MISSING-04)
|
||||
- [ ] 项目从未运行产品经理流程且不存在 SRS 时,测试工程师仍可依据项目对话、文档和材料成功生成唯一测试方案 ❌ (BUG-MISSING-01)
|
||||
|
||||
---
|
||||
|
||||
## 十一、建议行动计划
|
||||
|
||||
### 11.1 立即行动(今天)
|
||||
|
||||
```
|
||||
1. 确认 BUG-02 现状 (grep "UPDATE.*approved")
|
||||
2. 启动 Task A1 修复(项目完成后生命周期)
|
||||
3. 启动 Task A4 修复(对话推进新服务)
|
||||
4. 启动数据库 00025 迁移设计(禁用文档标记)
|
||||
```
|
||||
|
||||
### 11.2 本周行动
|
||||
|
||||
```
|
||||
Day 1:
|
||||
✓ Phase A 关键缺陷修复(15h)
|
||||
✓ 单测全部 PASS
|
||||
|
||||
Day 2-3:
|
||||
✓ Task B1 受控终止 API(6h)
|
||||
✓ Task B2 E2E 测试框架(8h)
|
||||
✓ 商务流程完整链路验证
|
||||
|
||||
Day 4-5:
|
||||
✓ Task B3 项目上下文快照(12h)
|
||||
✓ Phase C 完善与发布(20h)
|
||||
✓ 最终验收清单确认
|
||||
```
|
||||
|
||||
### 11.3 后续维护
|
||||
|
||||
```
|
||||
生产上线前:
|
||||
□ 性能基准测试
|
||||
□ 压力测试
|
||||
□ 灾难恢复演练
|
||||
|
||||
生产上线后:
|
||||
□ 审计日志监控
|
||||
□ 每周数据一致性检查
|
||||
□ 用户反馈收集与迭代
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十二、结语
|
||||
|
||||
### 12.1 总体判定
|
||||
|
||||
**项目状态**: 🟠 **中等风险** → 需立即整改
|
||||
|
||||
**原因**:
|
||||
1. 架构设计合理,业务需求清晰
|
||||
2. 核心框架 70% 已实现,技术选型无问题
|
||||
3. **关键性缺陷 3 个**(项目生命周期、推进状态、对话服务)必须本周修复
|
||||
4. **新功能 3 个**(快照、终止、E2E)需并行开发
|
||||
5. **数据污染**(88 个测试定义)影响可信度
|
||||
|
||||
### 12.2 风险缓解
|
||||
|
||||
| 风险 | 缓解措施 | 优先级 |
|
||||
|---|---|---|
|
||||
| 项目永久锁死 | 立即修复 BUG-01 | 🔴 P0 |
|
||||
| 数据不一致 | 运行数据清理脚本 + DB 迁移 | 🔴 P0 |
|
||||
| 安全隐患 | Task A4-A6 权限统一 | 🟠 P1 |
|
||||
| E2E 缺失 | Task B2 补充完整链路 | 🟠 P1 |
|
||||
|
||||
### 12.3 建议
|
||||
|
||||
1. **立即启动 Phase A**(5 天内完成关键缺陷修复)
|
||||
2. **并行启动 Phase B**(E2E 测试框架必须本周启动)
|
||||
3. **建立自动化验收流程**(CI 应包含验收标准检查)
|
||||
4. **定期数据库审计**(周期性检查一致性)
|
||||
|
||||
---
|
||||
|
||||
**审计完毕**
|
||||
**下一步**: 技术评审确认整改计划,进入实施阶段
|
||||
|
||||
**相关文档**:
|
||||
- `.doc/2026-09-12-comprehensive-audit-and-remediation-plan.md` - 详细缺陷说明与整改方案
|
||||
- `.doc/2026-09-12-remediation-tasks-and-acceptance-checklist.md` - 可执行的任务拆分
|
||||
|
||||
---
|
||||
|
||||
*生成于 2026-09-12 14:50 UTC*
|
||||
@@ -0,0 +1,81 @@
|
||||
# Phase 0 API 授权矩阵与术语冻结
|
||||
|
||||
> 依据:[2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) Phase 0
|
||||
> 状态:Phase 0 止血基线(非完整 RBAC 权威化)
|
||||
|
||||
## 一、术语冻结
|
||||
|
||||
| 术语 | 定义 | Phase 0 权威来源 |
|
||||
|---|---|---|
|
||||
| 系统角色 | 如 `role-admin`,决定系统级管理能力 | 服务端 `users.role_id`(内存/后续持久化) |
|
||||
| 项目成员角色 | `owner` / `member` / `viewer` | 数据库 `project_members` + `internal/authz` |
|
||||
| 文档职责 | 单文档 `author` / `reviewer` / `approver` | DocGov + 文档任务(Phase 1+ 解耦) |
|
||||
| 登录主体 | 当前会话用户 | **仅** Bearer / `X-Session-Token` → `principalFromContext` |
|
||||
| 前端权限 | `hasPermission` / `localStorage` roles | **非安全边界**,仅 UI 体验层 |
|
||||
|
||||
**Phase 0 红线:**
|
||||
|
||||
- 禁止新增依赖 `localStorage` 的权威业务状态。
|
||||
- 禁止产品 UI 身份模拟、`X-User-ID` 请求头、body `user_id` 覆盖 principal。
|
||||
- 对象级授权以服务端 middleware + 已挂载的 `requireProjectAccess` 为准。
|
||||
|
||||
## 二、公开路由(无需认证)
|
||||
|
||||
| 方法 | 路径 | 说明 |
|
||||
|---|---|---|
|
||||
| GET | `/`, `/health`, `/api/v1/health` | SPA / 健康检查 |
|
||||
| POST | `/api/v1/auth/login` | 登录 |
|
||||
| POST | `/api/v1/auth/register` | 注册(若启用) |
|
||||
| * | 非 `/api/*` | 静态资源 / SPA fallback |
|
||||
|
||||
## 三、API 资源—动作—条件矩阵
|
||||
|
||||
图例:`authn`=需登录;`admin`=需 `role-admin`;`proj`=需 `requireProjectAccess`;`—`=未挂对象级授权(Phase 1 补齐)
|
||||
|
||||
| 路由 | authn | admin | proj | Phase 0 备注 |
|
||||
|---|---:|---:|---:|---|
|
||||
| POST `/api/v1/projects` | ✓ | — | — | 创建人来自 token |
|
||||
| GET `/api/v1/projects` | ✓ | — | — | 列表按 user_id 过滤 |
|
||||
| GET `/api/v1/projects/{id}` | ✓ | — | ✓ | |
|
||||
| GET `/api/v1/projects/{id}/workflows` | ✓ | — | ✓ | |
|
||||
| PUT `/api/v1/projects/{id}/active-workflow` | ✓ | — | ✓ | |
|
||||
| POST `/api/v1/projects/{id}/workflows/{key}/run` | ✓ | — | ✓ | |
|
||||
| GET `/api/v1/projects/{id}/workflows/{key}/runs` | ✓ | — | ✓ | |
|
||||
| GET `/api/v1/projects/{id}/lineage` | ✓ | — | ✓ | |
|
||||
| GET `/api/v1/projects/{id}/documents` | ✓ | — | ✓ | |
|
||||
| POST/GET `/api/v1/projects/{id}/assets` | ✓ | — | ✓ | |
|
||||
| GET `/api/v1/workflows` | ✓ | — | — | |
|
||||
| POST `/api/v1/chat` | ✓ | — | — | user_id 来自 principal |
|
||||
| POST/GET `/api/v1/chat/stream` | ✓ | — | — | SSE;principal 强制 |
|
||||
| GET `/api/v1/chat/turns/{id}` | ✓ | — | — | |
|
||||
| POST/GET `/api/v1/tasks/run/stream` | ✓ | — | — | |
|
||||
| POST `/api/v1/tasks/runs` 等 | ✓ | — | 部分 | task_run_auth |
|
||||
| POST `/api/v1/admin/workspaces/reconcile` | ✓ | ✓ | — | |
|
||||
| GET/PUT `/api/v1/context/user*` | ✓ | — | — | |
|
||||
| GET `/api/v1/context/project` | ✓ | — | — | |
|
||||
| GET/POST `/api/v1/chat/sessions` 等 | ✓ | — | — | 会话归属校验 |
|
||||
| GET/POST `/api/v1/freeform-documents*` | ✓ | — | — | owner 校验在 service |
|
||||
| GET/POST `/api/v1/docgov/*` | ✓ | — | — | DocGov 三权 |
|
||||
| POST `/api/v1/auth/logout` 等 | ✓ | — | — | |
|
||||
| GET/POST `/api/v1/admin/users` | ✓ | ✓ | — | |
|
||||
| GET/PUT `/api/v1/admin/config` | ✓ | ✓ | — | |
|
||||
|
||||
## 四、Phase 0 已知 P0-gap(→ Phase 1)
|
||||
|
||||
| 缺口 | 说明 |
|
||||
|---|---|
|
||||
| 无 DB 时 authz 降级 | `authorizer.enabled()==false` 时任意已登录用户可访问任意 project_id(仅 dev/stub) |
|
||||
| localStorage RBAC | 前端按钮可见性仍非服务端 capabilities |
|
||||
| 阶段/文档 ABAC | 未实施;BD 跨阶段隔离在 Phase 3 |
|
||||
|
||||
## 五、Phase 0 验收对照
|
||||
|
||||
| 门禁 | 验证方式 |
|
||||
|---|---|
|
||||
| 无身份切换 UI | `scripts/check-prod-bundle.sh` + 人工 |
|
||||
| 匿名 API 401 | `TestP0_AnonymousBusinessAPIReturns401` |
|
||||
| X-User-ID 无效 | `TestP0_XUserIDCannotAuthenticate` |
|
||||
| body user_id 不覆盖 principal | `TestP0_BodyUserIDCannotOverridePrincipal` |
|
||||
| 生产无种子用户 | `TestMemoryStore_MainEnvNoSeedUsers` |
|
||||
| main 禁止 AllowInMemory | `TestValidateProductionSecrets_RejectsAllowInMemory` |
|
||||
| CORS 无 `*` | `TestP0_CORSAllowlist` |
|
||||
@@ -0,0 +1,312 @@
|
||||
# 项目全面审计 - 文档索引
|
||||
|
||||
> **HISTORICAL(2026-09-12 初审快照)**
|
||||
> **当前发布/缺口 SSOT** → [../remediation/gap-matrix.md](../remediation/gap-matrix.md)
|
||||
> **协作焦点** → [../ops/CURRENT.md](../ops/CURRENT.md)
|
||||
> **Agent 工作方式** → [AGENTS.md](../../AGENTS.md) · [PROJECT.md](../../PROJECT.md)
|
||||
|
||||
**审计日期**: 2026-09-12
|
||||
**项目**: Chat-Agent-System
|
||||
**审计状态**: 历史索引(下方 5.7/10 为初审结论,勿作 live status)
|
||||
|
||||
---
|
||||
|
||||
## 核心文档(按阅读顺序推荐)
|
||||
|
||||
### 0️⃣ 当前状态(Live SSOT)
|
||||
|
||||
**文件**: `2026-09-12-remediation-gap-matrix.md`
|
||||
**协作**: `.doc/ops/CURRENT.md` · `AGENTS.md` · `PROJECT.md`
|
||||
**用途**: 发布缺口、Codex 再审计闭环证据、发布门禁勾选
|
||||
|
||||
---
|
||||
|
||||
### 1️⃣ 从这里开始:审计总结报告(历史)
|
||||
**文件**: `2026-09-12-audit-summary-report.md`
|
||||
**用途**: 项目整体现状、关键数字、风险评估
|
||||
**适合**: 项目经理、技术负责人、快速概览
|
||||
**阅读时间**: 15-20 分钟
|
||||
|
||||
**关键内容**:
|
||||
- 项目评分及各维度打分
|
||||
- 12 个已确认缺陷分布(critical/high/medium)
|
||||
- 未完成功能清单
|
||||
- 开发库数据污染现状(88 个测试定义)
|
||||
- 整改时间与资源规划
|
||||
- 立即行动建议
|
||||
|
||||
---
|
||||
|
||||
### 2️⃣ 详细缺陷与整改:综合整改方案
|
||||
**文件**: `2026-09-12-comprehensive-audit-and-remediation-plan.md`
|
||||
**用途**: 12 个缺陷的详细分析 + 3 个新功能的整改方案
|
||||
**适合**: 架构师、资深开发工程师
|
||||
**阅读时间**: 45-60 分钟
|
||||
|
||||
**关键内容**:
|
||||
- BUG-01 到 BUG-12 的代码现场与后果分析
|
||||
- 5 个 high 缺陷的深层原因
|
||||
- 3 个 MISSING 新功能的实现设计
|
||||
- 3 个 Phase (A/B/C) 的整改计划
|
||||
- 风险预案与建议
|
||||
|
||||
---
|
||||
|
||||
### 3️⃣ 可执行的任务拆分:任务清单与验收
|
||||
**文件**: `2026-09-12-remediation-tasks-and-acceptance-checklist.md`
|
||||
**用途**: 具体的代码修改指引、单元测试框架、验收标准
|
||||
**适合**: 开发工程师、QA、代码审查人
|
||||
**阅读时间**: 60-90 分钟
|
||||
|
||||
**关键内容**:
|
||||
- Task A1-A6:关键缺陷修复(15h)
|
||||
- 每个 Task 的修改文件、代码片段、测试用例
|
||||
- 验收标准与预计工作量
|
||||
- Task B1-B3:高优先级新功能(26h)
|
||||
- 受控终止 API 的完整实现
|
||||
- E2E 测试框架与运行命令
|
||||
- 项目上下文快照的数据模型与集成点
|
||||
- Task C1-C7:完善与发布(20h)
|
||||
- 全套验收检查表
|
||||
|
||||
---
|
||||
|
||||
### 4️⃣ 快速参考与速查:快速指南
|
||||
**文件**: `2026-09-12-quick-reference-guide.md`
|
||||
**用途**: 问题症状→原因→解决方案的快速诊断
|
||||
**适合**: 所有开发人员、值班人员
|
||||
**阅读时间**: 5-10 分钟(按需查阅)
|
||||
|
||||
**关键内容**:
|
||||
- 10 个常见症状的诊断矩阵
|
||||
- 代码热点地图(哪个文件有哪个 bug)
|
||||
- 整改优先级排序
|
||||
- 代码修改检查清单
|
||||
- 数据库迁移清单
|
||||
- 测试命令参考
|
||||
- API 变动汇总
|
||||
- 常见问题 Q&A
|
||||
|
||||
---
|
||||
|
||||
## 配套参考文档
|
||||
|
||||
### 业务需求原文
|
||||
**文件**: `2026-09-12-three-workflows-strict-governance-remediation.md`
|
||||
**用途**: 业务决策、验收标准的原始出处
|
||||
**适合**: 产品、架构、QA(需要理解业务背景)
|
||||
|
||||
**关键章节**:
|
||||
- 第 3 章:不可违反的业务规则
|
||||
- 第 7 章:验收标准(7.1-7.5)
|
||||
- 第 8-9 章:已确认决策与实施解释
|
||||
|
||||
---
|
||||
|
||||
## 快速导航
|
||||
|
||||
### 我是 PM/项目经理
|
||||
```
|
||||
1. 读 audit-summary-report.md 第一部分(总体评估)
|
||||
2. 重点关注第九章(建议行动计划)
|
||||
3. 查阅 quick-reference-guide.md 第三部分(优先级排序)
|
||||
4. 预估资源与时间
|
||||
```
|
||||
|
||||
### 我是后端开发
|
||||
```
|
||||
1. 读 quick-reference-guide.md(快速了解要改什么)
|
||||
2. 针对每个 task 查阅 remediation-tasks-and-acceptance-checklist.md
|
||||
3. 参考 comprehensive-audit-and-remediation-plan.md 理解原因
|
||||
4. 按照 task 中的"修改文件"和"代码片段"进行开发
|
||||
5. 执行"测试用例"部分验证修改
|
||||
```
|
||||
|
||||
### 我是 QA/测试工程师
|
||||
```
|
||||
1. 读 audit-summary-report.md 第十一章(验收标准清单)
|
||||
2. 查阅 quick-reference-guide.md 第五部分(检查清单)
|
||||
3. 针对每个 task 制定测试计划
|
||||
4. 执行 comprehensive-audit-and-remediation-plan.md 中的验收标准
|
||||
5. 特别关注 remediation-tasks 的 E2E 部分
|
||||
```
|
||||
|
||||
### 我是前端工程师
|
||||
```
|
||||
1. 读 quick-reference-guide.md 第三部分(了解哪些前端需改)
|
||||
2. 查看 BUG-09、BUG-10、BUG-12 的具体改动
|
||||
3. 关注 comprehensive-audit 中的前端相关缺陷
|
||||
4. 参考 remediation-tasks 的 API 变动部分
|
||||
```
|
||||
|
||||
### 我是架构师/技术负责人
|
||||
```
|
||||
1. 读 audit-summary-report.md(整体判定)
|
||||
2. 深入 comprehensive-audit-and-remediation-plan.md(详细分析)
|
||||
3. 关注第八章(架构建议)和第十二章(结语)
|
||||
4. 制定整改计划和资源分配
|
||||
```
|
||||
|
||||
### 我要处理现场问题
|
||||
```
|
||||
1. 查询 quick-reference-guide.md 第五部分(症状→原因→解决)
|
||||
2. 找到对应的 bug 号
|
||||
3. 查阅 comprehensive-audit 的完整分析
|
||||
4. 按照 remediation-tasks 中的修复步骤操作
|
||||
5. 若需临时绕过,参考 quick-reference-guide 的建议
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文档关系图
|
||||
|
||||
```
|
||||
入口文档
|
||||
↓
|
||||
audit-summary-report.md ← 总体评估与建议
|
||||
↓
|
||||
├→ comprehensive-audit-and-remediation-plan.md ← 详细缺陷分析
|
||||
│ ├─ BUG-01 到 BUG-12 详解
|
||||
│ ├─ MISSING-01 到 MISSING-04 详解
|
||||
│ └─ Phase A/B/C 整改计划
|
||||
│
|
||||
├→ remediation-tasks-and-acceptance-checklist.md ← 可执行任务
|
||||
│ ├─ Task A1-A6(关键缺陷)
|
||||
│ ├─ Task B1-B3(新功能)
|
||||
│ └─ 验收检查表
|
||||
│
|
||||
├→ quick-reference-guide.md ← 快速查询
|
||||
│ ├─ 症状诊断矩阵
|
||||
│ ├─ 代码热点地图
|
||||
│ ├─ 优先级排序
|
||||
│ └─ 常见问题 Q&A
|
||||
│
|
||||
└→ three-workflows-strict-governance-remediation.md ← 业务背景
|
||||
├─ 业务需求与决策
|
||||
├─ 验收标准
|
||||
└─ 来源证据
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 关键指标速查
|
||||
|
||||
| 指标 | 数值 | 位置 |
|
||||
|---|---|---|
|
||||
| 项目完成度 | 70% | audit-summary-report.md:1.2 |
|
||||
| 总体评分 | 5.7/10 | audit-summary-report.md:1.1 |
|
||||
| 缺陷总数 | 12 个 | audit-summary-report.md:2.1 |
|
||||
| Critical 缺陷 | 3 个 | audit-summary-report.md:2.1 |
|
||||
| 整改工作量 | 61h | audit-summary-report.md:9.1 |
|
||||
| 单元测试覆盖率 | 85% | audit-summary-report.md:1.2 |
|
||||
| E2E 覆盖率 | 0% | audit-summary-report.md:1.2 |
|
||||
| 开发库污染定义 | 88 个 | audit-summary-report.md:4.1 |
|
||||
|
||||
---
|
||||
|
||||
## 立即行动清单
|
||||
|
||||
**今天需要做的事**(第一天):
|
||||
|
||||
```
|
||||
[ ] 技术负责人读 audit-summary-report.md(20 分钟)
|
||||
[ ] 架构师读 comprehensive-audit-and-remediation-plan.md(60 分钟)
|
||||
[ ] 后端 A 开发师启动 Task A1(2h)- 项目生命周期修复
|
||||
[ ] 后端 A 开发师启动 Task A4(2h)- 对话推进新服务
|
||||
[ ] QA 准备 E2E 测试框架(同步进行)
|
||||
[ ] 全队讨论确认整改计划(30 分钟)
|
||||
```
|
||||
|
||||
**本周目标**(5 天):
|
||||
|
||||
```
|
||||
Day 1: 完成 Phase A 关键缺陷修复(15h)
|
||||
Day 2-3: 启动 Phase B 新功能开发并行(26h)
|
||||
Day 4-5: Phase C 完善与发布准备(20h)
|
||||
+ 每晚运行完整测试套件验证
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见路径快查
|
||||
|
||||
**"完成工作流后项目仍然是 active"**
|
||||
→ quick-reference-guide.md 第二部分 症状 1
|
||||
→ comprehensive-audit 第二部分 BUG-01
|
||||
→ remediation-tasks 的 Task A1
|
||||
|
||||
**"对话推进不起作用"**
|
||||
→ quick-reference-guide.md 第二部分 症状 3
|
||||
→ comprehensive-audit 第二部分 BUG-04
|
||||
→ remediation-tasks 的 Task A4
|
||||
|
||||
**"禁用文档仍能被打开"**
|
||||
→ quick-reference-guide.md 第二部分 症状 2
|
||||
→ comprehensive-audit 第二部分 BUG-05
|
||||
→ remediation-tasks 的 Task A5
|
||||
|
||||
**"激活 token 可能被重复使用"**
|
||||
→ quick-reference-guide.md 第二部分 症状 6
|
||||
→ comprehensive-audit 第二部分 BUG-06
|
||||
→ remediation-tasks 的 Task A6
|
||||
|
||||
**"无法运行测试流程"**
|
||||
→ quick-reference-guide.md 第二部分 症状 7
|
||||
→ comprehensive-audit 第三部分 MISSING-06
|
||||
→ remediation-tasks 的 Phase B 开始
|
||||
|
||||
**"需要完整 E2E 验证"**
|
||||
→ comprehensive-audit 第三部分 MISSING-04
|
||||
→ remediation-tasks 的 Task B2
|
||||
|
||||
---
|
||||
|
||||
## 发布检查清单
|
||||
|
||||
**上线前必须确认**:
|
||||
|
||||
```
|
||||
整改完成度:
|
||||
□ Phase A 全部 PASS
|
||||
□ Phase B 全部 PASS
|
||||
□ Phase C 全部 PASS
|
||||
|
||||
测试覆盖:
|
||||
□ 单元测试覆盖率 ≥ 85%
|
||||
□ E2E 测试三工作流完整链路
|
||||
□ 并发测试通过
|
||||
□ 数据库迁移兼容性验证
|
||||
|
||||
业务验收:
|
||||
□ 验收标准 7.1-7.5 全部满足
|
||||
□ 不存在 critical 缺陷
|
||||
□ 安全性审计通过
|
||||
|
||||
运维就绪:
|
||||
□ 数据库备份与恢复方案
|
||||
□ 审计日志完整
|
||||
□ 监控告警配置
|
||||
□ 性能基准测试
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 文档维护
|
||||
|
||||
这套审计文档为 v1.0,应定期更新:
|
||||
|
||||
- **每完成一个 task**: 更新对应 task 的状态
|
||||
- **每发现新缺陷**: 补充到 comprehensive-audit-and-remediation-plan.md
|
||||
- **每月**: 做一次整体进度评估和文档更新
|
||||
|
||||
---
|
||||
|
||||
**审计完毕**
|
||||
|
||||
**下一步**: 确认整改计划,进入实施阶段
|
||||
|
||||
**总体建议**: 立即启动 Phase A(关键缺陷),并行启动 E2E 测试框架,一周内完成所有整改。
|
||||
|
||||
---
|
||||
|
||||
*本索引最后更新于 2026-09-12 15:05 UTC*
|
||||
@@ -0,0 +1,5 @@
|
||||
# 问题发现与分析
|
||||
|
||||
审计、根因分析、授权基线与矩阵。**不含**具体改码步骤(链到 `../remediation/`)。
|
||||
|
||||
索引:[INDEX.md](./INDEX.md)
|
||||
@@ -0,0 +1,35 @@
|
||||
# 授权实施基线快照(Phase 0)
|
||||
|
||||
- **分支**:`dev`
|
||||
- **Commit SHA**:`bb3f3a1b93eaf4bbd4a7c26a70714a3320d455d3`
|
||||
- **Goose schema**:`00020`(`00020_2026-09-12-task-run-worker-lease.sql`)
|
||||
- **规格文档**:`.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md`
|
||||
|
||||
## 环境矩阵
|
||||
|
||||
| 环境 | 分支 | Compose | HTTP | DB | 数据路径 |
|
||||
|---|---|---|---|---|---|
|
||||
| 开发 | dev | agent-dev | 8080 | 5433 | data/dev |
|
||||
| 测试 | test | agent-test | 8081 | 5434 | data/test |
|
||||
| 生产 | main | agent-main | 8000 | 5435 | data/main |
|
||||
| 共享 KB | — | agent-infra | — | 5432 | data/shared/kb |
|
||||
|
||||
## 工作流 v1 种子(published)
|
||||
|
||||
| workflow_key | 说明 | 备注 |
|
||||
|---|---|---|
|
||||
| `main` | 商务对接 v1 单阶段包装 | 真实阶段仍在 bizdev 硬编码 |
|
||||
| `product_manager` | 产品经理 v1 单阶段 | 未驱动 squad 五步 |
|
||||
| `test_manager` | 测试经理 v1 单阶段 | 未驱动结构化 coverage |
|
||||
|
||||
v2 将以新 version 发布,不覆盖 v1 hash。
|
||||
|
||||
## 验证命令(基线通过)
|
||||
|
||||
```bash
|
||||
go test -short -timeout 8m \
|
||||
./internal/auth/... ./internal/authz/... ./internal/workflowdef/... \
|
||||
./internal/projectinstance/... ./internal/projectworkflow/... ./internal/server/...
|
||||
|
||||
cd web && npm test && npm run build
|
||||
```
|
||||
@@ -0,0 +1,23 @@
|
||||
# API 授权矩阵 v2(Phase 0 基线)
|
||||
|
||||
> 基线 commit:`bb3f3a1b93eaf4bbd4a7c26a70714a3320d455d3`
|
||||
> 策略:默认拒绝;未知路由拒绝;跨项目 403/404 统一。
|
||||
|
||||
| 路由 | Resource | Action | Owner | 负例(未授权) |
|
||||
|---|---|---|---|---|
|
||||
| POST /api/v1/auth/login | session | create | auth | 匿名可访问(公开) |
|
||||
| GET /api/v1/auth/me | user | read_self | auth | 401 无 token |
|
||||
| GET /api/v1/projects | project | list | projectworkflow | 401 匿名 |
|
||||
| POST /api/v1/projects | project | create | projectworkflow | 401;403 无 project:create |
|
||||
| GET /api/v1/projects/{id} | project | read | authz | 403 非成员 |
|
||||
| GET /api/v1/projects/{id}/lineage | lineage | read | projectworkflow | 403 跨项目 |
|
||||
| GET /api/v1/projects/{id}/workflows/{key}/runs | workflow_run | list | projectworkflow | 403 跨项目 |
|
||||
| POST /api/v1/projects/{id}/workflows/{key}/run | task | run | bizdev+stage | 403 错 task/stage |
|
||||
| GET /api/v1/tasks/runs/{id} | task_run | view | taskrun | 403 非 owner/非 owner 成员 |
|
||||
| POST /api/v1/tasks/runs/{id}/cancel | task_run | cancel | taskrun | 403 取消他人 |
|
||||
| POST /api/v1/chat/stream | chat | send | chat+stage | 403 无阶段权限 |
|
||||
| GET /api/v1/docgov/* | document | * | docgov+duty | 403 非职责人 |
|
||||
| GET /api/v1/admin/* | admin | * | authz RBAC | 403 非 admin/细粒度 perm |
|
||||
| GET /health, /api/v1/health | system | health | server | 公开 |
|
||||
|
||||
完整路由枚举见 `internal/server/server.go` Routes();Phase 1 起每个项目子资源必须经 `requireProjectAccess`。
|
||||
@@ -1,35 +1,3 @@
|
||||
# 授权实施基线快照(Phase 0)
|
||||
# 已迁移
|
||||
|
||||
- **分支**:`dev`
|
||||
- **Commit SHA**:`bb3f3a1b93eaf4bbd4a7c26a70714a3320d455d3`
|
||||
- **Goose schema**:`00020`(`00020_2026-09-12-task-run-worker-lease.sql`)
|
||||
- **规格文档**:`.doc/2026-09-12-permissions-settings-three-workflows-implementation-plan.md`
|
||||
|
||||
## 环境矩阵
|
||||
|
||||
| 环境 | 分支 | Compose | HTTP | DB | 数据路径 |
|
||||
|---|---|---|---|---|---|
|
||||
| 开发 | dev | agent-dev | 8080 | 5433 | data/dev |
|
||||
| 测试 | test | agent-test | 8081 | 5434 | data/test |
|
||||
| 生产 | main | agent-main | 8000 | 5435 | data/main |
|
||||
| 共享 KB | — | agent-infra | — | 5432 | data/shared/kb |
|
||||
|
||||
## 工作流 v1 种子(published)
|
||||
|
||||
| workflow_key | 说明 | 备注 |
|
||||
|---|---|---|
|
||||
| `main` | 商务对接 v1 单阶段包装 | 真实阶段仍在 bizdev 硬编码 |
|
||||
| `product_manager` | 产品经理 v1 单阶段 | 未驱动 squad 五步 |
|
||||
| `test_manager` | 测试经理 v1 单阶段 | 未驱动结构化 coverage |
|
||||
|
||||
v2 将以新 version 发布,不覆盖 v1 hash。
|
||||
|
||||
## 验证命令(基线通过)
|
||||
|
||||
```bash
|
||||
go test -short -timeout 8m \
|
||||
./internal/auth/... ./internal/authz/... ./internal/workflowdef/... \
|
||||
./internal/projectinstance/... ./internal/projectworkflow/... ./internal/server/...
|
||||
|
||||
cd web && npm test && npm run build
|
||||
```
|
||||
本文档已迁至 [audit/authorization-baseline-2026-09-12.md](audit/authorization-baseline-2026-09-12.md)。请勿在此编辑。
|
||||
|
||||
@@ -1,23 +1,3 @@
|
||||
# API 授权矩阵 v2(Phase 0 基线)
|
||||
# 已迁移
|
||||
|
||||
> 基线 commit:`bb3f3a1b93eaf4bbd4a7c26a70714a3320d455d3`
|
||||
> 策略:默认拒绝;未知路由拒绝;跨项目 403/404 统一。
|
||||
|
||||
| 路由 | Resource | Action | Owner | 负例(未授权) |
|
||||
|---|---|---|---|---|
|
||||
| POST /api/v1/auth/login | session | create | auth | 匿名可访问(公开) |
|
||||
| GET /api/v1/auth/me | user | read_self | auth | 401 无 token |
|
||||
| GET /api/v1/projects | project | list | projectworkflow | 401 匿名 |
|
||||
| POST /api/v1/projects | project | create | projectworkflow | 401;403 无 project:create |
|
||||
| GET /api/v1/projects/{id} | project | read | authz | 403 非成员 |
|
||||
| GET /api/v1/projects/{id}/lineage | lineage | read | projectworkflow | 403 跨项目 |
|
||||
| GET /api/v1/projects/{id}/workflows/{key}/runs | workflow_run | list | projectworkflow | 403 跨项目 |
|
||||
| POST /api/v1/projects/{id}/workflows/{key}/run | task | run | bizdev+stage | 403 错 task/stage |
|
||||
| GET /api/v1/tasks/runs/{id} | task_run | view | taskrun | 403 非 owner/非 owner 成员 |
|
||||
| POST /api/v1/tasks/runs/{id}/cancel | task_run | cancel | taskrun | 403 取消他人 |
|
||||
| POST /api/v1/chat/stream | chat | send | chat+stage | 403 无阶段权限 |
|
||||
| GET /api/v1/docgov/* | document | * | docgov+duty | 403 非职责人 |
|
||||
| GET /api/v1/admin/* | admin | * | authz RBAC | 403 非 admin/细粒度 perm |
|
||||
| GET /health, /api/v1/health | system | health | server | 公开 |
|
||||
|
||||
完整路由枚举见 `internal/server/server.go` Routes();Phase 1 起每个项目子资源必须经 `requireProjectAccess`。
|
||||
本文档已迁至 [audit/authorization-matrix-v2.md](audit/authorization-matrix-v2.md)。请勿在此编辑。
|
||||
|
||||
@@ -0,0 +1,684 @@
|
||||
# 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]
|
||||
|
||||
建议把目标系统定义为一个“受控的项目工作流平台”,核心由五层组成:
|
||||
|
||||
```text
|
||||
账户主体 ── 组织/系统角色 ── 项目成员关系
|
||||
│
|
||||
▼
|
||||
不可变工作流版本 ──> 项目工作流实例 ──> 阶段实例 ──> 文档任务实例
|
||||
│ │
|
||||
├─ 对话参与策略 └─ 编制/审核/批准职责
|
||||
├─ 文档可见策略
|
||||
└─ 阶段推进门禁 + 审计 + 通知
|
||||
```
|
||||
|
||||
最重要的产品决策是:
|
||||
|
||||
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 在商务阶段可对话,进入研发阶段后不可对话且不可看研发文档”。建议采用组合策略:
|
||||
|
||||
```text
|
||||
允许 = 已认证
|
||||
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 定义结构
|
||||
|
||||
```text
|
||||
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`。推荐交互:
|
||||
|
||||
```text
|
||||
选择工作流版本
|
||||
→ 配置阶段/文档开关
|
||||
→ 指派每份启用文档的三权
|
||||
→ 系统校验
|
||||
→ 生成只读预览与 plan_hash
|
||||
→ 用户二次确认
|
||||
→ 单事务创建实例/快照/首阶段/文档任务/审计
|
||||
```
|
||||
|
||||
激活确认弹窗应明确展示:工作流名称和版本、启用阶段数、启用/关闭文档数、三权缺口、激活后哪些配置会冻结、当前参与者权限将如何变化。用户勾选“我理解激活后不能直接修改”并再次点击确认。
|
||||
|
||||
服务端不能只信任 `confirmed=true`。建议 `POST /activation-preview` 返回短期 `confirmation_token + plan_hash + expected_project_version`;真正激活时必须三者一致。若期间成员、责任人、模板或项目配置变化,返回 409 和差异摘要,要求重新预览确认。
|
||||
|
||||
### 9.3 工作流实例状态机
|
||||
|
||||
```text
|
||||
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 阶段状态机
|
||||
|
||||
```text
|
||||
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` 继续负责正文版本和受控生命周期。
|
||||
|
||||
```text
|
||||
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 关键约束
|
||||
|
||||
```sql
|
||||
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
|
||||
|
||||
```text
|
||||
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`](../internal/server/auth_middleware.go),统一保护非公开 API;[`internal/db/migrate.go`](../internal/db/migrate.go),Goose 迁移执行,访问于 2026-09-11。
|
||||
[^2]: 仓库源码,[`deploy/app/Dockerfile`](../deploy/app/Dockerfile),包含 Node 前端构建与 `web/dist` 复制,访问于 2026-09-11。
|
||||
[^3]: 仓库源码,[`internal/bizdev/service.go`](../internal/bizdev/service.go),数据库连接、迁移及生产失败关闭逻辑,访问于 2026-09-11。
|
||||
[^4]: 仓库源码,[`internal/auth/store.go`](../internal/auth/store.go) 与 [`internal/auth/service.go`](../internal/auth/service.go),内存用户存储与进程内 token,访问于 2026-09-11。
|
||||
[^5]: 仓库源码,[`web/src/App.tsx`](../web/src/App.tsx) 与 [`web/src/data/storage.ts`](../web/src/data/storage.ts),角色、人员、项目和交付物的浏览器持久化,访问于 2026-09-11。
|
||||
[^6]: 仓库源码,[`internal/server/auth_handlers.go`](../internal/server/auth_handlers.go),管理员接口以 `role-admin` 硬编码判断;[`web/src/components/admin/AdminSettingsModal.tsx`](../web/src/components/admin/AdminSettingsModal.tsx),角色权限编辑主要调用前端状态,访问于 2026-09-11。
|
||||
[^7]: 仓库源码,[`internal/projectworkflow/catalog.go`](../internal/projectworkflow/catalog.go),三个静态工作流及单一 stage/task 定义,访问于 2026-09-11。
|
||||
[^8]: 仓库源码,[`internal/projectworkflow/service.go`](../internal/projectworkflow/service.go) 与 [`deploy/postgres/goose/00010_2026-09-11-project-workflows-and-lineage.sql`](../deploy/postgres/goose/00010_2026-09-11-project-workflows-and-lineage.sql),新项目默认 `main` 及当前切换模型,访问于 2026-09-11。
|
||||
[^9]: 仓库源码,[`web/src/components/workflow/ProjectWorkflowSwitcher.tsx`](../web/src/components/workflow/ProjectWorkflowSwitcher.tsx),直接切换及冲突后自动重试行为,访问于 2026-09-11。
|
||||
[^10]: 仓库源码,[`web/src/types/workbench.ts`](../web/src/types/workbench.ts) 与 [`web/src/components/project/ProjectMembersModal.tsx`](../web/src/components/project/ProjectMembersModal.tsx),项目成员角色与文档职责混用,访问于 2026-09-11。
|
||||
[^11]: 仓库源码,[`web/src/types/workbench.ts`](../web/src/types/workbench.ts) 与 [`internal/projectworkflow/types.go`](../internal/projectworkflow/types.go),固定阶段枚举和自由文本设备类型,访问于 2026-09-11。
|
||||
[^12]: OWASP Cheat Sheet Series, “[Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
[^13]: NIST, “[Role Based Access Control](https://csrc.nist.gov/Projects/Role-Based-Access-Control),” 含 INCITS 359 RBAC 模型说明,更新于 2026-03-04。
|
||||
[^14]: NIST, Kuhn, Coyne, Weil, “[Adding Attributes to Role-Based Access Control](https://csrc.nist.gov/files/pubs/journal/2010/06/adding-attributes-to-rolebased-access-control/final/docs/kuhn-coyne-weil-10.pdf),” 2010。
|
||||
[^15]: NIST, “[SP 800-63B-4: Digital Identity Guidelines — Authentication and Authenticator Management](https://csrc.nist.gov/pubs/sp/800/63/B/4/final),” 2025-07。
|
||||
[^16]: OWASP Cheat Sheet Series, “[File Upload Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
[^17]: U.S. FDA, “[Quality Management System Regulation (QMSR)](https://www.fda.gov/medical-devices/postmarket-requirements-devices/quality-management-system-regulation-qmsr),” 更新于 2026-02-02。
|
||||
[^18]: ISO, “[ISO 13485:2016 — Medical devices — Quality management systems — Requirements for regulatory purposes](https://www.iso.org/standard/59752.html),” 2016,2025 年复审确认。
|
||||
[^19]: Electronic Code of Federal Regulations, “[21 CFR § 11.10 — Controls for closed systems](https://www.ecfr.gov/current/title-21/chapter-I/subchapter-A/part-11/subpart-B/section-11.10),” 访问于 2026-09-11。
|
||||
[^20]: U.S. FDA, “[Part 11, Electronic Records; Electronic Signatures — Scope and Application](https://www.fda.gov/regulatory-information/search-fda-guidance-documents/part-11-electronic-records-electronic-signatures-scope-and-application),” 2003-09,访问于 2026-09-11。
|
||||
[^21]: OWASP Cheat Sheet Series, “[Logging Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html),” 访问于 2026-09-11。
|
||||
[^22]: 仓库源码,[`internal/server/server.go`](../internal/server/server.go),当前 CORS 允许任意来源,访问于 2026-09-11。
|
||||
@@ -0,0 +1,680 @@
|
||||
# 项目全面审计与整改方案
|
||||
|
||||
> **HISTORICAL** — 缺陷详解与 Phase 设计档案。执行状态以 [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) 为准。
|
||||
|
||||
**日期**:2026-09-12
|
||||
**编制**:代码审计
|
||||
**状态**:待执行
|
||||
**范围**:功能完整性、实现缺陷、潜在bug 及整改优先级
|
||||
|
||||
---
|
||||
|
||||
## 一、执行现状总结
|
||||
|
||||
### 1.1 已完成的工作
|
||||
|
||||
| 项目 | 完成度 | 说明 |
|
||||
|---|---|---|
|
||||
| 业务决策文档 | ✅ 100% | `.doc/2026-09-12-three-workflows-strict-governance-remediation.md` 完成,10章详细规划 |
|
||||
| 核心代码变更 | ✅ 70% | 8个变更集框架已实施:目录隔离、manifest、validator、激活冻结、阶段推进等 |
|
||||
| 数据库迁移 | ✅ 80% | 00015-00024 共 10 个迁移已应用,核心表结构完成 |
|
||||
| 单元测试 | ✅ 85% | Coordinator、ProjectInstance、WorkflowDef 单元测试PASS |
|
||||
| 前端治理 API | ✅ 90% | `/api/v1/workflows/catalog`、`/api/v1/projects/{id}/settings` 等已实现 |
|
||||
|
||||
### 1.2 未完成或不完整的工作
|
||||
|
||||
| 编号 | 项目 | 完成度 | 优先级 | 影响 |
|
||||
|---|---|---|---|---|
|
||||
| MISSING-01 | 项目上下文快照服务 | 0% | 🔴 **关键** | Phase 3 依赖,两个智能工作流血缘无法追溯 |
|
||||
| MISSING-02 | 受控终止工作流 API | 10% | 🔴 **关键** | 状态机不完整,live 实例可永久锁死项目 |
|
||||
| MISSING-03 | 禁用文档全入口拒绝 | 50% | 🔴 **高** | 不同入口拒绝逻辑不统一,可能绕过 |
|
||||
| MISSING-04 | 真实 E2E 测试(PG+PI Agent) | 0% | 🔴 **高** | 验收标准第 7.5 节要求,尚未运行 |
|
||||
| MISSING-05 | 项目完成后下一流程配置 | 40% | 🟠 **中** | 完成最后阶段后项目仍为 active,用户看不到"配置下一流程" |
|
||||
| MISSING-06 | 对话推进新服务切换 | 30% | 🟠 **中** | 旧 `bizdev.ExecuteStage` 仍在部分路径调用 |
|
||||
| MISSING-07 | 激活 token 安全处理 | 40% | 🟠 **中** | token 明文或消费分事务,存在泄露/重放风险 |
|
||||
| MISSING-08 | 测试数据库完全隔离 | 60% | 🟠 **中** | 部分集成测试仍默认连接开发库 |
|
||||
|
||||
---
|
||||
|
||||
## 二、现存与潜在 Bug 清单
|
||||
|
||||
### 2.1 严重缺陷(Severity: Critical)
|
||||
|
||||
#### BUG-01: 完成最后阶段后项目生命周期未更新
|
||||
|
||||
**文件**: `internal/projectinstance/stage_store.go:128-158`, `internal/projectinstance/service.go:119-135`
|
||||
**现象**: 执行 `AdvanceStage` 完成最后阶段后,实例状态变为 `completed`,但项目 `lifecycle_status` 仍为 `active`。
|
||||
|
||||
**代码现场**:
|
||||
```go
|
||||
// stage_store.go:AdvanceStage
|
||||
after, err := s.store.AdvanceStage(ctx, instanceID, in.StageKey, in.ExpectedConfigRevision)
|
||||
// ... 只更新实例,未更新项目
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 项目创建者无法看到"配置下一工作流"选项
|
||||
- 前端无法识别项目已完成,可能显示旧流程按钮
|
||||
- 项目实际生命周期与数据库记录不一致
|
||||
|
||||
**验收标准冲突**: 7.4 "最后一阶段确认后实例为 completed,项目立即可配置下一流程"
|
||||
|
||||
**整改方案**:
|
||||
1. `AdvanceStage` 在同一事务中检查是否为最后阶段
|
||||
2. 若是最后阶段,同时更新 `projects.lifecycle_status` 为 `planning`
|
||||
3. 清空 `projects.current_workflow_instance_id`(可选,视数据模型)
|
||||
4. 写审计事件 `ProjectWorkflowCompleted`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-02: 推进事务内仍强制更新文档批准状态
|
||||
|
||||
**文件**: `internal/projectinstance/stage_store.go:71-158`
|
||||
**现象**: 执行阶段推进时,SQL 语句中有类似逻辑将启用任务的文档强制设置为 `approved`。
|
||||
|
||||
**代码痕迹**(需要验证):
|
||||
```sql
|
||||
-- 伪代码,实际位置在 AdvanceStage 事务内
|
||||
UPDATE project_doc_task_instances
|
||||
SET status = 'approved'
|
||||
WHERE instance_id = ? AND task_key = ? AND enabled = true;
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 违反业务规则 3.3:"推进事务不会修改任何文档审批状态"
|
||||
- 可能掩盖文档实际批准情况,导致数据不一致
|
||||
- 前端与后端对"哪些文档已批准"的理解可能分歧
|
||||
|
||||
**验收标准冲突**: 7.4 "推进事务不会修改任何文档审批状态"
|
||||
|
||||
**整改方案**:
|
||||
1. 确认 `stage_store.go:AdvanceStage` 中是否存在此 UPDATE 逻辑
|
||||
2. 若存在,删除该 UPDATE 语句
|
||||
3. `AdvanceStage` 只改变阶段状态和实例状态,不触及文档
|
||||
4. 补充单测: `TestAdvanceStage_DoesNotModifyDocumentApprovalStatus`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-03: 禁用文档状态未标记为 `skipped_disabled`
|
||||
|
||||
**文件**: `internal/projectinstance/store.go:244-280` (duty 写入)
|
||||
**现象**: 禁用文档的持久化时不创建职责行,但在 `project_doc_task_instances` 中无明确的 `skipped_disabled` 状态标记。
|
||||
|
||||
**代码现场**:
|
||||
```go
|
||||
// store.go:SaveWorkflowPlan 或类似
|
||||
for _, doc := range docs {
|
||||
if !doc.Enabled {
|
||||
continue // 跳过,不写入
|
||||
}
|
||||
// 只写启用文档
|
||||
}
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 禁用文档没有显式的数据库记录,无法区分"从未创建"与"被禁用"
|
||||
- 运行时查询时无法快速定位哪些文档被禁用,只能通过与定义比对
|
||||
- 审计和恢复时无法追溯禁用历史
|
||||
|
||||
**验收标准冲突**: 3.2 "禁用后实例状态写为 `skipped_disabled`"
|
||||
|
||||
**整改方案**:
|
||||
1. `project_doc_task_instances` 表添加状态枚举支持 `skipped_disabled`
|
||||
2. 激活时为禁用文档创建记录,状态明确设为 `skipped_disabled`
|
||||
3. 查询、拒绝等所有入口统一检查此状态
|
||||
4. 补充测试: `TestDisabledDocumentPersistence` 和 `TestDisabledDocumentRejectionAllEntries`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-04: 对话推进仍调用旧商务执行服务
|
||||
|
||||
**文件**: `internal/coordinator/engine.go:672-811`
|
||||
**现象**: 对话识别 `ADVANCE_STAGE` 意图后,调用 `bizdevSvc.ExecuteStage` 而非新的 `projectinstance.Service.AdvanceStage`。
|
||||
|
||||
**代码现场**:
|
||||
```go
|
||||
// engine.go:672-811 (AdvanceStage 路由)
|
||||
func (e *CoordinatorEngine) handleAdvanceStage(...) {
|
||||
// ...
|
||||
result, err := e.bizdevSvc.ExecuteStage(ctx, ...) // ❌ 旧服务
|
||||
// 应该调用 e.instSvc.AdvanceStage(...)
|
||||
}
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 对话推进绕过新的权限和门禁检查
|
||||
- 可能导致阶段推进状态不一致(新旧实例双轨运行)
|
||||
- 文档审批状态可能被旧 executor 强制改写
|
||||
|
||||
**验收标准冲突**: 3.4 "两种入口都调用同一个 `AdvanceStage` 应用服务"
|
||||
|
||||
**整改方案**:
|
||||
1. 修改 `CoordinatorEngine.handleAdvanceStage` 以调用新服务
|
||||
2. 删除对 `bizdevSvc.ExecuteStage` 的依赖(或标记 deprecated)
|
||||
3. 对话推进需要提取 `workflow_instance_id`(可从项目或上文获取)
|
||||
4. 补充端到端测试: `TestDialogueAdvanceStage_UsesNewService`
|
||||
|
||||
---
|
||||
|
||||
### 2.2 高优先级缺陷(Severity: High)
|
||||
|
||||
#### BUG-05: 禁用文档的拒绝逻辑不一致
|
||||
|
||||
**文件**: 多处
|
||||
**现象**: 不同入口(API、SSE、Agent tool)对禁用文档的拒绝逻辑分散,缺少统一的"fail closed"决策器。
|
||||
|
||||
**问题点**:
|
||||
- `stage_access.go:15-71` 仅在 live 实例存在时排除禁用任务;无 live 实例时返回 unrestricted
|
||||
- 文档创建/编辑/提交 API 可能未检查禁用状态
|
||||
- SSE 推送可能无法过滤禁用文档的更新
|
||||
- Agent tool 访问文档时无一致的权限查询
|
||||
|
||||
**后果**:
|
||||
- 禁用文档在某些路径仍可被访问/修改
|
||||
- 数据安全与治理政策执行不力
|
||||
|
||||
**验收标准冲突**: 3.2 "禁用后…不能通过 task key、对话、SSE、Agent tool 或旧 API 旁路启动"
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 `DocumentAccessDecider` 接口,统一决策逻辑:
|
||||
```go
|
||||
type DocumentAccessDecider interface {
|
||||
CanAccess(ctx context.Context, docTaskInstID int64, action string, userID int64) (bool, error)
|
||||
}
|
||||
```
|
||||
2. 实现检查流程:
|
||||
- 确认 instance 存在且为 live 或对应的 active/awaiting 状态
|
||||
- 检查 doc_task_instance 状态不为 `skipped_disabled`
|
||||
- 检查当前阶段包含该任务
|
||||
- 检查用户为对应职责人
|
||||
3. 在所有入口(API、SSE、异步任务、搜索、导出、RAG、Agent tool)使用此决策器
|
||||
4. 补充测试: `TestDocumentAccessDecider_AllEntries`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-06: 激活 token 安全问题
|
||||
|
||||
**文件**: `internal/projectinstance/service.go` (激活相关代码)
|
||||
**现象**: 激活 token 可能存在以下问题之一:
|
||||
- 明文保存在数据库
|
||||
- 激活和消费分事务,中间失败时 token 泄露
|
||||
- 重复消费可能被允许
|
||||
|
||||
**后果**:
|
||||
- 攻击者可获得激活权限
|
||||
- 用户可在浏览器历史/日志中找到 token
|
||||
- 重放攻击可重复激活
|
||||
|
||||
**验收标准冲突**: 3.1 "激活时冻结…运行中不可静默修改" 的先决条件是原子激活
|
||||
|
||||
**整改方案**:
|
||||
1. 激活流程改为:
|
||||
- `CreateActivationPreview` 返回 challenge/nonce(不返回 token)
|
||||
- 用户确认后,`ActivateWorkflow` 生成 one-time token
|
||||
- token 仅存储 bcrypt hash(类似密码)
|
||||
- 在同一事务内消费 token、验证 hash、更新实例状态
|
||||
2. token 过期时间设为 5 分钟
|
||||
3. 补充测试: `TestActivationTokenSecurity`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-07: 项目完成后项目生命周期转换逻辑缺失
|
||||
|
||||
**文件**: `internal/projectinstance/service.go`, `internal/projectworkflow/service.go`
|
||||
**现象**: 完成一个工作流后,项目无法自动进入可选择下一工作流的状态。
|
||||
|
||||
**代码现场**:
|
||||
```go
|
||||
// projectinstance/service.go:119-135
|
||||
// GetSettings 只允许 lifecycle == LifecyclePlanning 时编辑
|
||||
if lifecycle != LifecyclePlanning {
|
||||
return nil, ErrPlanFrozen // completed 实例的项目仍不能选择下一流程
|
||||
}
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 用户必须手工改数据库才能运行下一工作流
|
||||
- 用户体验与业务规则相悖
|
||||
|
||||
**验收标准冲突**: 3.1 "完成或受控终止后创建下一工作流实例"
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 `CompleteWorkflowInstance` 应用服务:
|
||||
- 检查实例处于最后阶段且阶段就绪
|
||||
- 在事务内:标记实例为 `completed`,项目改为 `planning`,清空 live 指针
|
||||
2. `AdvanceStage` 检查当前阶段是否为最后阶段,是则调用此服务
|
||||
3. 补充测试: `TestProjectLifecycleAfterCompletion`
|
||||
|
||||
---
|
||||
|
||||
### 2.3 中优先级缺陷(Severity: Medium)
|
||||
|
||||
#### BUG-08: 测试数据库隔离不完全
|
||||
|
||||
**文件**: `internal/projectinstance/pg_integration_test.go:19-49`,`internal/server/workflow_governance_pg_test.go:26-61`
|
||||
**现象**: 集成测试未设置 `TEST_DATABASE_URL` 时默认连接本地开发库,导致测试数据污染。
|
||||
|
||||
**现场数据**:
|
||||
```
|
||||
开发库 workflow_definitions = 92 个
|
||||
其中 pg_* / test_* 命名 = 88 个(测试污染)
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 业务数据与测试数据混淆
|
||||
- 本地开发环境无法清洁复现
|
||||
- CI/CD 若复用开发库会产生不可预测的行为
|
||||
|
||||
**验收标准冲突**: 7.5 "测试结束后业务数据库中不残留 `pg_*`、`test_*` 定义"
|
||||
|
||||
**整改方案**:
|
||||
1. 所有 `*_test.go` 中强制要求 `TEST_DATABASE_URL`;未设置时 skip 或 fatal
|
||||
2. 测试前创建隔离 schema 或独立库,测试后清理
|
||||
3. CI 配置中显式设置 `TEST_DATABASE_URL` 指向临时数据库
|
||||
4. 补充 CI 脚本检查:测试结束后确认开发库中无 `pg_*`、`test_*` 定义
|
||||
|
||||
---
|
||||
|
||||
#### BUG-09: 版本冲突时前端自动重试
|
||||
|
||||
**文件**: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:38-76,173-236`
|
||||
**现象**: 当两个浏览器同时切换工作流时,第一个返回版本冲突,但前端自动取新版本再次提交,无需用户确认。
|
||||
|
||||
**代码现场**:
|
||||
```typescript
|
||||
// ProjectWorkflowSwitcher.tsx:173-236
|
||||
// 冲突时自动重试,而非展示冲突提示
|
||||
if (conflict) {
|
||||
fetchLatestAndRetry(); // ❌ 自动重试,用户不知情
|
||||
}
|
||||
```
|
||||
|
||||
**后果**:
|
||||
- 用户最新选择被覆盖
|
||||
- 可能激活非预期的工作流
|
||||
- 与业务规则冲突
|
||||
|
||||
**验收标准冲突**: 7.2 "两个浏览器同时配置或推进时…另一个收到版本冲突并重新确认"
|
||||
|
||||
**整改方案**:
|
||||
1. 冲突时展示弹窗:"您的选择与其他编辑冲突,请重新确认"
|
||||
2. 显示当前版本、冲突版本和新版本内容
|
||||
3. 用户确认后重新提交,而非自动重试
|
||||
4. 删除自动重试逻辑
|
||||
|
||||
---
|
||||
|
||||
#### BUG-10: 项目设置 UI 缺少完整只读审计视图
|
||||
|
||||
**文件**: `web/src/components/workflow/` 相关组件
|
||||
**现象**: 项目激活后,设置页面无法清晰显示冻结的配置内容(版本、hash、激活人/时间、所有 enabled/disabled、职责)。
|
||||
|
||||
**后果**:
|
||||
- 创建者不知道实际冻结的是什么
|
||||
- 无法自助诊断权限问题
|
||||
- 审计信息不可见
|
||||
|
||||
**验收标准冲突**: 7.2 "live 配置缺少完整只读审计视图"
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 "工作流运行详情" 只读面板,显示:
|
||||
- 工作流版本、发布时间、hash
|
||||
- 激活人员、激活时间
|
||||
- 所有启用文档及三权职责
|
||||
- 所有禁用文档及禁用原因
|
||||
- 当前阶段进度
|
||||
2. 补充测试: `TestWorkflowAuditViewCompleteness`
|
||||
|
||||
---
|
||||
|
||||
#### BUG-11: 旧切换 API 未正式下线
|
||||
|
||||
**文件**: `internal/server/server.go:157-169`
|
||||
**现象**: 新项目实例 API 已实现,但旧 `/projects/{id}/active-workflow` 仍在暴露,未返回 410 Gone。
|
||||
|
||||
**代码现场**:
|
||||
```go
|
||||
// server.go:157-169
|
||||
mux.HandleFunc("POST /projects/{id}/active-workflow", s.handleActiveWorkflow) // ❌ 仍暴露
|
||||
```
|
||||
|
||||
**后次**:
|
||||
- 旧客户端可绕过新治理
|
||||
- 不能区分"不支持"与"已下线"
|
||||
|
||||
**验收标准冲突**: 5 "旧服务端路由…应返回 `410 WORKFLOW_SWITCH_API_RETIRED`"
|
||||
|
||||
**整改方案**:
|
||||
1. 将 `/projects/{id}/active-workflow` 路由改为返回 410 Gone 和迁移指引
|
||||
2. 添加 deprecation 日志
|
||||
3. 补充测试: `TestLegacyAPIReturns410`
|
||||
|
||||
---
|
||||
|
||||
### 2.4 低优先级缺陷(Severity: Low)
|
||||
|
||||
#### BUG-12: 前端名称不一致
|
||||
|
||||
**文件**: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:16-23`
|
||||
**现象**: 前端硬编码的三个工作流名称与后端正式名称不一致。
|
||||
|
||||
**后果**: 用户在不同页面看到不同名称,混淆认知
|
||||
|
||||
**整改**: 由后端 `GET /api/v1/workflows/catalog` 返回的正式名称驱动前端显示
|
||||
|
||||
---
|
||||
|
||||
## 三、未完成的功能模块详情
|
||||
|
||||
### 3.1 项目上下文快照服务(ProjectContextSnapshot)
|
||||
|
||||
**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:82-105`
|
||||
**当前状态**: 规划完整,实现 0%
|
||||
**关键要求**:
|
||||
|
||||
1. **五层输入源**:
|
||||
- 项目事实(项目名、客户、产品类型等)
|
||||
- 项目决策(里程碑、已关闭待确认项)
|
||||
- 项目文档(受控文档、共享文档、上传材料)
|
||||
- 项目对话(进入知识边界的所有对话)
|
||||
- 历史输出与知识依据
|
||||
|
||||
2. **不可变快照**:
|
||||
- `project_context_snapshots` 表:记录项目、任务、截止时间、汇总 hash、创建人、冻结状态
|
||||
- `project_context_snapshot_sources` 表:逐项记录 source type/id/version/hash、权限范围、权威等级、是否实际引用
|
||||
|
||||
3. **冲突优先级**:
|
||||
- 创建者确认事实/决策 > 已批准文档 > 上传材料 > 里程碑记录 > 普通对话 > 智能体总结
|
||||
|
||||
4. **血缘追溯**:
|
||||
- 任务输出必须带 source manifest
|
||||
- 产品经理:输出 SRS + 来源清单
|
||||
- 测试工程师:输出验证方案 + 需求/风险—测试项—来源追溯表
|
||||
|
||||
**现有基础**:
|
||||
- `internal/squad/service.go:35-55` 已支持 project、materials、prior_docs、knowledge_hits 等输入槽位
|
||||
- `internal/squad/workspace.go:262-408` 已有 context 索引建立能力
|
||||
- `internal/bizdev/service.go:250-294` 已有部分项目事实输入逻辑
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 `internal/projectcontext/service.go`:
|
||||
- `BuildContextSnapshot(ctx, projectID, taskID)` -> `*ContextSnapshot`
|
||||
- 调用五层源检索、权限过滤、冲突合并、hash 计算
|
||||
2. 新增数据库表与迁移
|
||||
3. 产品经理与测试工程师都改用此服务
|
||||
4. 补充集成测试
|
||||
|
||||
**验收标准**: 7.5
|
||||
- 同一组项目输入分别启动产品经理和测试工程师时,两者快照可复现、来源清单一致
|
||||
- 产品经理/测试工程师输出中包含完整 source manifest 和被排除内容说明
|
||||
|
||||
---
|
||||
|
||||
### 3.2 受控终止工作流(WorkflowTermination)
|
||||
|
||||
**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:109-131` (状态机)
|
||||
**当前状态**: 状态表存在,API 和逻辑 0%
|
||||
**关键要求**:
|
||||
|
||||
1. **状态转换**:
|
||||
```
|
||||
active → termination_requested → terminated
|
||||
```
|
||||
|
||||
2. **操作约束**:
|
||||
- 仅创建者可申请
|
||||
- 需二次确认
|
||||
- 需填写原因
|
||||
- 处理或取消在途任务
|
||||
- 生成审计
|
||||
|
||||
3. **API**:
|
||||
- `POST /api/v1/workflow-instances/{id}/termination-preview` - 预览影响
|
||||
- `POST /api/v1/workflow-instances/{id}/terminate` - 执行终止
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 `internal/projectinstance/terminate.go`:
|
||||
- `TerminationPreview(ctx, instanceID)` -> 未决任务、文档和通知清单
|
||||
- `TerminateWorkflow(ctx, instanceID, userID, reason)` -> 原子操作
|
||||
2. 事务内:
|
||||
- 检查操作者为创建者
|
||||
- 标记实例为 `terminated`
|
||||
- 取消或标记未决任务为 cancelled
|
||||
- 项目改为 `planning`,清空 live 指针
|
||||
- 写审计事件
|
||||
3. 补充 API 路由和端到端测试
|
||||
|
||||
**验收标准**: 7.3
|
||||
- 创建者可以选择"受控终止"而非永久锁死
|
||||
- terminated 状态的项目可创建下一实例
|
||||
- 审计记录包含终止原因
|
||||
|
||||
---
|
||||
|
||||
### 3.3 真实 E2E 测试(PostgreSQL + PI Agent)
|
||||
|
||||
**规划文档**: `.doc/2026-09-12-three-workflows-strict-governance-remediation.md:417-459` (验收标准)
|
||||
**当前状态**: 单元测试 PASS,E2E 0%
|
||||
**要求**:
|
||||
|
||||
1. 使用真实 PostgreSQL(不是内存 mock)
|
||||
2. 使用真实 PI Agent 容器
|
||||
3. 完整链路:
|
||||
- 创建项目 → 选择工作流 → 激活 → 推进各阶段 → 完成 → 配置下一工作流
|
||||
4. 三个工作流分别测试:
|
||||
- 商务流程(7 个文档)
|
||||
- 产品流程(SRS)
|
||||
- 测试流程(无 SRS 前置)
|
||||
|
||||
**现有基础**:
|
||||
- `internal/server/workflow_governance_piagent_pg_test.go` 已有 PG 集成框架
|
||||
- PI Agent 容器已在 `docker-compose.yml` 中定义
|
||||
|
||||
**整改方案**:
|
||||
1. 新增 `internal/server/e2e_workflow_test.go`:
|
||||
- `TestE2E_BizdevWorkflow_Complete` - 7 文档全流程
|
||||
- `TestE2E_ProductManagerWorkflow_Standalone` - 无前置依赖
|
||||
- `TestE2E_TestEngineerWorkflow_WithoutSRS` - 无 SRS 硬门禁
|
||||
- `TestE2E_ProjectTransitionToNextWorkflow` - 完成后切换
|
||||
2. 设置 `TEST_DATABASE_URL` 指向隔离库
|
||||
3. 启动 PI Agent 容器(或 mock 其接口)
|
||||
4. 逐步执行,记录结果
|
||||
|
||||
**验收标准**: 7.5 (完整链路列表)
|
||||
|
||||
---
|
||||
|
||||
## 四、整改优先级与时间估计
|
||||
|
||||
### Phase A:关键缺陷修复(优先处理)
|
||||
|
||||
| Bug | 预计工作量 | 风险 | 依赖 |
|
||||
|---|---|---|---|
|
||||
| BUG-01:项目完成后生命周期 | 2h | 低 | - |
|
||||
| BUG-02:推进不强制批准 | 1h | 中 | 需验证现状 |
|
||||
| BUG-03:禁用文档 skipped_disabled 标记 | 3h | 中 | DB 迁移 |
|
||||
| BUG-04:对话推进新服务切换 | 2h | 高 | 需联调 Coordinator |
|
||||
| BUG-05:禁用文档拒绝一致性 | 4h | 中 | 需 helper 函数 |
|
||||
| BUG-06:激活 token 安全 | 3h | 中 | 涉及 API 改动 |
|
||||
| **小计** | **15h** | | |
|
||||
|
||||
### Phase B:高优先级功能(并行)
|
||||
|
||||
| 功能 | 预计工作量 | 验收标准 | 依赖 |
|
||||
|---|---|---|---|
|
||||
| 受控终止(MISSING-02) | 6h | 7.3 | BUG-01 |
|
||||
| 真实 E2E 测试(MISSING-04) | 8h | 7.5 | Phase A + 容器 |
|
||||
| 项目上下文快照(MISSING-01) | 12h | 7.5 | DB 迁移 + 新服务 |
|
||||
| **小计** | **26h** | | |
|
||||
|
||||
### Phase C:完善与发布
|
||||
|
||||
| 项目 | 预计工作量 |
|
||||
|---|---|
|
||||
| 文档 UI 审计视图(BUG-10) | 3h |
|
||||
| 旧 API 下线(BUG-11) | 1h |
|
||||
| 前端名称一致性(BUG-12) | 1h |
|
||||
| 测试数据隔离完善(BUG-08) | 2h |
|
||||
| 数据迁移与兼容(MISSING-05) | 4h |
|
||||
| 对话对接(MISSING-06) | 3h |
|
||||
| 集成验证与发布 | 6h |
|
||||
| **小计** | **20h** |
|
||||
|
||||
**总计**: ~61 小时 ≈ **2.5 天(单人全职)**或 **5 天(双人)**
|
||||
|
||||
---
|
||||
|
||||
## 五、整改执行计划
|
||||
|
||||
### 5.1 Day 1: 关键缺陷修复
|
||||
|
||||
**Morning (4h)**:
|
||||
1. BUG-01 修复:AdvanceStage → 同事务更新项目生命周期
|
||||
- 修改 `stage_store.go` 和 `service.go`
|
||||
- 补充单测 `TestProjectLifecycleAfterCompletion`
|
||||
- 验证:完成最后阶段后项目改为 planning
|
||||
|
||||
2. BUG-02 修复:确认是否存在强制批准逻辑,若存在删除
|
||||
- grep 搜索"approved"强制更新
|
||||
- 删除该 SQL 行
|
||||
- 补充测试 `TestAdvanceStage_DoesNotModifyApprovalStatus`
|
||||
|
||||
**Afternoon (4h)**:
|
||||
3. BUG-04 修复:对话推进切换到新服务
|
||||
- 修改 `coordinator/engine.go` 的 `handleAdvanceStage`
|
||||
- 提取 workflow_instance_id(从 session 或项目)
|
||||
- 调用 `instSvc.AdvanceStage` 替代 `bizdevSvc.ExecuteStage`
|
||||
- 补充对话测试
|
||||
|
||||
4. BUG-06 开始:激活 token 安全重构
|
||||
- 设计 one-time token 与 hash 方案
|
||||
- 修改激活预览与激活 API
|
||||
|
||||
### 5.2 Day 2: 继续缺陷修复 + 开始新功能
|
||||
|
||||
**Morning (4h)**:
|
||||
5. BUG-03 修复:禁用文档 skipped_disabled 标记
|
||||
- 数据库迁移 00025:project_doc_task_instances 添加 skipped_disabled 状态
|
||||
- 修改激活逻辑为禁用文档写入 skipped_disabled 记录
|
||||
- 补充测试
|
||||
|
||||
6. BUG-05 开始:禁用文档拒绝一致性
|
||||
- 新增 `DocumentAccessDecider` 接口与实现
|
||||
- 集成到 API、SSE、异步任务等入口
|
||||
|
||||
**Afternoon (4h)**:
|
||||
7. 受控终止开发(MISSING-02)
|
||||
- 新增 `terminate.go` 服务
|
||||
- 实现终止预览和执行 API
|
||||
- 补充测试
|
||||
|
||||
### 5.3 Day 3: 新功能开发与集成测试
|
||||
|
||||
**Full Day (8h)**:
|
||||
8. 项目上下文快照初版(MISSING-01)
|
||||
- 新增 `projectcontext/service.go`
|
||||
- 实现快照构建与来源清单
|
||||
- 产品/测试工程师改用新服务
|
||||
|
||||
9. 真实 E2E 测试启动(MISSING-04)
|
||||
- 编写 E2E 测试框架
|
||||
- 三个工作流链路验证
|
||||
- 文档与验证报告
|
||||
|
||||
---
|
||||
|
||||
## 六、质量保证与验收检查表
|
||||
|
||||
### 6.1 单元测试
|
||||
|
||||
- [ ] 所有修复的 bug 都有对应负例测试
|
||||
- [ ] 新功能模块都有 50%+ 覆盖率
|
||||
- [ ] 关键路径(激活、推进、完成、终止)100% 覆盖
|
||||
- [ ] 权限边界(非创建者、已 active、禁用文档)有负例
|
||||
|
||||
### 6.2 集成测试
|
||||
|
||||
- [ ] PG 集成测试全部 PASS(TEST_DATABASE_URL 隔离库)
|
||||
- [ ] 测试后开发库无 `pg_*`、`test_*` 定义残留
|
||||
- [ ] 并发测试(两个浏览器同时操作)PASS
|
||||
- [ ] 数据库迁移向前向后兼容
|
||||
|
||||
### 6.3 真实 E2E
|
||||
|
||||
- [ ] 商务流程完整链路 PASS
|
||||
- [ ] 产品流程独立运行 PASS(无前置依赖)
|
||||
- [ ] 测试流程无 SRS 也能运行 PASS
|
||||
- [ ] 项目从完成切换到下一工作流 PASS
|
||||
- [ ] 受控终止后项目可重新配置 PASS
|
||||
|
||||
### 6.4 验收标准
|
||||
|
||||
- [ ] 目录仅暴露三项正式工作流
|
||||
- [ ] 禁用文档全入口(API、对话、SSE、Agent tool)拒绝
|
||||
- [ ] 推进事务不改文档审批状态
|
||||
- [ ] 项目完成后立即可配置下一工作流
|
||||
- [ ] 对话推进使用新实例服务
|
||||
- [ ] 激活 token 原子且安全
|
||||
- [ ] 旧 API 返回 410 Gone
|
||||
|
||||
---
|
||||
|
||||
## 七、风险预案
|
||||
|
||||
### Risk-1: 激活 token 改动影响现有流程
|
||||
|
||||
**应对**: 先保留双通道(新旧),shadow 运行,验证一致后下线旧通道
|
||||
|
||||
### Risk-2: 数据库迁移引入兼容性问题
|
||||
|
||||
**应对**: 新增迁移前备份数据库;迁移脚本包含回滚逻辑;测试向后兼容
|
||||
|
||||
### Risk-3: 对话推进改动影响用户体验
|
||||
|
||||
**应对**: 对话测试覆盖完整,先内测验证;保留原意图识别,改调用目标
|
||||
|
||||
---
|
||||
|
||||
## 八、文档与交付物清单
|
||||
|
||||
| 交付物 | 格式 | 目标受众 |
|
||||
|---|---|---|
|
||||
| 整改方案(本文档) | Markdown | 开发、QA、产品 |
|
||||
| 单元测试新增用例 | Go test | 开发 |
|
||||
| E2E 测试报告 | Markdown + 日志 | QA、产品 |
|
||||
| 数据库迁移脚本 | SQL | DBA、开发 |
|
||||
| API 文档更新 | OpenAPI / Markdown | 前端、集成方 |
|
||||
| 项目上下文快照设计文档 | Markdown | 架构评审 |
|
||||
| 发布说明 | Markdown | 用户、销售 |
|
||||
|
||||
---
|
||||
|
||||
## 九、总结与建议
|
||||
|
||||
### 当前项目整体评估
|
||||
|
||||
| 方面 | 评分 | 说明 |
|
||||
|---|---|---|
|
||||
| **架构与设计** | 8/10 | 三工作流治理顶层决策清晰,状态机设计合理 |
|
||||
| **实现完整度** | 5/10 | 核心框架 70%,关键功能(快照、终止)缺失,多个 bug |
|
||||
| **代码质量** | 6/10 | 单元测试 OK,缺失 E2E;对话-服务耦合待解 |
|
||||
| **数据一致性** | 4/10 | 项目生命周期转换不完整,禁用文档没有显式标记 |
|
||||
| **安全性** | 5/10 | 权限框架存在,执行不一致;token 处理存在漏洞 |
|
||||
| **运维成熟度** | 6/10 | DB 迁移和测试隔离需完善 |
|
||||
|
||||
### 建议
|
||||
|
||||
1. **优先完成 Phase A 缺陷修复**(2 天)以稳定当前功能
|
||||
2. **并行开发 Phase B 新功能**(3 天),特别是 E2E 测试以验证整体逻辑
|
||||
3. **建立自动化验收流程**:CI 应包括所有验收标准的检查
|
||||
4. **后续维护建议**:
|
||||
- 禁用项目选择非正式工作流的自动检查(CI 中)
|
||||
- 每次激活/推进/完成后都输出审计链(便于故障排查)
|
||||
- 项目完成前端页面加"确认完成工作流"的双确认卡
|
||||
- 定期数据库快照与清理脚本(防止垃圾数据)
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0
|
||||
**最后更新**: 2026-09-12 14:45 UTC
|
||||
**下一步**: 待产品&技术评审确认,进入实施阶段
|
||||
+706
@@ -0,0 +1,706 @@
|
||||
# Agent System 权限、设置与三类工作流完整实施方案
|
||||
|
||||
## 1. 执行结论
|
||||
|
||||
当前系统已经完成了从原型向受控工作流平台演进所需的多数“结构件”:数据库账户与会话、系统角色/权限表、项目成员、工作流定义及版本、模板版本、项目工作流实例、阶段实例、文档任务实例、三权职责、激活确认、阶段推进请求、通知 Outbox、任务运行持久化和文档血缘均已存在。现有 Go 短测、前端测试和生产构建也能通过。因此,本轮不应推倒重做,而应完成最后一段也是最关键的一段:**统一授权权威、把设置真正落到服务端、让已发布工作流版本成为运行时唯一事实源,并将商务对接、智能产品经理、智能测试经理发布为可配置、可冻结、可执行、可审计的正式工作流。**[^1][^2][^3]
|
||||
|
||||
但截至本次审计,系统还不能宣称“权限和设置已做全”,三个工作流也还不能按当前治理设计直接投入多人生产使用。核心原因如下:
|
||||
|
||||
1. **权限表存在,但策略执行不完整。** 部分项目查询、工作流历史和血缘查询缺少对象级授权;创建项目只校验登录,不校验 `project:create`;工作流管理 API 仍统一要求超级管理员,未使用已入库的细粒度权限;系统权限计算还忽略绑定作用域、角色状态和 `valid_from`。[^4][^5][^6]
|
||||
2. **阶段权限存在高风险放行路径。** 解析 live 实例发生数据库错误时会回退为“不限制”,多个列表、聊天、RAG/上下文过滤辅助函数也在错误时放行;拥有当前阶段任一文档职责的用户会获得该阶段全部文档任务权限,任务执行门禁还允许其运行任意 `task_key`。[^7][^8]
|
||||
3. **设置界面与服务端权威尚未闭环。** 浏览器仍把 Bearer token 和会话对象放入 `localStorage`,登出只删除本地状态;个人资料保存、个人偏好和部分权限画像仍是前端本地数据,已有活动会话 API 未在用户设置中形成闭环。[^9][^10]
|
||||
4. **三个工作流只是“登记过”,不是“完整接入”。** `main`、`product_manager`、`test_manager` 已作为发布种子存在,但都是单阶段包装;运行目录会把任意已发布版本压扁为第一阶段的第一个任务。商务对接真实的 V0.1/V0.5/V1.0 阶段仍硬编码在 BizDev 执行器中;产品经理和测试经理的五步 Agent 流程存在,但没有由版本化定义驱动。[^11][^12][^13]
|
||||
5. **项目实例与文档治理还未成为同一条链。** 规划校验没有检查必需阶段/必需任务是否被整个遗漏,也没有校验三权人员是否为有效项目成员;实例持久化把所有阶段 `position` 写成 0;执行器又会在请求未传三权时回退到固定用户 2/3,并把文档阶段固定为 `V0.5_feasibility`,没有消费冻结实例中的职责和活动阶段。[^14][^15]
|
||||
|
||||
因此建议把工作拆为三道发布闸门:
|
||||
|
||||
- **闸门 A:授权止血。** 先关闭跨项目读取、错误放行、任意任务键、身份/会话本地权威等 P0;完成全部 API/数据通路的策略矩阵。
|
||||
- **闸门 B:配置与运行时合流。** 扩展工作流 schema,建立 `executor_key` 注册表和全阶段解释器,让项目实例、DocGov、任务运行、对话/RAG、文档血缘都从同一冻结快照取值。
|
||||
- **闸门 C:发布三个正式版本。** 以新版本而不是覆盖旧数据的方式发布三个工作流,完成迁移、真实 PostgreSQL、跨用户负例和真实 PI Agent E2E 后再开放生产选择。
|
||||
|
||||
本方案遵循当前系统已经确定的治理原则:生产身份只来自服务端会话;系统角色、项目角色和单文档三权职责分离;已发布版本不可原地修改;项目激活时冻结完整快照;同一项目只允许一个 live 工作流;当前流程完成或受控终止后才能选择下一个;门禁满足只发提醒,阶段推进必须由项目创建人明确确认。[^1]
|
||||
|
||||
## 2. 本次研究范围与验证边界
|
||||
|
||||
### 2.1 已审阅范围
|
||||
|
||||
| 层 | 已审阅内容 |
|
||||
|---|---|
|
||||
| 数据库 | Goose `00014`–`00020`:成员、IAM、工作流/模板、项目实例、通知、任务运行 |
|
||||
| 后端 | `internal/auth`、`authz`、`workflowdef`、`projectinstance`、`projectworkflow`、`bizdev`、`squad`、`server` |
|
||||
| 前端 | 登录会话、RBAC 类型、用户设置、系统设置、项目设置、工作流切换/展示 |
|
||||
| 业务执行 | 商务对接真实阶段;产品经理/测试经理 Agent 角色、步骤、模板、质量门禁、前置依赖和血缘 |
|
||||
| 既有文档 | 2026-09-11 治理总方案、Phase 1/2 实施计划、当前 PG/CI/Soak/E2E 报告 |
|
||||
|
||||
### 2.2 本轮已执行验证
|
||||
|
||||
```text
|
||||
go test -short -timeout 8m \
|
||||
./internal/auth/... ./internal/authz/... ./internal/workflowdef/... \
|
||||
./internal/projectinstance/... ./internal/projectworkflow/... ./internal/server/...
|
||||
结果:全部通过
|
||||
|
||||
cd web && npm test
|
||||
结果:170 项 Node tests + 22 项 Vitest tests 全部通过
|
||||
|
||||
cd web && npm run build
|
||||
结果:TypeScript + Vite 构建通过;存在主 bundle 过大的非阻断警告
|
||||
```
|
||||
|
||||
这些结果证明当前分支能编译且现有回归未破坏,不证明跨租户授权、真实 PostgreSQL 事务、重启恢复和真实 PI Agent 长链路已满足本方案的发布门禁。当前测试报告中 PI Agent 全生命周期仍记录了 `/v1/run` 超时,且报告结尾又写“仍在运行”,应先修正文档状态,再以一次新的、带 commit SHA 和环境指纹的运行作为验收证据。[^16]
|
||||
|
||||
### 2.3 外部设计基线
|
||||
|
||||
授权采用“默认拒绝、每次请求验证、对象标识不可猜测越权、失败安全退出、记录审计”的基线;动态项目、阶段和文档条件用 RBAC + ReBAC + ABAC 组合,而不是只靠全局角色。OWASP 明确建议默认拒绝并对每次请求执行权限判断;NIST RBAC 模型把用户、角色、权限、操作和对象建模为独立关系,并支持职责分离约束。[^17][^18]
|
||||
|
||||
浏览器会话不再把认证 token 放在 `localStorage`。OWASP 指出 Web Storage 可被同源 JavaScript 读取,建议会话使用 `HttpOnly; Secure; SameSite` Cookie;Cookie 模式下同时补齐 CSRF 防护。[^19]
|
||||
|
||||
## 3. 当前系统能力盘点
|
||||
|
||||
### 3.1 可以直接保留并扩展的能力
|
||||
|
||||
| 能力 | 当前状态 | 本方案处理 |
|
||||
|---|---|---|
|
||||
| 统一 API 认证中间件 | 已存在 | 保留;切换到安全 Cookie/CSRF,并在授权失败时统一错误模型 |
|
||||
| 数据库账户、密码哈希、会话哈希 | 已存在 | 保留;增加密码/MFA/重置策略、会话前端闭环和安全事件 |
|
||||
| 系统角色/权限/绑定 | 已存在 | 纠正多角色、作用域、有效期、状态和管理审计语义 |
|
||||
| `project_members` | 已存在 | 增加 FK、项目业务角色多绑定、成员状态和职责候选资格 |
|
||||
| 工作流草稿/发布/退役 | 后端基础存在 | 增加复制草稿、完整 schema、细粒度授权、发布影响预览和 UI |
|
||||
| 模板 CAS/版本/扫描状态 | 基础存在 | 增加扫描 worker、隔离区、预览、发布/退役和引用影响分析 |
|
||||
| 项目规划/预览/确认/冻结 | 基础存在 | 修复完整性校验、原子 token、阶段顺序、受控变更和下一个工作流 |
|
||||
| 文档三权状态机 | 已存在 | 由实例职责驱动;加职责资格、再认证/签署策略和阶段门禁映射 |
|
||||
| Outbox/通知/阶段推进请求 | 已存在 | 完成用户偏好、渠道、升级、去重和创建人确认体验 |
|
||||
| 任务运行持久化/lease | 已存在 | 把任务与实例/阶段/任务定义绑定;细分 read/cancel/resume 权限 |
|
||||
| 文档血缘/stale | 已存在 | stale 成为阶段退出阻断条件,提供影响分析和重新基线闭环 |
|
||||
|
||||
### 3.2 当前成熟度判定
|
||||
|
||||
| 领域 | 代码骨架 | 服务端权威 | 前端闭环 | 生产验收 | 判定 |
|
||||
|---|---:|---:|---:|---:|---|
|
||||
| 认证与会话 | 高 | 中 | 低 | 中 | 需整改 |
|
||||
| 系统 RBAC | 中 | 低 | 中 | 低 | 发布阻断 |
|
||||
| 项目 ReBAC | 中 | 中 | 中 | 低 | 发布阻断 |
|
||||
| 阶段/文档 ABAC | 中 | 低 | 中 | 低 | 发布阻断 |
|
||||
| 用户设置 | 中 | 低 | 中 | 低 | 未做全 |
|
||||
| 系统设置 | 中 | 中 | 中 | 低 | 未做全 |
|
||||
| 项目设置 | 中高 | 中 | 中 | 低 | 关键断点 |
|
||||
| 工作流设计/版本 | 中高 | 中 | 低 | 低 | 关键断点 |
|
||||
| 三工作流执行器 | 高 | 低 | 中 | 低 | 尚未正式接入 |
|
||||
| 审计与通知 | 中 | 中 | 低 | 低 | 尚未闭环 |
|
||||
|
||||
## 4. 必须优先修复的问题清单
|
||||
|
||||
### 4.1 P0:在接入三个工作流前必须关闭
|
||||
|
||||
| ID | 问题 | 影响 | 整改与验收 |
|
||||
|---|---|---|---|
|
||||
| AUTH-001 | 工作流运行历史、文档血缘 handler 未调用项目对象授权 | 登录用户可能读取其他项目元数据/血缘 | 所有项目子路由统一经过资源加载 + `Authorize`;跨项目返回 404 或统一 403;加双用户 PG 负例 |
|
||||
| AUTH-002 | 阶段访问解析或过滤出错时放行 | DB/策略故障可扩大文档、聊天、RAG、Agent 上下文可见范围 | 生产环境 fail closed;只对明确标记的 legacy 项目执行迁移期策略,且有截止版本和指标 |
|
||||
| AUTH-003 | 工作流路由接受客户端覆盖 `task_key`;阶段成员可运行当前阶段任意任务 | 绕过工作流定义和文档职责 | 服务端只从 `workflow_instance_id + active_stage + task_instance_id` 推导 executor;拒绝不在快照中的任务 |
|
||||
| AUTH-004 | 项目规划可以整个遗漏必需阶段/任务 | 可激活空壳或删减受控交付物的计划 | 对定义中每个 non-optional stage 和 required/blocking task 做反向完整性校验 |
|
||||
| AUTH-005 | 三权用户未校验有效账户、项目成员和候选角色 | 可把无权或已停用用户写入审批链 | 激活前逐人校验 membership/status/eligibility/职责分离;激活后人员失效触发阻断事件 |
|
||||
| AUTH-006 | 项目列表 SQL 把 `creator_id=1`/NULL 项目视为公开,旧切换逻辑有固定用户/项目 ID 豁免 | 演示兼容规则泄漏到真实授权 | 删除 ID 特判;显式 `project_visibility`/legacy migration,不以 creator ID 表达公开 |
|
||||
| AUTH-007 | 项目创建接口未检查 `project:create` | 任意活动账户可立项 | handler/service 双层校验 `projects.create`,前端按钮仅作体验控制 |
|
||||
| AUTH-008 | 项目成员可读取/取消其他成员任务运行,未区分动作 | 破坏他人运行和审计归属 | `task_runs.view_own/view_project/cancel_own/cancel_any/resume` 分权;取消他人任务须负责人或创建人 |
|
||||
| AUTH-009 | 本地 token、仅本地 logout、失效 `/me` 后仍保留登录态 | XSS/撤销后前端假登录 | 改安全 Cookie;服务端 logout;`/me` 401 立即清空主体和缓存;权限加载失败敏感动作 fail closed |
|
||||
| WF-001 | DBCatalog 将完整版本压扁为第一阶段第一任务 | 发布多阶段定义也不会按定义运行 | 移除 flatten 执行路径,新增实例编排器逐阶段/任务读取冻结快照 |
|
||||
| WF-002 | DocGov 三权和阶段来自请求/固定默认值,不来自实例 | 配置的责任人和活动阶段不生效 | 由 `doc_task_instance_id` 解析 author/reviewer/approver/stage;禁止生产请求传入身份覆盖 |
|
||||
|
||||
### 4.2 P1:首次正式发布必须完成
|
||||
|
||||
| ID | 问题 | 整改 |
|
||||
|---|---|---|
|
||||
| IAM-101 | `ListCapabilities` 忽略 `scope_type/scope_id`、角色状态和 `valid_from` | 引入带资源上下文的 PDP;系统能力只取 `scope_type=system, scope_id=0`,校验角色/账户/有效期 |
|
||||
| IAM-102 | `users.role_id` 与 `user_role_bindings` 双权威,更新角色会删除其他绑定 | `user_role_bindings` 为唯一权威;`users.role_id` 只作迁移兼容后移除;支持多角色 |
|
||||
| IAM-103 | `assigned_by` 被写成目标用户本身,角色+状态更新非原子且忽略角色更新错误 | 从 principal 传 actor;单事务变更;写不可变审计事件;失败整体回滚 |
|
||||
| IAM-104 | `role-admin` 字符串直接赋予管理员身份,`perm:manage` 又作为所有权限通配 | 显式 `system.superadmin`;普通 `permissions.manage` 不再通配业务数据;至少两名受控管理员防死锁 |
|
||||
| IAM-105 | 前端权限键只有最早 7 项,后端迁移已有更多权限 | 后端暴露 permission catalog;前端由 API 渲染,不维护硬编码联合类型作为事实源 |
|
||||
| SET-101 | 用户资料保存只改 React state;偏好仅组件本地;活动会话 UI 缺失 | 增加 `/me/profile`、`/me/preferences`、`/me/notification-preferences` 和会话管理 UI |
|
||||
| SET-102 | 管理中心工作流页只能列出/校验/发布,不能完整建模 | 增加创建、复制草稿、阶段排序、任务/职责/参与策略、模板选择、diff、发布、退役 |
|
||||
| SET-103 | Office 模板进入 `pending` 后缺少扫描完成链 | 隔离上传 + scanner worker + 状态回调/轮询;只有 `ready` 可发布 |
|
||||
| SET-104 | UI 宣称符合 21 CFR Part 11,但未实现电子签名控制 | 删除不实文案;如需合规,另立 e-sign scope(再认证、签署含义、签名绑定、审计、防篡改) |
|
||||
| WF-101 | 所有阶段实例 `position=0` | 从定义快照持久化真实 position;增加唯一性与连续性校验 |
|
||||
| WF-102 | 激活 token 明文保存且消费、激活非同一事务 | 仅存 token hash;`SELECT FOR UPDATE` 后在同一事务验证、消费和激活 |
|
||||
| WF-103 | 推进会把全部启用任务强制标成 approved | 推进只允许已满足门禁的状态,不修正业务状态;不一致即事务失败 |
|
||||
| WF-104 | stale 未纳入阶段门禁 | required upstream/downstream lineage 有 stale 时禁止推进,重新批准后清除 stale 并留痕 |
|
||||
| WF-105 | 完成后缺少“选择下一工作流”与受控终止/变更 API | 实现 `completed/termination_requested/terminated` 全状态机及下一实例创建 |
|
||||
| WF-106 | bootstrap 发现已有 published 版本就退出 | 种子升级采用显式版本 manifest;内容 hash 变化创建 v2 draft,经校验批准后发布 |
|
||||
|
||||
### 4.3 P2:可在首发后持续增强
|
||||
|
||||
- 管理员 break-glass:理由、近期认证、限时、醒目标识、禁止代签、完整审计。
|
||||
- MFA/WebAuthn、企业 SSO/SCIM、组织层级和角色层级。
|
||||
- 策略模拟器、权限差异比较、定期访问复核和孤儿权限报告。
|
||||
- 工作流可视化 DAG;首版仍建议坚持线性阶段,减少编排复杂度。
|
||||
- 审计日志防篡改、WORM/外部归档和监管报表。
|
||||
|
||||
## 5. 目标授权架构
|
||||
|
||||
### 5.1 五层判定模型
|
||||
|
||||
每个敏感动作统一调用一个服务端策略决策点(PDP),判定表达式为:
|
||||
|
||||
```text
|
||||
ALLOW = authenticated(principal)
|
||||
AND account.active
|
||||
AND session.active
|
||||
AND permission_allows(action, resource_type, scope)
|
||||
AND project_relationship_allows(principal, project)
|
||||
AND workflow_snapshot_policy_allows(principal, active_instance, stage)
|
||||
AND document_policy_allows(principal, doc_task, document)
|
||||
AND state_machine_allows(action, current_state)
|
||||
AND separation_of_duty_allows(principal, action)
|
||||
|
||||
unknown / missing policy / dependency error => DENY
|
||||
```
|
||||
|
||||
| 层 | 回答的问题 | 数据权威 |
|
||||
|---|---|---|
|
||||
| 认证 | 这个请求是谁,账号/会话是否有效 | `users`、`auth_sessions` |
|
||||
| 系统 RBAC | 是否具备创建、管理、发布、审计等平台动作 | role/permission/binding 表 |
|
||||
| 项目 ReBAC | 是否属于该项目,承担哪些项目业务角色 | `project_members` + `project_role_bindings` |
|
||||
| 工作流/阶段 ABAC | 当前实例、阶段、参与策略是否允许 | 冻结 `config_snapshot` + 实例状态 |
|
||||
| 文档职责/状态 | 是否为该文档的编制/审核/批准人,当前状态能否执行动作 | `document_duty_assignments` + DocGov |
|
||||
|
||||
### 5.2 角色分层
|
||||
|
||||
系统角色不再表达具体项目里的业务职责,项目角色也不再等同于某一份文档的三权。
|
||||
|
||||
| 范围 | 建议内置角色 | 用途 |
|
||||
|---|---|---|
|
||||
| 系统 | 超级管理员、安全管理员、用户管理员、工作流管理员、模板管理员、安全审计员、普通用户 | 平台配置和治理;业务项目数据不因管理员身份默认全开 |
|
||||
| 项目 | 项目创建人、项目经理、商务 BD、产品经理、系统/研发工程师、测试、法规、QA、观察者 | 阶段参与、项目资料范围和业务动作候选资格 |
|
||||
| 文档 | author、reviewer、approver | 绑定单个文档任务实例;必须是具体用户,默认互斥 |
|
||||
|
||||
一个用户可以在同一项目绑定多个业务角色;角色绑定和文档职责均必须有 `valid_from/valid_until/status/assigned_by/reason`。静态职责分离在配置时阻止冲突,动态职责分离在动作时阻止同一主体对同一版本自审自批。
|
||||
|
||||
### 5.3 权限目录
|
||||
|
||||
权限键统一采用 `resource.action`,旧键通过一版兼容映射迁移,之后删除。建议首发目录:
|
||||
|
||||
| 域 | 权限 |
|
||||
|---|---|
|
||||
| 系统 | `system.settings.view/manage`、`system.security.manage`、`system.audit.view/export` |
|
||||
| 用户 | `users.view/create/edit/disable/reset_password`、`users.sessions.revoke` |
|
||||
| 角色 | `roles.view/create/edit/retire/assign/review` |
|
||||
| 工作流 | `workflow_defs.view/create/edit_draft/publish/retire`、`workflow_defs.impact_view` |
|
||||
| 模板 | `templates.view/upload/download/publish/retire` |
|
||||
| 项目 | `projects.create/view/edit/archive`、`projects.members.view/manage` |
|
||||
| 项目流程 | `projects.workflow.view/configure/activate/terminate`、`projects.stage.advance` |
|
||||
| 参与 | `workflow.chat.view/send`、`workflow.task.run`、`workflow.progress.view` |
|
||||
| 任务运行 | `task_runs.view_own/view_project/cancel_own/cancel_any/resume` |
|
||||
| 文档 | `documents.view/edit/submit/review/approve/export`、`documents.visibility.manage` |
|
||||
| 通知 | `notifications.view/update`、`notification_policies.manage` |
|
||||
|
||||
### 5.4 服务端执行点
|
||||
|
||||
不要在每个 handler 手写角色判断。建立:
|
||||
|
||||
```go
|
||||
Decision Authorize(ctx, Principal, Action, ResourceRef, Attributes)
|
||||
|
||||
Decision {
|
||||
Allowed bool
|
||||
ReasonCode string
|
||||
PolicyVersion string
|
||||
Obligations []string // redact, require_recent_auth, audit_reason, etc.
|
||||
}
|
||||
```
|
||||
|
||||
- 路由中间件负责身份和粗粒度权限。
|
||||
- service 层在事务内重新验证对象关系和当前状态,防止 TOCTOU。
|
||||
- repository 查询默认带可见范围,不先查全量再在浏览器过滤。
|
||||
- SSE、附件下载、搜索、导出、RAG、Agent tools 使用同一个 `ResourceRef`/Decision。
|
||||
- 禁止把 `user_id`、`role`、`stage`、`work_dir` 或 duty 作为客户端可信授权输入。
|
||||
- 403/404 策略统一;审计记录 actor、resource、action、decision、reason、request_id、policy_version。
|
||||
|
||||
### 5.5 核心动作矩阵
|
||||
|
||||
| 动作 | 普通成员 | 项目业务角色 | 项目创建人 | 系统管理角色 | 文档三权 |
|
||||
|---|---|---|---|---|---|
|
||||
| 创建项目 | 需 `projects.create` | 同左 | 同左 | 不默认拥有,按绑定 | 无关 |
|
||||
| 查看项目 | active membership | active membership | 是 | 仅 break-glass 或显式审计权限 | 无关 |
|
||||
| 管理成员 | 否 | 项目经理可选 | 是 | break-glass | 无关 |
|
||||
| 配置待激活流程 | 否 | 可提议 | 是 | 工作流管理员不能代替业务确认 | 无关 |
|
||||
| 激活/终止流程 | 否 | 可申请 | 是 + 再确认 | 只可 break-glass | 无关 |
|
||||
| 运行任务 | 否 | 阶段策略允许 + 对应 task permission | 同策略,不绕过 | 不默认 | author 或显式执行人 |
|
||||
| 查看文档 | 文档策略允许 | 阶段/角色策略允许 | 仍受私密/合规策略 | 不默认 | 当前职责人允许 |
|
||||
| 提交审核 | 否 | 否 | 不默认 | 不默认 | author |
|
||||
| 审核 | 否 | 否 | 不默认 | 不默认 | reviewer 且非 author |
|
||||
| 批准 | 否 | 否 | 不默认 | 不默认 | approver 且非 author/reviewer |
|
||||
| 推进阶段 | 否 | 只能申请/接收提醒 | 明确确认 | 不替代业务确认 | 无关 |
|
||||
| 发布工作流版本 | 否 | 否 | 无关 | 工作流发布权限 + 双人复核可选 | 无关 |
|
||||
|
||||
## 6. 设置体系完整方案
|
||||
|
||||
### 6.1 用户设置 `/settings`
|
||||
|
||||
| 页面 | 服务端能力 | 验收 |
|
||||
|---|---|---|
|
||||
| 个人资料 | `GET/PATCH /api/v1/me/profile`;姓名、邮箱、语言、时区;部门/工号受控只读 | 刷新、换设备仍一致;审计敏感字段变更 |
|
||||
| 安全 | 修改密码、MFA 状态、活动会话、撤销其他会话、最近登录 | 修改密码撤销其他会话;撤销后下一请求 401 |
|
||||
| 通知 | 站内/邮件渠道、事件类型、免打扰、升级策略 | Outbox 读取服务端偏好;关键审批提醒不可被完全关闭 |
|
||||
| 偏好 | 主题、默认导出、语言、默认项目页、Agent 显示偏好 | 落库并有 schema 版本;不再只存在组件 state |
|
||||
| 我的权限 | 服务端返回生效角色、作用域、有效期和权限来源 | 不由前端本地 role 推导;支持“为何有/无此权限” |
|
||||
|
||||
安全会话改造:登录响应通过 `Set-Cookie: __Host-agent_session=...; Secure; HttpOnly; SameSite=Lax|Strict; Path=/` 建立会话;状态变更使用 CSRF token/origin 验证;logout 调服务端撤销当前会话。测试环境可通过独立 fixture 获取 Cookie,不在产品包保留任意身份切换。
|
||||
|
||||
### 6.2 项目设置 `/projects/{id}/settings`
|
||||
|
||||
| 页面 | planning | active/awaiting | completed/terminated |
|
||||
|---|---|---|---|
|
||||
| 基本信息 | 创建人编辑 | 受控字段变更单 | 只读/归档 |
|
||||
| 成员与业务角色 | 增删改,校验职责候选 | 变更需影响分析;不能留下无人职责 | 历史只读,可为下个实例配置 |
|
||||
| 工作流选择 | 选已发布版本 | 冻结只读 | 可创建下一个 planning 实例 |
|
||||
| 阶段/任务 | 配置 optional/default,required 不可关闭 | 冻结;仅受控变更 | 快照只读 |
|
||||
| 模板版本 | 从 ready 版本选择 | 冻结 | 快照只读 |
|
||||
| 三权职责 | 必填、互斥、成员/资格校验 | 变更单 + 未决审批处理 | 历史只读 |
|
||||
| 参与/可见策略 | 从版本默认值继承,可按允许范围收紧 | 冻结;紧急收紧可走安全变更 | 历史只读 |
|
||||
| 预览与激活 | diff + 门禁 + 二次确认 | 不显示“重新激活” | 显示下一流程入口 |
|
||||
| 推进/终止 | 无 | 门禁满足后创建人确认;终止需原因/影响 | 展示完整审计 |
|
||||
|
||||
项目创建人不是系统超级管理员。项目设置的“独占确认权”和系统权限的“是否允许操作接口”同时成立:例如可由项目经理编辑草案,但最终激活和阶段推进仍由创建人确认。
|
||||
|
||||
### 6.3 系统管理中心 `/admin/*`
|
||||
|
||||
| 页面 | 必做功能 |
|
||||
|---|---|
|
||||
| 概览 | 服务/DB/Runner/Outbox/worker 健康、失败任务、待审批、策略版本 |
|
||||
| 用户 | 创建、审批、启停、资料、重置密码、撤销会话、多角色绑定、批量导入 |
|
||||
| 角色权限 | 权限目录、多角色、作用域、有效期、职责分离、影响预览、角色退役 |
|
||||
| 工作流设计器 | 创建/复制草稿、阶段排序、任务、执行器、模板、输入输出、门禁、职责候选、参与/可见策略、校验、diff、发布、退役 |
|
||||
| 模板库 | 隔离上传、扫描、预览、变量 schema、版本、发布/退役、引用关系 |
|
||||
| 项目类型与合规 | `product_domain` 与 `compliance_profile` 分离;可用流程、必需文档和签署强度 |
|
||||
| 通知自动化 | 事件、渠道、模板、频率、升级和去重 |
|
||||
| 审计 | 按 actor/action/resource/result/request_id 查询和导出;高风险变更对比 |
|
||||
| 安全 | 注册、审批、密码、MFA、会话时限、CSRF/CORS、上传限制、保留期、break-glass |
|
||||
|
||||
管理端不能继续依赖硬编码权限清单。`GET /api/v1/admin/permissions` 返回目录和风险等级;每个页面使用服务端 capabilities 控制入口,但最终仍由 API 决策。
|
||||
|
||||
## 7. 工作流定义 Schema v2
|
||||
|
||||
现有 schema 只有阶段、位置、人工门禁和文档任务基本字段,无法表达运行绑定、参与策略、职责资格、输入输出和确定性质量门禁。建议新增 `schema_version: 2`:
|
||||
|
||||
```json
|
||||
{
|
||||
"schema_version": 2,
|
||||
"workflow_key": "product_manager",
|
||||
"product_domains": ["medical_device", "non_medical_software"],
|
||||
"required_upstream": [],
|
||||
"participation_policy": {},
|
||||
"completion_policy": {},
|
||||
"stages": [{
|
||||
"key": "requirements_baseline",
|
||||
"name": "系统需求基线",
|
||||
"position": 10,
|
||||
"optional": false,
|
||||
"entry_gate": {},
|
||||
"exit_gate": {},
|
||||
"participation_policy": {},
|
||||
"doc_tasks": [{
|
||||
"key": "system_reqs",
|
||||
"executor_key": "squad.system_reqs.v1",
|
||||
"required": true,
|
||||
"blocking": true,
|
||||
"template": {"asset_key": "system_reqs", "version": 2},
|
||||
"input_contract": {},
|
||||
"output_contract": {},
|
||||
"quality_gate_key": "quality.system_reqs.v2",
|
||||
"eligible_project_roles": {},
|
||||
"visibility_policy": {},
|
||||
"retry_policy": {},
|
||||
"timeout_seconds": 3600
|
||||
}]
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
发布校验必须至少验证:
|
||||
|
||||
- key 格式和全局唯一;stage position 唯一且严格递增;必需阶段/任务不可缺失;
|
||||
- `executor_key` 已注册且声明支持相应输入/输出;不再把未知任务落入 generic runner;
|
||||
- template version 存在且 `scan_status=ready`,变量 schema 与 input contract 一致;
|
||||
- 三权候选角色存在,且不会造成项目无人可配;author/reviewer/approver 默认互斥;
|
||||
- 上游工作流和文档依赖无环、能解析到已发布版本;
|
||||
- 每个 required/blocking task 有确定性质量门禁;
|
||||
- 可见/参与策略有明确默认值,未知即拒绝;
|
||||
- 发布后 definition JSON/hash 和所有引用版本不可变;编辑从已发布版本复制新 draft。
|
||||
|
||||
## 8. 三个工作流的正式定义
|
||||
|
||||
### 8.1 兼容性决定
|
||||
|
||||
当前项目和代码广泛使用 `main` 代表商务主线。首轮迁移**保留稳定 key `main`**,显示名统一为“商务对接”,避免破坏存量项目、任务记录和文档 ID;停止在新代码里把它解释成“任意默认流程”。`product_manager` 和 `test_manager` 保持现有 key。若未来希望改为 `business_engagement`,新增显式 alias 表,不直接改历史 key。
|
||||
|
||||
三个正式版本均以 v2 draft 创建和发布;不得修改已有 published v1,也不得依赖当前 `UpsertPublishedSeed` 自动覆盖。已 active 的 v1 项目继续使用原快照;planning 项目由创建人查看 diff 后主动升级。
|
||||
|
||||
### 8.2 商务对接 `main` v2
|
||||
|
||||
当前真实执行器已有以下阶段和任务,本方案将其搬入版本定义,执行器只保留能力注册,不再保留另一套阶段事实源。[^13]
|
||||
|
||||
| 顺序 | 阶段 | 文档任务 | 必需/阻断 | 建议三权候选 | 退出门禁 |
|
||||
|---:|---|---|---|---|---|
|
||||
| 10 | `V0.1_triage` 闪电摸底与盲区探测 | `intake` 客户需求采集/初始需求表 | 是/是 | author: BD/PM;reviewer: 项目经理;approver: 创建人或商务负责人 | intake approved;关键项无缺失;无运行任务 |
|
||||
| 20 | `V0.5_feasibility` 方案成型与法规对齐 | `research` 竞品调研;`feasibility_reg` 法规可行性;`prelim_design` 初步设计 | 全部是/是 | 按文档分别指派 BD、法规、研发;审核/批准分离 | 三文档 approved;无 stale/open change;entry inputs 已基线化 |
|
||||
| 30 | `V1.0_quoting` 工程拆解与商业锁定 | `cdo_quote` CDO 报价与核算 | 是/是 | author: 商务/项目经理;reviewer: 技术/财务;approver: 创建人/授权商务负责人 | 正文和核算 XLSX hash 一致、approved;报价关键字段完整 |
|
||||
|
||||
参与策略默认值:
|
||||
|
||||
- BD 可参与 V0.1/V0.5 的 `intake/research`,不因“是项目成员”自动获得 `prelim_design` 或报价批准权。
|
||||
- 法规只访问被授权的法规任务及其显式上游;研发只访问初步设计及显式上游。
|
||||
- 创建人可看项目进度并确认推进,但不会自动获得某份文档的审核/批准动作。
|
||||
- 阶段完成只产生 `ready_to_advance` 通知;创建人确认后原子进入下一阶段。
|
||||
|
||||
### 8.3 智能产品经理 `product_manager` v2
|
||||
|
||||
项目层保持一个受控阶段,阶段内的五个 Agent step 是 executor 内部步骤,不把内部 agent step 误建成五个需要人工推进的项目阶段。现有代码已经定义需求梳理、系统工程、法规、成文、终审五角色和五步执行链,可直接注册为 `squad.system_reqs.v1`。[^20]
|
||||
|
||||
| 项 | 正式配置 |
|
||||
|---|---|
|
||||
| 阶段 | `requirements_baseline` 系统需求基线,position=10,required/blocking |
|
||||
| 文档任务 | `system_reqs`,输出受控《系统需求规格书》 |
|
||||
| 执行器 | `squad.system_reqs.v1` |
|
||||
| 模板 | `system_reqs` ready version;发布时固定版本 |
|
||||
| 必需输入 | 项目五要素;已批准/显式基线化的客户需求或上游商务文档;项目材料清单 |
|
||||
| 结构化输出 | `output.md`、`artifacts/requirements.json`、manifest/hash、质量报告 |
|
||||
| 三权候选 | author: PM/系统工程;reviewer: 技术负责人/法规;approver: 创建人授权的批准人/QA |
|
||||
| 质量门禁 v2 | 每条需求唯一 ID;来源、理由、优先级、可验证准则、验证方法齐全;无未替换占位;JSON 与正文一致;重复/冲突/孤儿需求为 0 |
|
||||
| 完成门禁 | executor 成功 + deterministic gate 通过 + 文档 approved + 无 stale/open change/running task |
|
||||
|
||||
当前质量门禁只检查正文中是否出现 `REQ-` 和宽泛的“测试/分析/审查”等词,达不到“需求集合完整、唯一、可追溯、可测”的正式门禁。v2 必须解析 `requirements.json`,以结构化集合为准,并把校验报告与文档版本绑定。[^21]
|
||||
|
||||
### 8.4 智能测试经理 `test_manager` v2
|
||||
|
||||
| 项 | 正式配置 |
|
||||
|---|---|
|
||||
| 阶段 | `system_verification_planning` 系统验证策划,position=10,required/blocking |
|
||||
| 文档任务 | `test_manager`,输出受控《系统验证方案及计划》 |
|
||||
| 执行器 | `squad.test_manager.v1` |
|
||||
| 上游条件 | 同项目最近一次已批准且非 stale 的 `system_reqs`;记录上游 doc/version/hash |
|
||||
| 模板 | `test_manager` ready version;发布时固定版本 |
|
||||
| 结构化输出 | `output.md`、必需的 `artifacts/test_cases.json`、coverage report、manifest/hash |
|
||||
| 三权候选 | author: 测试;reviewer: 系统/法规;approver: 测试负责人/QA,三者互斥 |
|
||||
| 质量门禁 v2 | 上游需求全集解析成功;每条 requirement 至少一条有效 case;case ID 唯一;步骤、预期、判据、环境、方法完整;覆盖率 100%;无孤儿引用 |
|
||||
| stale 策略 | 上游 SR hash 变化立即将下游标为 stale,禁止提交/批准/阶段完成,完成影响分析与重新基线后解除 |
|
||||
|
||||
现有 executor 已要求上游 SR approved 并建立血缘,也定义了 100% 覆盖的 Agent 目标;但当前确定性门禁只检查 `TC-/TEST-`、`REQ-` 字符串,并且 `test_cases.json` 仅在文件存在时校验 JSON,文件不存在不会失败。v2 必须把结构化用例文件和覆盖率报告设为必需产物。[^21][^22]
|
||||
|
||||
### 8.5 三个工作流的串联语义
|
||||
|
||||
系统当前设计是“一项目最多一个 live 工作流”,不是三条流程同时 active:
|
||||
|
||||
```text
|
||||
商务对接 completed/受控 terminated
|
||||
-> 创建人选择并配置 product_manager v2
|
||||
-> 产品经理流程 completed,系统需求 approved
|
||||
-> 创建人选择并配置 test_manager v2
|
||||
-> 测试经理流程完成
|
||||
```
|
||||
|
||||
系统可以在前一流程门禁满足时推荐下一个流程并通知创建人,但绝不自动激活。上游依赖解析按文档类型 + workflow instance + approved version 查询,不依赖固定文件路径或仅由字符串拼出的 doc ID。
|
||||
|
||||
## 9. 配置到运行时的唯一权威链
|
||||
|
||||
必须建立以下单向链,禁止旁路:
|
||||
|
||||
```text
|
||||
published workflow version + ready template versions
|
||||
↓ creator configures / preview / confirms
|
||||
immutable project workflow snapshot
|
||||
↓ creates ordered stage/task instances + duty assignments
|
||||
active stage + authorized doc task instance
|
||||
↓ resolves executor, template, inputs, actor obligations
|
||||
task run + DocGov document version + lineage + audit
|
||||
↓ deterministic gate + three-duty approval + no stale/open work
|
||||
ready_to_advance notification
|
||||
↓ creator explicit confirmation
|
||||
next stage OR workflow completed
|
||||
```
|
||||
|
||||
具体约束:
|
||||
|
||||
1. `POST task-runs` 接收 `doc_task_instance_id` 和业务输入,不接收可信 `user_id/role/stage/work_dir/reviewer_id/approver_id`。
|
||||
2. 服务端锁定实例和 task instance,验证 active stage、actor、executor、模板和当前状态。
|
||||
3. WorkDir 由服务端按 project/instance/task_run 生成并做路径约束。
|
||||
4. DocGov 从 duty assignment 创建/校验文档责任人,stage 来自 stage instance。
|
||||
5. 任务结果写入与运行终态、文档版本、manifest、lineage、outbox 使用事务/可恢复 saga,避免“显示完成但产物未落稳”。
|
||||
6. 列表、详情、导出、附件、搜索、SSE、RAG 和 Agent tool read 都使用同一资源授权上下文。
|
||||
|
||||
## 10. 数据库迁移方案
|
||||
|
||||
迁移号以合并时最新 Goose 版本为准,下表暂按 `00021+` 表示。
|
||||
|
||||
| 迁移 | 主要变更 | 兼容/回填 |
|
||||
|---|---|---|
|
||||
| 00021 IAM hardening | project_members.user_id FK;role/binding 状态、reason;审计 actor;权限键 alias | 校验孤儿成员后加 FK;旧 `users.role_id` 双读一版、停止写入 |
|
||||
| 00022 project roles | `project_roles`、`project_role_permissions`、`project_user_role_bindings` | owner/member/viewer 映射为 owner/contributor/observer;原表保留 membership 状态 |
|
||||
| 00023 settings | user preferences、notification preferences、security policy versions | 把可识别的 local preferences 一次性导入需用户确认;其余使用服务端默认 |
|
||||
| 00024 workflow schema v2 | executor registry/version、schema fields、policy JSON schema/version | 不修改 v1 JSON;validator 按 schema_version 路由 |
|
||||
| 00025 instance integrity | stage position、task executor/template/output snapshot、duty eligibility、change requests | 修正现有 position;对 active 数据先报告后修复,不静默重排 |
|
||||
| 00026 authorization audit | `authorization_audit_events` 或统一 audit_event 扩展、policy version、request ID | 明确保留期和敏感字段脱敏 |
|
||||
| 00027 workflow v2 manifests | 创建三个 v2 draft/版本 manifest | 只在 hash 匹配预期时创建;不覆盖用户自定义版本 |
|
||||
|
||||
数据库约束建议:
|
||||
|
||||
- live instance 部分唯一索引继续保留;增加 planning 与 live 状态转换约束测试。
|
||||
- `project_stage_instances(workflow_instance_id, position)` unique,position > 0。
|
||||
- task instance 保存 `executor_key/template_version/output_doc_type/quality_gate_key` 的冻结副本。
|
||||
- duty assignment 引用 active project membership;跨表动态条件用事务 trigger 或 service + deferred validation 实现。
|
||||
- activation token 只存 hash;高风险一次性 token 使用短 TTL、actor/project/plan hash 绑定。
|
||||
- published definition/template 通过数据库权限或 trigger 阻止 UPDATE/DELETE,不只依赖 Go service。
|
||||
|
||||
## 11. API 调整
|
||||
|
||||
### 11.1 身份与设置
|
||||
|
||||
```text
|
||||
POST /api/v1/auth/login -> Set-Cookie
|
||||
POST /api/v1/auth/logout -> revoke current session
|
||||
GET /api/v1/me
|
||||
PATCH /api/v1/me/profile
|
||||
GET/PUT /api/v1/me/preferences
|
||||
GET/PUT /api/v1/me/notification-preferences
|
||||
GET /api/v1/me/sessions
|
||||
DELETE /api/v1/me/sessions/{id}
|
||||
POST /api/v1/me/password/change
|
||||
```
|
||||
|
||||
### 11.2 权限与管理
|
||||
|
||||
```text
|
||||
GET /api/v1/admin/permissions
|
||||
GET/POST/PATCH /api/v1/admin/roles...
|
||||
GET/POST/DELETE /api/v1/admin/role-bindings...
|
||||
POST /api/v1/admin/authorization/simulate
|
||||
GET /api/v1/admin/audit-events
|
||||
POST /api/v1/admin/users/{id}/reset-password
|
||||
POST /api/v1/admin/users/{id}/sessions/revoke
|
||||
```
|
||||
|
||||
每个 admin endpoint 绑定独立 permission,不再通过 `requireSystemAdmin` 全包。
|
||||
|
||||
### 11.3 工作流与项目实例
|
||||
|
||||
```text
|
||||
POST /api/v1/admin/workflows/{id}/versions/{v}/copy-draft
|
||||
PATCH /api/v1/admin/workflows/{id}/versions/{v}
|
||||
POST /api/v1/admin/workflows/{id}/versions/{v}/validate
|
||||
GET /api/v1/admin/workflows/{id}/versions/{v}/impact
|
||||
POST /api/v1/admin/workflows/{id}/versions/{v}/publish
|
||||
POST /api/v1/admin/workflows/{id}/versions/{v}/retire
|
||||
|
||||
GET/PUT /api/v1/projects/{id}/workflow-plan
|
||||
POST /api/v1/projects/{id}/workflow-plan/preview
|
||||
POST /api/v1/projects/{id}/workflow-plan/activate
|
||||
POST /api/v1/projects/{id}/workflow-instances/{iid}/termination-requests
|
||||
POST /api/v1/projects/{id}/workflow-instances/{iid}/terminate
|
||||
POST /api/v1/projects/{id}/workflow-instances/{iid}/change-requests
|
||||
POST /api/v1/projects/{id}/workflow-instances/{iid}/stages/{stage}/advance
|
||||
POST /api/v1/projects/{id}/doc-tasks/{taskInstanceId}/runs
|
||||
```
|
||||
|
||||
所有资源路径先验证 path 中 project/instance/stage/task/document 的归属一致性,避免用合法项目权限访问另一个项目的子资源。
|
||||
|
||||
## 12. 前端实施方案
|
||||
|
||||
1. **认证壳**:不从 `localStorage` 恢复 principal/token;启动时只调用 `/me`。401 清空全部敏感状态并跳转登录。
|
||||
2. **权限 Provider**:从 `/me` 获取 capabilities + scoped grants;按钮、菜单和路由只做 UX 控制,错误统一展示服务端 reason code。
|
||||
3. **用户设置**:现有 modal 拆到真实 API;接入活动会话;资料/偏好保存失败不更新本地成功态。
|
||||
4. **系统管理中心**:从单一大 modal 演进为路由页面;权限矩阵来自 catalog;高风险变更提供 diff、影响人数和二次确认。
|
||||
5. **工作流设计器**:线性阶段排序、每阶段多任务、executor 只从注册表下拉、模板版本选择、职责候选、参与/可见策略、JSON 高级视图、发布校验报告。
|
||||
6. **项目设置**:明确 planning/live/history 三态;live 快照只读;门禁列表展示每个阻断项;下一工作流必须由创建人确认。
|
||||
7. **工作台**:根据服务端返回的 allowed actions 渲染,不在前端用姓名/本地角色重新计算业务授权。
|
||||
8. **删除演练入口**:`UserProjectRightsModal` 的测试角色切换、旧 `SettingsModal`、本地模拟分支和生产 bundle 中的测试身份文案移出产品代码。
|
||||
|
||||
## 13. 分阶段交付计划
|
||||
|
||||
估时为单个熟悉代码库的小组工作日,安全修复与工作流建模可并行开发,但发布必须按闸门顺序。
|
||||
|
||||
### Phase 0:基线冻结与权限清单(1–2 天)
|
||||
|
||||
- 固定 commit、DB schema、环境和三个 workflow v1 hash。
|
||||
- 自动导出全部 `/api/v1` 路由,建立 resource/action/owner/negative test 矩阵。
|
||||
- 修正当前 E2E 报告状态矛盾;归档一次干净的 short test 和 build 结果。
|
||||
- 输出:`authorization-matrix-v2.md`、migration preflight SQL、测试数据拓扑。
|
||||
|
||||
门禁:每个非公开路由都有责任 owner、策略和至少一个未授权负例;未知路由默认为拒绝。
|
||||
|
||||
### Phase 1:P0 授权止血(3–5 天)
|
||||
|
||||
- 修复 AUTH-001–009、WF-001/002 的越权入口。
|
||||
- 建立统一 `Authorize`/ResourceRef 和 server-side allowed actions。
|
||||
- 删除固定管理员/演示项目 ID 豁免;生产禁用 permissive fallback。
|
||||
- Cookie/CSRF/logout/401 前端失效闭环。
|
||||
|
||||
门禁:匿名、跨用户、跨项目、跨阶段、错 task、错 child resource、DB authz fault 全部负例通过;SSE/RAG/Agent tool 同样验证。
|
||||
|
||||
### Phase 2:IAM 与设置权威化(4–6 天)
|
||||
|
||||
- 完成 IAM-101–105 和用户/项目/系统设置 API。
|
||||
- 角色多绑定、作用域/有效期、permission catalog、原子用户变更和审计。
|
||||
- 用户资料、偏好、通知、活动会话 UI;管理中心权限拆分。
|
||||
|
||||
门禁:重启/换浏览器数据一致;权限收回和账号停用下一请求生效;至少两名管理员防锁死演练通过。
|
||||
|
||||
### Phase 3:工作流 Schema v2 与运行时合流(5–8 天)
|
||||
|
||||
- 实现 schema v2、executor/quality gate registry、完整 validator。
|
||||
- 移除 `flattenVersion` 作为执行路径;编排器只读实例快照。
|
||||
- 修复 position、token 原子性、DocGov duty/stage 绑定、stale 门禁。
|
||||
- 完成受控终止、变更单和下一个工作流生命周期。
|
||||
|
||||
门禁:修改全局 published/latest 不影响 active 实例;请求伪造 stage/task/duty 无效;故障恢复后实例位置和职责不漂移。
|
||||
|
||||
### Phase 4:发布三个 v2 工作流(4–6 天)
|
||||
|
||||
- 按 §8 创建 `main`、`product_manager`、`test_manager` v2 draft。
|
||||
- 绑定 ready 模板和 executor;补齐结构化门禁。
|
||||
- 对 planning v1 项目生成可读 diff,由创建人选择是否升级;active v1 不迁移。
|
||||
- 完成三个流程的串联推荐,但保持人工选择/激活。
|
||||
|
||||
门禁:三个版本通过静态校验、dry-run、单流程 PG E2E 和串联 PG E2E。
|
||||
|
||||
### Phase 5:管理端/项目端完整体验(4–6 天)
|
||||
|
||||
- 工作流设计器、模板库、项目规划、门禁详情、影响预览、下一流程、终止/变更 UI。
|
||||
- 删除旧本地/演示权威路径和不实合规文案。
|
||||
- 可访问性、错误恢复、并发 diff/reconfirm。
|
||||
|
||||
门禁:产品经理无需改代码即可复制 v2 为 v3 草案、换模板/职责候选、校验并由有权者发布;普通管理员无法越权发布。
|
||||
|
||||
### Phase 6:发布验证与灰度(5–8 天)
|
||||
|
||||
- 全量 Go/前端、race、PG、迁移升级/回滚、重启、worker 故障注入。
|
||||
- 真实 PI Agent 三工作流 E2E;长任务超时/恢复/取消;跨用户负例。
|
||||
- 备份恢复、日志脱敏、监控告警、容量和 bundle 分包。
|
||||
- 灰度一个内部项目,再扩到新项目;旧项目只读兼容指标归零后删除 fallback。
|
||||
|
||||
门禁:§14 全部完成;P0/P1 为 0;可恢复演练和回滚演练均有报告。
|
||||
|
||||
总体建议:**21–35 个小组工作日**。如多人并行,最短日历时间约 4–5 周;不应通过跳过负例、迁移和真实 Runner 验证压缩关键路径。
|
||||
|
||||
## 14. 测试与验收矩阵
|
||||
|
||||
### 14.1 授权负例
|
||||
|
||||
| 场景 | 预期 |
|
||||
|---|---|
|
||||
| 未登录访问任意非公开 API/SSE/附件 | 401,不泄漏资源存在性 |
|
||||
| A 项目成员读 B 项目、run history、lineage、搜索、导出 | 403/404,审计 deny |
|
||||
| 当前阶段 BD 请求研发 task key | 403;不创建 task_run/workdir/doc |
|
||||
| 非职责人提交/审核/批准 | 403;状态、版本、审计不变 |
|
||||
| author 尝试审核或批准同一版本 | 409/403 SoD violation |
|
||||
| authz DB/策略加载故障 | 敏感路径拒绝,健康状态 degraded,触发告警 |
|
||||
| 权限撤销后复用旧页面/旧 SSE/旧 Cookie | 下一次鉴权失败;流关闭或重新鉴权 |
|
||||
| 猜测 task/document/template/blob ID | 不能跨项目读取 |
|
||||
| 客户端伪造 user/role/stage/workdir/duty | 服务端忽略或 400;不得改变判定 |
|
||||
|
||||
### 14.2 工作流配置与冻结
|
||||
|
||||
- v2 required stage/task 被遗漏、禁用、重复或错序时校验失败。
|
||||
- executor 未注册、模板非 ready、变量 schema 不匹配时禁止发布。
|
||||
- published version UPDATE/DELETE 在 service 和 DB 层均失败。
|
||||
- 激活 token 重放、过期、跨 actor、跨 project、plan hash 不同均失败。
|
||||
- 并发保存/激活/推进只成功一个;另一方收到 diff/reconfirm,不自动重试。
|
||||
- 修改 v3 不影响使用 v2 的 active 项目;历史 hash 可复算。
|
||||
- 流程未完成/未终止时不能创建第二个 live;完成后可配置下一个 planning。
|
||||
|
||||
### 14.3 三工作流 E2E
|
||||
|
||||
**商务对接:** 按 V0.1 → V0.5 三任务 → V1.0 运行;每阶段文档分别走三权;未全部 approved 不产生 ready;满足后产生一次去重提醒;只有创建人确认推进。
|
||||
|
||||
**智能产品经理:** 从批准的输入基线生成 `requirements.json` 和正文;随机抽取、重复 ID、缺验证准则、正文/JSON 不一致均被确定性门禁拒绝;批准后可作为下游输入。
|
||||
|
||||
**智能测试经理:** 没有 approved SR、SR stale、hash 不匹配时拒绝启动;生成必需 `test_cases.json`;需求全集覆盖率必须 100%;上游更新后下游立即 stale 且不能完成。
|
||||
|
||||
**串联:** `main` 完成后只推荐 PM;创建人配置并激活;PM 完成后只推荐 Test;每个实例版本、模板、职责、输入 hash、输出 hash 和审计链可追溯。
|
||||
|
||||
### 14.4 运行与灾难恢复
|
||||
|
||||
- 应用、worker、PostgreSQL、PI Runner 分别重启,验证会话/任务/实例/Outbox 恢复。
|
||||
- PI Runner 超时后 task 可恢复或明确失败,不重复生成审批版本。
|
||||
- Outbox 重投不重复发阶段提醒;消费者幂等。
|
||||
- 迁移从 v20 的生产快照升级;备份恢复后 hash/权限/实例一致。
|
||||
- `go test -race`、前端测试、生产 build、依赖/镜像扫描、长期 soak。
|
||||
|
||||
## 15. 发布完成定义(Definition of Done)
|
||||
|
||||
只有同时满足以下条件,才能宣布“权限、设置和三个工作流已按当前设计做全”:
|
||||
|
||||
- [ ] 生产产品不存在任意身份切换、本地认证 fallback 或客户端身份权威。
|
||||
- [ ] 每个 API/SSE/RAG/Agent tool/附件通路都有服务端授权和跨用户负例。
|
||||
- [ ] 授权失败或依赖异常默认拒绝;不存在固定用户 ID、项目 ID 特权。
|
||||
- [ ] 系统角色、项目业务角色、文档三权分离且可审计;三权职责分离生效。
|
||||
- [ ] 用户、项目、系统三类设置均由服务端持久化,刷新/重启/换端一致。
|
||||
- [ ] 工作流、模板、权限管理使用各自细粒度 permission,而不是全员超级管理员。
|
||||
- [ ] 已发布工作流/模板不可变;项目激活冻结版本、模板、阶段、任务、策略和职责。
|
||||
- [ ] 同一项目最多一个 live;完成/受控终止后由创建人选择下一个。
|
||||
- [ ] 门禁满足只通知,不自动推进;创建人确认与推进在事务中完成。
|
||||
- [ ] `main` v2 完整执行 V0.1/V0.5/V1.0,不再由硬编码目录另行决定。
|
||||
- [ ] `product_manager` v2 结构化需求门禁通过;`test_manager` v2 实现 100% 需求覆盖和 stale 阻断。
|
||||
- [ ] DocGov 的 stage 和三权全部来自冻结实例,客户端不能覆盖。
|
||||
- [ ] PG、真实 PI Agent、重启恢复、故障注入、跨项目/跨阶段负例均有可复现报告。
|
||||
- [ ] P0/P1 缺陷归零,灰度/回滚/监控/告警和审计查询可用。
|
||||
|
||||
## 16. 风险与控制
|
||||
|
||||
| 风险 | 概率/影响 | 控制 |
|
||||
|---|---|---|
|
||||
| v1/v2 双执行权威并存 | 高/高 | feature flag 只选一个 orchestrator;记录每次 run 的 schema/executor/version;不静默 fallback |
|
||||
| 存量项目职责/成员数据不完整 | 高/中 | preflight 报告;active 不强迁;planning 由创建人补全并确认 |
|
||||
| 权限收紧影响现有演示项目 | 高/中 | 显式 legacy visibility 数据迁移;不保留 ID 豁免;灰度观察 deny 指标 |
|
||||
| Cookie 改造引入 CSRF | 中/高 | SameSite + CSRF token + Origin/Referer 校验;状态变更不用 GET |
|
||||
| 长 Agent 运行与 HTTP 超时 | 高/高 | 异步 task + lease/heartbeat + resumable worker;客户端订阅状态,不持有超长请求 |
|
||||
| 结构化质量门禁误报 | 中/中 | schema version、明确错误定位、golden corpus、允许修复重跑但不可人工静默跳过 |
|
||||
| 角色配置锁死管理员 | 中/高 | 双管理员、关键权限不可清空、变更影响预览、break-glass 离线流程 |
|
||||
| 模板恶意文件/解析炸弹 | 中/高 | 隔离、扩展/MIME/签名、大小/解压限制、扫描、Web root 外 CAS;仅 ready 可引用 |
|
||||
|
||||
## 17. 建议的首个迭代任务包
|
||||
|
||||
第一周不要先画完整工作流设计器,先完成以下可独立验收的任务:
|
||||
|
||||
1. `AUTH-001`:给 run history/lineage 及所有项目子资源补统一对象授权和双用户 PG 负例。
|
||||
2. `AUTH-002`:阶段访问错误全部 fail closed,加入数据库故障注入测试。
|
||||
3. `AUTH-003`:workflow run/task run 改从 task instance 推导 task/stage/executor,客户端覆盖返回 400。
|
||||
4. `AUTH-004/005`:补必需项反向校验和 duty member/status/role eligibility 校验。
|
||||
5. `AUTH-006/007`:删除 ID 特判,项目列表改用 `ListVisibleProjectIDs`/membership join,创建项目校验 permission。
|
||||
6. `AUTH-009`:服务端 logout + `/me` 失效清理;设计 Cookie/CSRF 兼容迁移。
|
||||
7. `WF-001/002`:提交 schema v2 ADR 和 runtime authority contract,阻止新增旁路。
|
||||
|
||||
首周验收物应是:代码、迁移 preflight、授权矩阵、负例测试、更新后的安全报告。只有该闸门通过,才开始发布三个 v2 draft。
|
||||
|
||||
## 18. 交付物清单
|
||||
|
||||
- 本实施方案。
|
||||
- API 授权矩阵 v2(路由、动作、资源、策略、负例、owner)。
|
||||
- Schema v2 JSON Schema + executor/quality gate registry ADR。
|
||||
- Goose 00021+ 迁移和 preflight/rollback SQL。
|
||||
- 三个工作流 v2 manifest、模板版本清单和 golden fixtures。
|
||||
- 用户/项目/系统设置产品规格与 API contract。
|
||||
- 授权负例、PG、真实 PI Agent、迁移、恢复、soak 测试报告。
|
||||
- 灰度清单、监控面板、告警规则、回滚 runbook。
|
||||
|
||||
## 资料来源
|
||||
|
||||
[^1]: 当前治理原则与目标模型见 [2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md)。
|
||||
[^2]: IAM、工作流定义、项目实例、通知和任务持久化分别见 [00015 IAM](../deploy/postgres/goose/00015_2026-09-12-iam-core.sql)、[00016 workflow definitions](../deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql)、[00017 project instances](../deploy/postgres/goose/00017_2026-09-12-project-workflow-instances.sql)、[00018 outbox](../deploy/postgres/goose/00018_2026-09-12-outbox-notifications-stage-advance.sql)、[00019 task runs](../deploy/postgres/goose/00019_2026-09-12-task-runs-events.sql) 和 [00020 worker lease](../deploy/postgres/goose/00020_2026-09-12-task-run-worker-lease.sql)。
|
||||
[^3]: 本轮验证命令与结果记录在本方案 §2.2;当前历史测试状态见 [2026-09-12-pg-ci-soak-e2e-test-report.md](./test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md)。
|
||||
[^4]: 系统能力查询没有限定 binding scope/role status/valid_from,且 role-admin 字符串直接判 admin,见 [internal/authz/service.go](../internal/authz/service.go#L26-L99)。
|
||||
[^5]: 创建项目只验证身份,见 [project_handlers.go](../internal/server/project_handlers.go#L16-L46);运行历史和血缘查询未做项目访问判断,见同文件 [run history/lineage](../internal/server/project_handlers.go#L221-L274)。
|
||||
[^6]: 工作流管理统一走 `requireSystemAdmin`,没有使用已经入库的 `workflow_defs.*`,见 [admin_workflow_handlers.go](../internal/server/admin_workflow_handlers.go#L13-L23);权限种子见 [00016](../deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql#L67-L82)。
|
||||
[^7]: `ResolveStageAccess` 在 live 查询错误时返回 unrestricted,且一个阶段任一职责会放开该阶段全部任务,见 [stage_access.go](../internal/projectinstance/stage_access.go#L15-L68);服务器过滤辅助函数也在错误时放行,见 [stage_access_helpers.go](../internal/server/stage_access_helpers.go#L23-L47)。
|
||||
[^8]: 任务门禁在 actor 能访问 active stage 时放过不匹配 task,见 [bizdev_stage_gate.go](../internal/server/bizdev_stage_gate.go#L40-L54);workflow run 接收客户端 task override,见 [project_handlers.go](../internal/server/project_handlers.go#L205-L218)。
|
||||
[^9]: token/session 存 localStorage 且 logout 只删除本地键,见 [web/src/api/auth.ts](../web/src/api/auth.ts#L306-L330);恢复 session 后 `/me` 失败被吞掉,见 [web/src/App.tsx](../web/src/App.tsx#L690-L703)。
|
||||
[^10]: 用户设置把偏好描述为浏览器本地并从前端角色推导权限,见 [UserSettingsModal.tsx](../web/src/components/user/UserSettingsModal.tsx#L68-L77) 与 [同文件](../web/src/components/user/UserSettingsModal.tsx#L673-L779);后端已有活动会话 API,见 [auth_handlers.go](../internal/server/auth_handlers.go#L162-L204)。
|
||||
[^11]: 三个单阶段种子见 [workflowdef/bootstrap.go](../internal/workflowdef/bootstrap.go#L63-L74);seed 遇到已有发布版本直接退出,见 [workflowdef/store.go](../internal/workflowdef/store.go#L364-L372)。
|
||||
[^12]: DBCatalog 只取首阶段/首任务,见 [workflowdef/catalog.go](../internal/workflowdef/catalog.go#L50-L82);现有 schema 能表达的字段见 [workflowdef/types.go](../internal/workflowdef/types.go#L15-L43)。
|
||||
[^13]: 商务流程真实阶段和任务仍由 [internal/bizdev/service.go](../internal/bizdev/service.go#L202-L223) 硬编码。
|
||||
[^14]: 规划 validator 只遍历客户端提交项,没有反向验证必需定义项是否缺失,见 [projectinstance/validator.go](../internal/projectinstance/validator.go#L37-L105);三权只校验非空和互斥,见 [同文件](../internal/projectinstance/validator.go#L108-L144)。
|
||||
[^15]: 阶段实例 position 固定写 0,见 [projectinstance/store.go](../internal/projectinstance/store.go#L244-L249);执行器默认 reviewer=2、approver=3 并固定阶段,见 [bizdev/service.go](../internal/bizdev/service.go#L383-L418)。
|
||||
[^16]: 当前报告的真实 PI Agent E2E 记录 `/v1/run` 超时,同时结论仍称“进行中”,见 [2026-09-12-pg-ci-soak-e2e-test-report.md](./test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md)。
|
||||
[^17]: [OWASP Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html)。
|
||||
[^18]: [NIST Role Based Access Control](https://csrc.nist.gov/Projects/Role-Based-Access-Control) 与 [NIST SP 800-162 ABAC](https://csrc.nist.gov/pubs/sp/800/162/upd2/final)。
|
||||
[^19]: [OWASP Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html)。
|
||||
[^20]: 产品经理和测试经理的 Agent 角色及职责见 [squad/workspace.go](../internal/squad/workspace.go#L648-L743),内部步骤见 [同文件](../internal/squad/workspace.go#L940-L1073)。
|
||||
[^21]: 当前产品/测试质量门禁见 [squad/quality_gate.go](../internal/squad/quality_gate.go#L108-L146)。
|
||||
[^22]: 测试经理对 approved SR 的前置校验和材料注入见 [bizdev/service.go](../internal/bizdev/service.go#L365-L381),stale 传播见 [projectworkflow/service.go](../internal/projectworkflow/service.go#L237-L265)。
|
||||
@@ -0,0 +1,99 @@
|
||||
# Phase 1:账户与授权权威化 Implementation Plan
|
||||
|
||||
> **依据**:[2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) §5.2、§4、§12、Phase 1
|
||||
> **前置**:Phase 0 已合并(5 commits on `dev`,`8341168`)
|
||||
|
||||
**Goal:** 登录、角色、权限、项目成员关系全部以数据库 + 服务端策略为唯一权威;前端只消费 `capabilities`;重启后会话/账户策略仍有效;禁用账户下一请求失效。
|
||||
|
||||
**Architecture:** Goose 迁移新增 IAM 表 → `PostgresAuthStore` 替换 `MemoryStore`(dev 可 feature flag 回退)→ `AuthorizationService` 统一 RBAC + `project_members` + admin 判定 → `/api/v1/auth/me` 返回 capabilities → 管理端用户/角色 API 持久化 → 前端移除 localStorage 权限权威。
|
||||
|
||||
**Tech Stack:** Goose、pgx、现有 `internal/auth`、`internal/authz`、React/Vite。
|
||||
|
||||
**明确不在本阶段:** 工作流版本模型、阶段 ABAC、capabilities 到每个 DocGov 动作的全覆盖(先系统 + 项目 + 已挂 authz 路由)。
|
||||
|
||||
---
|
||||
|
||||
## 完成门禁
|
||||
|
||||
| 门禁 | 判定 |
|
||||
|---|---|
|
||||
| 持久化账户 | 重启后 users/roles 仍在 DB |
|
||||
| 持久化会话 | token 存哈希;logout/禁用立即失效 |
|
||||
| 无 localStorage RBAC 权威 | `AdminSettingsModal` 读写 API;`hasPermission` 仅 UI 兜底并标注 deprecated |
|
||||
| 项目成员 CRUD | 创建者可增删改成员;API 测试 |
|
||||
| 负例 | 禁用用户 token → 401;跨项目已挂 authz → 403 |
|
||||
|
||||
---
|
||||
|
||||
## 任务分解
|
||||
|
||||
### Task 1 — IAM 数据库迁移(`feat(db)`)
|
||||
|
||||
新建 `deploy/postgres/goose/00015_iam_core.sql`:
|
||||
|
||||
- `users`(id, 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)
|
||||
- `auth_sessions`(id, token_hash, user_id, created_at, last_seen_at, idle_expires_at, absolute_expires_at, revoked_at, ip_hash, user_agent)
|
||||
- `roles` / `permissions` / `role_permissions` / `user_role_bindings`
|
||||
- seed:`role-admin` + 核心 permissions + 从 MemoryStore dev 用户回填(仅 dev/test 迁移脚本)
|
||||
|
||||
约束:username unique;token_hash unique;至少一个 super-admin binding。
|
||||
|
||||
### Task 2 — PostgresAuthStore(`feat(auth)`)
|
||||
|
||||
- `internal/auth/pg_store.go` 实现 `AuthStore`
|
||||
- 会话:Login 写 `auth_sessions`(只存 SHA256(token));ValidateToken 查库 + 更新 last_seen
|
||||
- Logout/RevokeAll 标记 revoked_at
|
||||
- `server.go`:有 `ContextDbHost` 时用 PgStore,否则 dev 仍 MemoryStore
|
||||
|
||||
### Task 3 — AuthorizationService(`feat(authz)`)
|
||||
|
||||
- `internal/authz/service.go`:`Capabilities(ctx, userID) []string`
|
||||
- `HasPermission(ctx, userID, perm, scope)` 组合系统 role_bindings + `project_members`
|
||||
- 替换 scattered `role-admin` 硬编码 → `HasSystemPermission(..., "system.admin")` 或保留 admin role_id 映射
|
||||
- `requireAdmin` / `requireProjectAccess` 改调用 Authorizer + AuthzService
|
||||
|
||||
### Task 4 — Auth API 扩展(`feat(api)`)
|
||||
|
||||
- `GET /api/v1/auth/me` 增加 `capabilities: string[]`
|
||||
- 会话列表/撤销(用户设置 Phase 1 最小版):`GET/DELETE /api/v1/auth/sessions`
|
||||
- Admin users/roles CRUD 对齐 DB(现有 handler 改接 PgStore)
|
||||
|
||||
### Task 5 — 项目成员 API(`feat(api)`)
|
||||
|
||||
- `GET/POST/PUT/DELETE /api/v1/projects/{id}/members`
|
||||
- 仅 owner/creator + `projects.members.manage` 可写
|
||||
- 与 `project_members` 表对齐;禁止把 author/reviewer/approver 写入成员 role
|
||||
|
||||
### Task 6 — 前端 capabilities(`feat(web)`)
|
||||
|
||||
- `authClient.me()` 缓存 capabilities
|
||||
- `engine/rbac.ts`:`hasPermission` 优先读 capabilities;localStorage roles 只读迁移提示
|
||||
- `AdminSettingsModal` / `UserProjectRightsModal` 成员编辑走 API
|
||||
- 移除 `loadRoles(DEFAULT_ROLES)` 作为权威初始化(保留 demo 数据只读展示直至导入完成)
|
||||
|
||||
### Task 7 — 测试与报告(`test` / `docs(test)`)
|
||||
|
||||
- `internal/auth/pg_store_test.go`(testcontainers 或 stub pg)
|
||||
- `internal/authz/service_test.go`
|
||||
- 扩展 `security_p0_test` + 跨项目 403(需 DB fixture)
|
||||
- `.doc/test-reports/2026-09-12-phase1-iam-authz-test-report.md`
|
||||
|
||||
---
|
||||
|
||||
## 建议提交节奏
|
||||
|
||||
1. `feat(db):` IAM goose migration + seed
|
||||
2. `feat(auth):` PostgresAuthStore + session persistence
|
||||
3. `feat(authz):` AuthorizationService + admin gate
|
||||
4. `feat(api):` members CRUD + auth/me capabilities
|
||||
5. `feat(web):` frontend capabilities consumer
|
||||
6. `test(docs):` Phase 1 report
|
||||
|
||||
---
|
||||
|
||||
## 风险
|
||||
|
||||
- **双写期**:MemoryStore 与 PG 并存时须单一 Store 注入,避免混用。
|
||||
- **ID 对齐**:现有 `projects.creator_user_id` / memory user id 与 PG users.id 迁移需一次性回填脚本。
|
||||
- **前端降级**:capabilities 未加载前 fail closed(禁用敏感按钮,不默认 allow)。
|
||||
@@ -0,0 +1,23 @@
|
||||
# Phase 2:工作流设计器与模板库 Implementation Plan
|
||||
|
||||
> **依据**:`.doc/2026-09-11-production-ready-workflow-governance-plan.md` §7、§15 Phase 2
|
||||
|
||||
**Goal:** 工作流定义版本化入库;模板 CAS 资产库;Admin 草稿/校验/发布/退役;静态 catalog bootstrap;运行时 DBCatalog。
|
||||
|
||||
**不在本阶段:** 项目激活冻结、instance 快照、阶段 ABAC(Phase 3)。
|
||||
|
||||
## 完成门禁
|
||||
|
||||
| 门禁 | 判定 |
|
||||
|---|---|
|
||||
| 已发布版本不可变 | Publish 后 UpdateDraft 拒绝 |
|
||||
| 非法工作流不能发布 | Validate 失败 → 422 |
|
||||
| 旧 catalog bootstrap | BootstrapSeeds 幂等写入 5 套 published v1 |
|
||||
| 运行时读 DB | NewCatalog 优先 DBCatalog |
|
||||
|
||||
## 已交付模块
|
||||
|
||||
- `deploy/postgres/goose/00016_2026-09-12-workflow-definitions-and-templates.sql`
|
||||
- `internal/workflowdef/` — store, service, validator, catalog, bootstrap
|
||||
- `internal/server/admin_workflow_handlers.go`, `admin_template_handlers.go`
|
||||
- `web/src/api/workflowAdmin.ts` + AdminSettingsModal workflows Tab
|
||||
@@ -0,0 +1,461 @@
|
||||
# 项目审计快速参考指南
|
||||
|
||||
**用途**: 开发/QA 快速定位问题、理解整改方向
|
||||
**格式**: 结构化索引,支持搜索和导航
|
||||
|
||||
---
|
||||
|
||||
## 一、关键数字一览
|
||||
|
||||
| 指标 | 数值 | 说明 |
|
||||
|---|---|---|
|
||||
| 项目完成度 | 70% | 架构完整,核心功能大部分实现,缺新功能和 bug 修复 |
|
||||
| 已确认缺陷 | 12 个 | 3 个 critical,4 个 high,5 个 medium |
|
||||
| 未完成功能 | 3 个 | 项目上下文快照、受控终止、E2E 测试 |
|
||||
| 整改工作量 | 61h | 单人 2.5 天,双人 5 天 |
|
||||
| 单元测试 | 120+ | 85% 覆盖主要包 |
|
||||
| E2E 测试 | 0% | **需补充** |
|
||||
| 数据污染 | 88 个定义 | 测试定义混入开发库 |
|
||||
|
||||
---
|
||||
|
||||
## 二、快速诊断矩阵
|
||||
|
||||
### 症状 → 原因 → 解决方案
|
||||
|
||||
```
|
||||
症状 1: 完成工作流后项目仍显示为"正在运行",无法配置下一个工作流
|
||||
├─ 原因: BUG-01 - AdvanceStage 完成最后阶段时未更新项目 lifecycle
|
||||
├─ 代码位置: internal/projectinstance/stage_store.go:128-158
|
||||
├─ 优先级: 🔴 P0 CRITICAL
|
||||
└─ 解决: Task A1(2h)
|
||||
└─ 同事务更新 projects.lifecycle_status = 'planning'
|
||||
|
||||
症状 2: 禁用的文档仍然可以在某些页面被启动/编辑
|
||||
├─ 原因: BUG-05 - 拒绝逻辑分散,不同入口检查不一致
|
||||
├─ 代码位置: stage_access.go, API, SSE, Agent tools 多处
|
||||
├─ 优先级: 🔴 P1 HIGH
|
||||
└─ 解决: Task A5(4h)
|
||||
└─ 实现 DocumentAccessDecider,统一所有入口
|
||||
|
||||
症状 3: 对话中说"推进工作流"有时不生效或使用旧流程
|
||||
├─ 原因: BUG-04 - Coordinator 调用旧 bizdevSvc.ExecuteStage
|
||||
├─ 代码位置: internal/coordinator/engine.go:672-811
|
||||
├─ 优先级: 🔴 P0 CRITICAL
|
||||
└─ 解决: Task A4(2h)
|
||||
└─ 改为调用 instSvc.AdvanceStage
|
||||
|
||||
症状 4: 阶段推进后发现文档被强制标记为"已批准",但用户未操作
|
||||
├─ 原因: BUG-02 - AdvanceStage SQL 中有强制更新批准状态的逻辑
|
||||
├─ 代码位置: internal/projectinstance/stage_store.go(需 grep 验证)
|
||||
├─ 优先级: 🔴 P0 CRITICAL
|
||||
└─ 解决: Task A2(1h)
|
||||
└─ 删除 UPDATE 批准状态的 SQL 行
|
||||
|
||||
症状 5: 测试在开发环境运行后,88 个奇怪的 pg_* 定义出现在工作流目录
|
||||
├─ 原因: BUG-08 - 集成测试未设置 TEST_DATABASE_URL,默认连接开发库
|
||||
├─ 代码位置: internal/projectinstance/pg_integration_test.go
|
||||
├─ 优先级: 🟠 P1 MEDIUM
|
||||
└─ 解决: Task BUG-08(2h)
|
||||
└─ 强制要求 TEST_DATABASE_URL;测试后清理
|
||||
|
||||
症状 6: 激活工作流时 token 可能在浏览器历史中看到,或被重复使用
|
||||
├─ 原因: BUG-06 - Token 明文保存,消费分事务,不是 one-time
|
||||
├─ 代码位置: internal/projectinstance/service.go(激活相关)
|
||||
├─ 优先级: 🟠 P1 HIGH
|
||||
└─ 解决: Task A6(3h)
|
||||
└─ Token → hash + one-time,同事务消费
|
||||
|
||||
症状 7: 产品经理流程不运行,测试工程师流程无法启动,提示"需先运行产品流程"
|
||||
├─ 原因: MISSING-06 - test_manager manifest 中仍有 upstream 依赖
|
||||
├─ 代码位置: internal/workflowdef/manifests/test_manager.v2.json
|
||||
├─ 优先级: 🟠 P1 HIGH
|
||||
└─ 解决: Task B3(需先删除测试流程的上游依赖)
|
||||
└─ 修改 manifest,删除 required_upstream_workflow
|
||||
|
||||
症状 8: 选择工作流时前端显示"商务流程",但服务返回的名称不一致
|
||||
├─ 原因: BUG-12 - 前端硬编码名称 vs 后端正式名称不同步
|
||||
├─ 代码位置: web/src/components/workflow/ProjectWorkflowSwitcher.tsx
|
||||
├─ 优先级: 🟢 P2 LOW
|
||||
└─ 解决: 由后端 GET /api/v1/workflows/catalog 驱动前端显示
|
||||
|
||||
症状 9: 无法手工删除已完成的工作流实例,项目永久处于"运行中"
|
||||
├─ 原因: MISSING-02 - 受控终止 API 未实现
|
||||
├─ 代码位置: (缺失)
|
||||
├─ 优先级: 🔴 P1 CRITICAL
|
||||
└─ 解决: Task B1(6h)
|
||||
└─ 实现 TerminateWorkflow API,二次确认 + 原因记录
|
||||
|
||||
症状 10: 产品经理和测试工程师输出中缺少"来源追溯",无法知道数据从哪来
|
||||
├─ 原因: MISSING-01 - 项目上下文快照服务未实现
|
||||
├─ 代码位置: (缺失)
|
||||
├─ 优先级: 🔴 P1 CRITICAL
|
||||
└─ 解决: Task B3(12h)
|
||||
└─ 实现 ProjectContextSnapshot 服务,包含血缘表
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、代码热点地图
|
||||
|
||||
### 高风险区域(需特别关注的文件)
|
||||
|
||||
```
|
||||
🔴 CRITICAL
|
||||
├─ internal/projectinstance/stage_store.go
|
||||
│ ├─ BUG-01: AdvanceStage 不更新项目生命周期
|
||||
│ ├─ BUG-02: 推进强制批准文档(需验证)
|
||||
│ └─ 位置: 第 71-158 行
|
||||
│
|
||||
├─ internal/coordinator/engine.go
|
||||
│ ├─ BUG-04: 对话推进调用旧服务
|
||||
│ └─ 位置: 第 672-811 行(handleAdvanceStage)
|
||||
│
|
||||
├─ internal/projectinstance/service.go
|
||||
│ ├─ BUG-01: 完成后生命周期(同上)
|
||||
│ └─ 位置: 第 119-135 行(SaveWorkflowPlan)
|
||||
|
||||
🟠 HIGH
|
||||
├─ internal/projectinstance/stage_access.go
|
||||
│ ├─ BUG-05: 禁用文档拒绝逻辑不一致
|
||||
│ └─ 位置: 第 15-71, 90-104 行
|
||||
│
|
||||
├─ web/src/components/workflow/ProjectWorkflowSwitcher.tsx
|
||||
│ ├─ BUG-09: 版本冲突自动重试
|
||||
│ ├─ BUG-12: 硬编码名称
|
||||
│ └─ 位置: 第 16-23, 38-76, 173-236 行
|
||||
|
||||
🟡 MEDIUM
|
||||
├─ internal/projectinstance/pg_integration_test.go
|
||||
│ ├─ BUG-08: 未设置 TEST_DATABASE_URL
|
||||
│ └─ 位置: 第 19-49 行
|
||||
│
|
||||
├─ internal/workflowdef/manifests/test_manager.v2.json
|
||||
│ ├─ 依然有 upstream 依赖(需删除)
|
||||
│ └─ 位置: 第 1-23 行
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、整改优先级排序
|
||||
|
||||
### 必须在本周内完成(优先级递减)
|
||||
|
||||
```
|
||||
□ P0-1: BUG-01 项目完成后生命周期 (2h)
|
||||
→ 项目永久锁死的根本原因
|
||||
|
||||
□ P0-2: BUG-04 对话推进新服务切换 (2h)
|
||||
→ 权限检查绕过
|
||||
|
||||
□ P0-3: BUG-02 推进不强制批准 (1h)
|
||||
→ 数据违反业务规则
|
||||
|
||||
□ P1-1: BUG-05 禁用文档一致性 (4h)
|
||||
→ 安全隐患
|
||||
|
||||
□ P1-2: BUG-06 激活 token 安全 (3h)
|
||||
→ 存在泄露/重放风险
|
||||
|
||||
□ P1-3: Task B1 受控终止 API (6h)
|
||||
→ 恢复能力必需
|
||||
|
||||
□ P1-4: Task B2 E2E 测试 (8h)
|
||||
→ 验收标准要求
|
||||
|
||||
可以延后(下周处理)
|
||||
|
||||
□ P2-1: BUG-03 禁用文档 skipped_disabled (3h)
|
||||
□ P2-2: BUG-08 测试隔离完善 (2h)
|
||||
□ P2-3: BUG-10 项目设置审计视图 (3h)
|
||||
□ P2-4: BUG-09 前端冲突自动重试 (1h)
|
||||
□ P2-5: BUG-11 旧 API 下线 (1h)
|
||||
□ P2-6: BUG-12 前端名称一致性 (1h)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、代码修改检查清单
|
||||
|
||||
### 提交前验收标准
|
||||
|
||||
**修复 BUG-01 时**:
|
||||
```
|
||||
[ ] 修改 stage_store.go 的 AdvanceStage 函数
|
||||
- 检查是否最后阶段
|
||||
- 若是,同事务更新 projects.lifecycle_status
|
||||
- 清空 current_workflow_instance_id
|
||||
- 写审计事件
|
||||
[ ] 新增测试: TestAdvanceStage_CompletesProjectAfterLastStage
|
||||
[ ] 新增测试: TestAdvanceStage_DoesNotChangeProjectOnNonLastStage
|
||||
[ ] 本地测试通过 (go test ./internal/projectinstance -v)
|
||||
[ ] 前端检查:/projects/{id}/settings 显示"配置下一工作流"
|
||||
```
|
||||
|
||||
**修复 BUG-04 时**:
|
||||
```
|
||||
[ ] 修改 coordinator/engine.go 的 handleAdvanceStage
|
||||
- 提取 workflow_instance_id
|
||||
- 改调 instSvc.AdvanceStage 替代 bizdevSvc.ExecuteStage
|
||||
- 调整返回格式
|
||||
[ ] 新增测试: TestDialogueAdvanceStage_UsesNewService
|
||||
[ ] 新增测试: TestDialogueAdvanceStage_PermissionCheck
|
||||
[ ] 本地测试通过 (go test ./internal/coordinator -v)
|
||||
[ ] 对话测试通过 (go test ./internal/server -run Dialogue -v)
|
||||
```
|
||||
|
||||
**创建 Task B2 E2E 框架时**:
|
||||
```
|
||||
[ ] 确保 TEST_DATABASE_URL 已设置
|
||||
[ ] 创建 setupE2ETestDB() 函数
|
||||
- 创建隔离 schema
|
||||
- 运行所有迁移
|
||||
- 清理逻辑
|
||||
[ ] 编写 TestE2E_BizdevWorkflow_Complete
|
||||
- 7 文档完整流程
|
||||
- 每个阶段验证门禁
|
||||
- 完成后验证项目状态
|
||||
[ ] 编写 TestE2E_ProductManagerWorkflow_Standalone
|
||||
- 无前置依赖
|
||||
- 独立运行成功
|
||||
[ ] 编写 TestE2E_TestEngineerWorkflow_WithoutSRS
|
||||
- 无 SRS 输入仍能运行
|
||||
- 输出包含来源清单
|
||||
[ ] 全部 E2E 测试通过
|
||||
[ ] 验收标准 7.5 完全满足
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、数据库迁移清单
|
||||
|
||||
### 需要新增的迁移脚本
|
||||
|
||||
```
|
||||
00025_2026-09-12-disabled-doc-status.sql
|
||||
├─ 添加 project_doc_task_instances.status_reason
|
||||
├─ 添加约束:disabled 时 duties 为空
|
||||
└─ 编写回滚脚本
|
||||
|
||||
00026_2026-09-12-workflow-termination.sql
|
||||
├─ 添加 project_workflow_instances.terminated_at/by/reason
|
||||
├─ 添加 termination_reason 列
|
||||
└─ 编写回滚脚本
|
||||
|
||||
00027_2026-09-12-context-snapshots.sql
|
||||
├─ 创建 project_context_snapshots 表
|
||||
├─ 创建 project_context_snapshot_sources 表
|
||||
└─ 编写回滚脚本
|
||||
|
||||
00028_2026-09-12-activation-challenges.sql
|
||||
├─ 创建 activation_challenges 表
|
||||
├─ 创建 one_time_tokens 表
|
||||
└─ 编写回滚脚本
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、测试命令参考
|
||||
|
||||
```bash
|
||||
# 运行所有项目实例测试
|
||||
go test ./internal/projectinstance -v
|
||||
|
||||
# 运行所有协调器测试
|
||||
go test ./internal/coordinator -v
|
||||
|
||||
# 运行所有工作流定义测试
|
||||
go test ./internal/workflowdef -v
|
||||
|
||||
# 运行服务器集成测试
|
||||
go test ./internal/server -v
|
||||
|
||||
# 运行特定 bug 的测试
|
||||
go test ./internal/projectinstance -run "TestAdvanceStage" -v
|
||||
|
||||
# 运行 PG 集成测试(需 TEST_DATABASE_URL)
|
||||
TEST_DATABASE_URL=postgresql://... go test ./internal/server -run PG -v
|
||||
|
||||
# 运行 E2E 测试
|
||||
TEST_DATABASE_URL=postgresql://... go test ./internal/server -run E2E -v
|
||||
|
||||
# 代码覆盖率分析
|
||||
go test ./internal/projectinstance ./internal/coordinator ./internal/workflowdef \
|
||||
-coverprofile=coverage.out && go tool cover -html=coverage.out
|
||||
|
||||
# 静态检查
|
||||
go vet ./internal/...
|
||||
golangci-lint run ./internal/...
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、API 快速参考
|
||||
|
||||
### 关键端点变动汇总
|
||||
|
||||
```
|
||||
现有(需保留或改进):
|
||||
GET /api/v1/workflows/catalog
|
||||
→ 返回三项正式工作流 ✅
|
||||
|
||||
GET /api/v1/projects/{id}/settings
|
||||
→ 返回项目设置及 live instance 配置 ✅
|
||||
|
||||
PUT /api/v1/projects/{id}/workflow-plan
|
||||
→ 保存/修改规划 (planning 状态下) ✅
|
||||
|
||||
POST /api/v1/projects/{id}/workflow-instances/activate
|
||||
→ 激活工作流 (需修复 token) ⚠️
|
||||
|
||||
GET /api/v1/workflow-instances/{id}/stages/{stage}/readiness
|
||||
→ 阶段门禁详情 ✅
|
||||
|
||||
POST /api/v1/workflow-instances/{id}/stages/{stage}/advance
|
||||
→ 推进阶段 (需修复生命周期) ❌
|
||||
|
||||
待实现(高优先级):
|
||||
POST /api/v1/workflow-instances/{id}/termination-preview
|
||||
→ 终止预览(Task B1)
|
||||
|
||||
POST /api/v1/workflow-instances/{id}/terminate
|
||||
→ 执行终止(Task B1)
|
||||
|
||||
待删除或返回 410:
|
||||
POST /projects/{id}/active-workflow
|
||||
→ 旧切换 API(需下线)
|
||||
|
||||
需改进(权限一致性):
|
||||
POST /api/v1/doc-task-instances/{id}/runs
|
||||
→ 启动编制 (需 DocumentAccessDecider) ⚠️
|
||||
|
||||
POST /api/v1/documents/{id}/submit
|
||||
→ 提交审核 (需统一权限检查) ⚠️
|
||||
|
||||
POST /api/v1/documents/{id}/approve
|
||||
→ 批准 (需统一权限检查) ⚠️
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、常见问题速查
|
||||
|
||||
### Q1: 为什么完成工作流后项目仍然处于"active"?
|
||||
**A**: BUG-01 - `AdvanceStage` 完成最后阶段时未同事务更新项目 `lifecycle_status`。
|
||||
**修复**: Task A1(2h)
|
||||
**临时绕过**: 手动执行 SQL `UPDATE projects SET lifecycle_status='planning' WHERE id=?`
|
||||
|
||||
### Q2: 禁用的文档仍然能被某些用户操作?
|
||||
**A**: BUG-05 - 不同入口对禁用文档的检查不一致。
|
||||
**修复**: Task A5(4h) - 实现 `DocumentAccessDecider`
|
||||
**临时绕过**: 在关键入口前添加 `if doc.status == 'skipped_disabled' { return 409 }`
|
||||
|
||||
### Q3: 激活 token 可能被重复使用?
|
||||
**A**: BUG-06 - Token 明文保存,消费分事务。
|
||||
**修复**: Task A6(3h)
|
||||
**临时保护**: 限制 token 有效期为 5 分钟;记录消费日志;审计异常 token 使用
|
||||
|
||||
### Q4: 对话推进工作流不起作用?
|
||||
**A**: BUG-04 - Coordinator 调用旧商务服务而非实例服务。
|
||||
**修复**: Task A4(2h)
|
||||
**临时检查**: 查看 `internal/coordinator/engine.go:672-811` 是否仍调用 `bizdevSvc`
|
||||
|
||||
### Q5: 为什么 E2E 测试一直 fail?
|
||||
**A**: 可能多个原因:
|
||||
1. TEST_DATABASE_URL 未设置 → 连接开发库(88 个污染定义)
|
||||
2. E2E 框架缺失 → 需实现 setupE2ETestDB()
|
||||
3. 实例生命周期 bug → BUG-01 导致测试逻辑不对
|
||||
|
||||
**修复**: 检查 TEST_DATABASE_URL;运行 Task B2
|
||||
|
||||
### Q6: 生产数据库中有 47 个"已完成但项目仍为 active"的不一致数据?
|
||||
**A**: BUG-01 导致。数据本身可恢复。
|
||||
**恢复方案**:
|
||||
1. 查询 `SELECT * FROM project_workflow_instances WHERE status='completed'`
|
||||
2. 对每个 completed 实例:
|
||||
```sql
|
||||
UPDATE projects SET lifecycle_status='planning', current_workflow_instance_id=NULL
|
||||
WHERE id=(SELECT project_id FROM project_workflow_instances WHERE id=?)
|
||||
```
|
||||
3. 补写审计日志
|
||||
|
||||
---
|
||||
|
||||
## 十、参考文档导航
|
||||
|
||||
| 文档 | 用途 | 适合人员 |
|
||||
|---|---|---|
|
||||
| [remediation-gap-matrix.md](./2026-09-12-remediation-gap-matrix.md) | **当前缺口 SSOT** | 全体 |
|
||||
| [ops/CURRENT.md](./ops/CURRENT.md) | 协作焦点 | Agent / 开发 |
|
||||
| [comprehensive-audit-and-remediation-plan.md](./2026-09-12-comprehensive-audit-and-remediation-plan.md) | 详细缺陷分析与整改方案(历史) | 架构师、资深开发 |
|
||||
| [remediation-tasks-and-acceptance-checklist.md](./2026-09-12-remediation-tasks-and-acceptance-checklist.md) | 可执行的任务拆分与验收 | 开发、QA |
|
||||
| [audit-summary-report.md](./2026-09-12-audit-summary-report.md) | 审计总结与建议(历史) | 项目经理、技术负责人 |
|
||||
| **[本文件]** | 快速参考与索引 | 全体团队 |
|
||||
| [three-workflows-strict-governance-remediation.md](./2026-09-12-three-workflows-strict-governance-remediation.md) | 业务需求原始规划 | 产品、架构 |
|
||||
|
||||
---
|
||||
|
||||
## 十一、快速评分表
|
||||
|
||||
### 修复每个 bug 后的自检清单
|
||||
|
||||
```
|
||||
BUG-01 ✓ 完成
|
||||
□ stage_store.go 修改
|
||||
□ 新增单元测试 ×2
|
||||
□ 本地 go test PASS
|
||||
□ 前端验证项目状态改变
|
||||
→ 接受标准: 完成最后阶段后项目 lifecycle='planning'
|
||||
|
||||
BUG-02 ✓ 完成
|
||||
□ grep 确认强制批准逻辑存在
|
||||
□ 删除 UPDATE 批准状态的 SQL
|
||||
□ 新增单元测试
|
||||
□ 本地 go test PASS
|
||||
→ 接受标准: 推进前后文档状态不变
|
||||
|
||||
BUG-04 ✓ 完成
|
||||
□ engine.go handleAdvanceStage 改为调用新服务
|
||||
□ 新增单元测试
|
||||
□ 本地 go test PASS
|
||||
□ 对话测试 PASS
|
||||
→ 接受标准: 对话推进使用 instSvc
|
||||
|
||||
BUG-05 ✓ 完成
|
||||
□ 实现 DocumentAccessDecider 接口
|
||||
□ 集成到 API、SSE、异步任务、Agent tools
|
||||
□ 新增综合测试
|
||||
□ 本地 go test PASS
|
||||
→ 接受标准: 禁用文档全拒绝,返回 409/403
|
||||
|
||||
BUG-06 ✓ 完成
|
||||
□ 数据库迁移 00028
|
||||
□ API 改为 challenge_id + one_time_token
|
||||
□ Token hash + 原子消费
|
||||
□ 新增安全测试 ×4
|
||||
□ 本地 go test PASS
|
||||
→ 接受标准: Token one-time、hash 存储、5 分钟过期
|
||||
|
||||
Task B1 ✓ 完成
|
||||
□ 新增 terminate.go 服务
|
||||
□ TerminationPreview API
|
||||
□ TerminateWorkflow API
|
||||
□ 新增端到端测试
|
||||
□ 本地 go test PASS
|
||||
→ 接受标准: 终止后项目可配置下一流程
|
||||
|
||||
Task B2 ✓ 完成
|
||||
□ setupE2ETestDB() 实现
|
||||
□ TestE2E_BizdevWorkflow_Complete PASS
|
||||
□ TestE2E_ProductManagerWorkflow_Standalone PASS
|
||||
□ TestE2E_TestEngineerWorkflow_WithoutSRS PASS
|
||||
□ TEST_DATABASE_URL 隔离库运行
|
||||
→ 接受标准: 三工作流完整链路验证
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**文档版本**: v1.0 快速参考
|
||||
**适用对象**: 项目全体
|
||||
**更新频率**: 同步更新主审计文档
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,525 @@
|
||||
# 三工作流严格治理与现有系统融合整改方案
|
||||
|
||||
- 日期:2026-09-12
|
||||
- 状态:核心业务决策已确认 / 可进入实施拆分
|
||||
- 范围:工作流定义、项目实例、阶段门禁、文档三权、通知与对话推进、运行时授权、数据迁移和验收
|
||||
- 本文性质:当前代码与开发数据库的只读核验结论及整改设计;本轮未修改业务代码
|
||||
|
||||
## 1. 结论先行
|
||||
|
||||
系统面向项目创建者和项目成员时,只应存在以下 **3 个可选择工作流**:
|
||||
|
||||
1. **商务对接流程**:7 个文档,3 个阶段;
|
||||
2. **智能产品经理流程**:1 个输出文档,1 个阶段;
|
||||
3. **智能测试工程师流程**:1 个输出文档,1 个阶段。
|
||||
|
||||
商务对接流程的文档数量可以定案为 **7 个,不是 6 个**。前端模板工厂和测试固定断言了 7 个任务键,后端标准任务目录也包含同一组 7 个商务文档,历史专项测试报告同样把它们定义为标准全生命周期交付物。[^biz-seven-test][^biz-seven-backend][^biz-seven-report]
|
||||
|
||||
当前系统尚未满足这一目标,且不是简单改几个显示名称即可解决:
|
||||
|
||||
- 启动代码实际发布 5 个默认工作流,除目标三项外还包含“医疗器械研发”和“非医疗纯软件”;[^bootstrap-five]
|
||||
- 当前开发库已有 92 个工作流定义,其中大量为测试定义;三个目标工作流仍都是单阶段的 schema v1;
|
||||
- 仓库虽然有三个 schema v2 清单,但商务清单只有 5 个文档,漏了 `feasibility_dev` 和 `user_requirements`;[^main-v2-missing]
|
||||
- 三个 v2 清单仅被嵌入和登记,没有进入启动发布链;已有发布版又会让 seed 逻辑直接退出,因此现有库不会自动升级;[^manifest-loader][^seed-no-upgrade]
|
||||
- 旧运行入口会把多阶段版本压成“第一个阶段的第一个任务”,与项目实例运行时并存,形成双轨权威;[^catalog-flatten]
|
||||
- 配置页面允许勾选关闭文档,但后端校验禁止关闭所有 `required/blocking` 文档;当前清单又把所有文档都标成这两类,因此界面能力实际上不可用;[^plan-disable-conflict]
|
||||
- 智能测试工程师当前被 manifest、执行服务和前端提示硬绑定到产品经理/SRS,与已确认的两个智能工作流独立运行原则冲突;[^test-upstream][^test-hard-dependency]
|
||||
- 阶段推进虽然先检查批准状态,但事务内会把所有启用任务强制写成 `approved`,并且最后阶段完成后没有把项目恢复到可选择下一工作流的状态;[^advance-forces-approved][^project-lifecycle-gap]
|
||||
- 对话中的“推进阶段”仍调用旧商务成熟度执行器,并没有调用项目工作流实例的阶段推进服务;[^dialogue-old-advance]
|
||||
|
||||
因此本次整改的核心是:**以已激活项目工作流实例的冻结快照作为唯一运行时权威**。工作流目录、项目配置、文档三权、任务启动、审批、阶段门禁、通知和对话都必须围绕同一个实例标识运行,旧的直接切换和扁平执行入口退出生产路径。
|
||||
|
||||
## 2. 已确认的业务基线
|
||||
|
||||
### 2.1 唯一允许对项目展示和选择的工作流
|
||||
|
||||
| 稳定内部 key | 对外名称 | 阶段数 | 输出文档数 | 说明 |
|
||||
|---|---|---:|---:|---|
|
||||
| `main` | 商务对接流程 | 3 | 7 | 保留现有 key 以避免破坏历史数据,只改正式名称 |
|
||||
| `product_manager` | 智能产品经理流程 | 1 | 1 | 输出《系统需求规格书》 |
|
||||
| `test_manager` | 智能测试工程师流程 | 1 | 1 | 保留现有 key,只把“测试经理”统一更名为“测试工程师” |
|
||||
|
||||
“系统只需要三个流程”的含义应同时落实到三个层面:
|
||||
|
||||
- 项目设置 API 只返回这 3 个可选项;
|
||||
- 前端任何入口只展示这 3 个可选项;
|
||||
- 服务端只允许为这 3 个正式、已发布版本创建项目工作流实例。
|
||||
|
||||
后台可以保留历史定义和草稿以满足审计,但必须标记为 `retired` 或 `project_selectable=false`,不能继续出现在项目目录中。不能仅靠前端白名单隐藏,因为当前设置服务会枚举数据库里全部有发布版本的定义。[^settings-all-definitions]
|
||||
|
||||
### 2.2 商务对接流程:7 个文档,3 个阶段
|
||||
|
||||
沿用系统已经形成的 V0.1 / V0.5 / V1.0 业务阶段和模板归属,目标定义如下。当前模板工厂已按 `1 + 5 + 1` 归档这 7 个文档。[^template-stage-map]
|
||||
|
||||
| 阶段 | 顺序 | task key | 正式文档名 | 默认状态 | 阶段门禁 |
|
||||
|---|---:|---|---|---|---|
|
||||
| V0.1 需求摸底 | 10 | `intake` | 用户初始需求收集表 | 启用 | 启用时必须批准 |
|
||||
| V0.5 方案与可行性 | 20 | `research` | 调研报告 | 启用 | 启用时必须批准 |
|
||||
| V0.5 方案与可行性 | 21 | `feasibility_dev` | 设计开发可行性评估报告 | 启用 | 启用时必须批准 |
|
||||
| V0.5 方案与可行性 | 22 | `feasibility_reg` | 注册路径可行性评估报告 | 启用 | 启用时必须批准 |
|
||||
| V0.5 方案与可行性 | 23 | `user_requirements` | 用户需求表 | 启用 | 启用时必须批准 |
|
||||
| V0.5 方案与可行性 | 24 | `prelim_design` | 系统初步设计方案 | 启用 | 启用时必须批准 |
|
||||
| V1.0 商务报价 | 30 | `cdo_quote` | CDO 报价单 | 启用 | 启用时必须批准 |
|
||||
|
||||
当前后端商务阶段只执行 `intake`、`research`、`feasibility_reg`、`prelim_design`、`cdo_quote` 五项,正好缺少另外两项,必须同步补齐阶段执行映射和 executor 注册。[^biz-stage-five][^executor-missing]
|
||||
|
||||
### 2.3 智能产品经理流程
|
||||
|
||||
| 阶段 | task key | 唯一输出文档 | 默认状态 | 门禁 |
|
||||
|---|---|---|---|---|
|
||||
| 系统需求基线 | `system_reqs` | 系统需求规格书 | 启用 | 文档批准后,创建者确认完成工作流 |
|
||||
|
||||
### 2.4 智能测试工程师流程
|
||||
|
||||
| 阶段 | task key | 唯一输出文档 | 默认状态 | 门禁 |
|
||||
|---|---|---|---|---|
|
||||
| 系统验证策划 | `test_manager` | 系统验证方案及计划 | 启用 | 文档批准后,创建者确认完成工作流 |
|
||||
|
||||
**智能产品经理流程和智能测试工程师流程相互解耦。** 智能测试工程师流程不再要求项目曾运行智能产品经理流程,也不再要求必须存在该流程输出的《系统需求规格书》。它直接从当前项目可用于工作流的对话、文档、上传材料、项目事实和决策记录中提取需求及验证依据,独立生成《系统验证方案及计划》。
|
||||
|
||||
如果项目中恰好存在已批准的《系统需求规格书》,它只是项目输入集合中的一项高权威来源,不是启动前置条件,也不产生流程级耦合。当前 manifest、执行服务、血缘逻辑和前端提示仍硬编码了这一依赖,整改时必须一起删除。[^test-upstream][^test-hard-dependency]
|
||||
|
||||
### 2.5 两个智能工作流的统一项目上下文输入
|
||||
|
||||
智能产品经理和智能测试工程师使用同一个“项目上下文快照服务”,但采用不同的分析目标和输出模板:
|
||||
|
||||
| 输入类别 | 纳入内容 | 建议权威等级 |
|
||||
|---|---|---|
|
||||
| 项目事实 | 项目名称、客户、产品类型、预期用途、目标市场、结构化事实黑板 | 已确认事实 |
|
||||
| 项目决策 | 创建者确认事项、里程碑决策、已关闭的待确认项 | 已确认决策 |
|
||||
| 项目文档 | 当前有效版本的受控文档、项目共享文档、上传材料 | 按批准状态和来源分级 |
|
||||
| 项目对话 | 所有已进入项目共享知识边界的成员对话及其附件 | 原始沟通证据 |
|
||||
| 历史输出 | 商务、产品、测试或自由任务形成的项目交付物 | 按状态和版本分级 |
|
||||
| 知识依据 | 系统检索到的法规、标准和内部知识库命中 | 外部参考依据 |
|
||||
|
||||
这里的“所有”是指 **当前项目知识边界内全部有资格被工作流使用的内容**,不是把数据库中所有原文无差别拼接到一次模型调用中。建议遵循以下规则:
|
||||
|
||||
1. 只纳入当前项目,绝不跨项目召回;
|
||||
2. 私人草稿、个人私聊只有在明确“共享到项目”后才进入项目级工作流输入,避免流程执行扩大原有可见范围;
|
||||
3. 任务启动时生成不可变 `project_context_snapshot`,记录截止时间、来源 ID、版本、内容 hash、权限判定和引用位置;
|
||||
4. 全量来源先建立清单,再按任务目标检索相关片段;已确认事实和已批准文档必须进入固定核心上下文,普通对话按相关性分批读取;
|
||||
5. 冲突时不静默覆盖,优先级建议为:创建者确认事实/决策 > 当前已批准文档 > 用户上传原始材料 > 里程碑记录 > 普通项目对话 > 智能体历史总结;
|
||||
6. 输出必须带 source manifest。智能测试工程师需在唯一输出文档内部生成“需求/风险—测试项—来源”追溯表,不额外创建第二个受控输出文档;
|
||||
7. 任务运行后项目来源发生变化时,依据被引用来源的 hash 判断 `input_changed/stale`,而不是只监听《系统需求规格书》。未被本次输出引用的无关对话变化不应把文档误标为 stale。
|
||||
|
||||
现有 Squad 工作区已经支持 project context、materials、prior docs、knowledge hits 等输入槽位,也会建立带权威等级的 context 索引;产品经理还已有从项目事实和里程碑生成输入材料的局部实现。因此应把这些能力上移为通用项目上下文快照服务,而不是为测试流程继续维护单一 SRS 特例。[^context-input-foundation]
|
||||
|
||||
## 3. 不可违反的业务规则
|
||||
|
||||
### 3.1 选择、启动和切换
|
||||
|
||||
1. 只有项目创建者可以选择、配置、激活、推进或受控终止项目工作流。
|
||||
2. 一个项目同一时刻最多只能有一个 live 实例。
|
||||
3. 在 `active`、`awaiting_stage_confirmation` 或 `termination_requested` 状态下,不允许选择或切换工作流。
|
||||
4. “切换工作流”不是修改当前实例的 `workflow_key`,而是当前实例 `completed` 或 `terminated` 后创建一个新的 planning 实例。
|
||||
5. 激活时冻结工作流版本、阶段、文档开关、模板版本、执行器、质量门禁和三权责任人。运行中不可静默修改。
|
||||
6. 管理员不因系统身份自动替代项目创建者执行推进;如以后引入 break-glass,必须单独设计理由、再认证和审计,且不能代替文档签署人。
|
||||
|
||||
目标状态机:
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> planning: 创建者选择并配置
|
||||
planning --> active: 预览后确认激活
|
||||
active --> awaiting_stage_confirmation: 当前阶段所有启用文档已批准
|
||||
awaiting_stage_confirmation --> active: 创建者确认进入下一阶段
|
||||
awaiting_stage_confirmation --> completed: 创建者确认完成最后阶段
|
||||
active --> termination_requested: 创建者申请终止
|
||||
termination_requested --> terminated: 二次确认并记录原因
|
||||
completed --> planning: 创建下一工作流实例
|
||||
terminated --> planning: 创建下一工作流实例
|
||||
```
|
||||
|
||||
数据库已经为一个 planning 实例和一个 live 实例设置了部分唯一索引,也预留了 `awaiting_stage_confirmation`、`terminated` 等状态,适合沿此模型完善,不必另造一套表。[^instance-schema]
|
||||
|
||||
### 3.2 文档启用与禁用
|
||||
|
||||
项目创建者可以在 planning 状态逐文档启用或禁用。严格语义如下:
|
||||
|
||||
| 文档状态 | 三权配置 | 可创建/启动编制 | 可提交审核 | 可审核 | 可批准 | 是否计入阶段门禁 |
|
||||
|---|---|---:|---:|---:|---:|---:|
|
||||
| enabled | 作者、审核人、批准人均必填且互斥 | 是,仅作者或明确执行人 | 是,仅作者 | 是,仅审核人 | 是,仅批准人 | 是 |
|
||||
| disabled | 必须为空 | 否 | 否 | 否 | 否 | 否 |
|
||||
|
||||
关键约束:
|
||||
|
||||
- `default_enabled` 只表示默认值,不表示不可关闭;
|
||||
- `blocking_when_enabled=true` 表示文档一旦启用,未批准就阻断阶段;
|
||||
- 新增明确字段 `creator_configurable=true/false`,不要继续混用现有 `required`、`blocking`、`default_enabled` 三个布尔值表达四种含义;
|
||||
- 禁用后实例状态写为 `skipped_disabled`,不创建 DocGov 文档、不生成三权行,也不允许通过 task key、对话、SSE、Agent tool 或旧 API 旁路启动;
|
||||
- 对禁用文档发起动作时统一返回 `409 DOC_TASK_DISABLED`;对启用文档但责任人不匹配返回 `403 DOC_DUTY_FORBIDDEN`;
|
||||
- 激活计划必须至少包含一个启用文档。这样一文档流程仍可在配置时关闭唯一文档,但关闭后不能激活一个没有产出的空工作流。
|
||||
|
||||
现有数据结构已经能表达 `enabled` 和三权,且持久化时会跳过禁用文档的职责写入;可复用这部分。问题在于定义校验把 required/blocking 文档一律视为不可关闭,需要先修正语义。[^plan-structure][^duty-write-enabled-only]
|
||||
|
||||
### 3.3 阶段完成和推进
|
||||
|
||||
阶段就绪的唯一业务判定应为:
|
||||
|
||||
```text
|
||||
stage_ready = 当前阶段处于 active
|
||||
AND 当前阶段至少有一个 enabled 文档
|
||||
AND 每个 enabled 文档的当前受控版本都为 approved
|
||||
AND 没有正在执行、待审核、待批准或 stale 的同任务实例
|
||||
```
|
||||
|
||||
推进动作必须满足:
|
||||
|
||||
- 服务端在同一数据库事务中锁定 workflow instance 和 stage instance;
|
||||
- 重新计算门禁,不能只信几秒前的 readiness 响应;
|
||||
- 校验操作者仍是项目创建者;
|
||||
- 校验 `expected_config_revision` 和幂等键;
|
||||
- 只改变阶段和实例状态,绝不把文档“补写”为 approved;
|
||||
- 进入下一启用阶段;若没有下一阶段,则把实例标为 completed,并把项目切回“可配置下一个工作流”的状态;
|
||||
- 同事务关闭对应 `stage_advance_request`,写审计和 outbox 事件。
|
||||
|
||||
当前 readiness 已经忽略禁用任务、检查启用必需文档是否批准,并限制创建者推进,这一骨架可以保留;但它按 `project_id + task_key` 汇总文档状态,仍需升级到 `doc_task_instance_id + document_version_id`,避免跨阶段或重复实例串线。[^readiness-current][^approval-key-too-wide]
|
||||
|
||||
### 3.4 主动提醒和对话推进
|
||||
|
||||
系统在 readiness 从 false 变为 true 时生成一次 `stage.ready_to_advance` 事件,并只通知项目创建者。已有 outbox、站内通知、去重键以及 24 小时再次提醒机制可以复用。[^notify-ready][^notify-reminder]
|
||||
|
||||
建议闭环:
|
||||
|
||||
1. 最后一份启用文档批准;
|
||||
2. 事务后事件处理器重新计算 readiness;
|
||||
3. 实例进入 `awaiting_stage_confirmation`;
|
||||
4. 创建者收到站内消息和可操作确认卡:阶段名、启用/已批准文档清单、下一阶段或“完成工作流”;
|
||||
5. 创建者点击按钮,或在项目对话中说“推进到下一阶段 / 确认推进”;
|
||||
6. 两种入口都调用同一个 `AdvanceStage` 应用服务;
|
||||
7. 成功后通知状态改为 acted,推进请求改为 confirmed;若条件在确认前失效,则返回最新阻断项并把旧请求标为 superseded。
|
||||
|
||||
当前前端已经每 15 秒拉取通知并显示“确认推进”按钮,但对话入口仍走旧的 `bizdev.ExecuteStage`,所以需要把自然语言意图解析与执行彻底分开:识别器只产生命令,实例服务才拥有推进权。[^stage-banner][^dialogue-old-advance]
|
||||
|
||||
## 4. 当前系统与目标的差距
|
||||
|
||||
### 4.1 定义和目录
|
||||
|
||||
| 编号 | 当前事实 | 风险 | 整改 |
|
||||
|---|---|---|---|
|
||||
| WF-CAT-01 | Bootstrap 发布 5 个工作流 | 项目会看到目标外流程 | 只发布三项;其余退役且不可选 |
|
||||
| WF-CAT-02 | 设置服务返回所有有发布版的定义 | 测试/历史流程进入项目 | 增加 `project_selectable`,查询端白名单 + 状态双重校验 |
|
||||
| WF-CAT-03 | 开发库有 92 个定义,88 个 key 为 `pg_*` 或 `test_*` | 测试污染业务目录 | 测试强制独立数据库/schema,fixture 必须清理 |
|
||||
| WF-DEF-01 | 三个正式 key 当前均为 schema v1 单阶段 | 实际运行不是目标结构 | 以新版本发布 schema v2/v3,禁止覆盖旧版本 |
|
||||
| WF-DEF-02 | `main.v2.json` 只有 5 个文档 | 商务流程缺 2 个输出 | 补齐 7 个并增加 executor、模板和质量门禁校验 |
|
||||
| WF-DEF-03 | v2 manifest 未进入 bootstrap | 仓库文件与运行数据库不一致 | 建立 manifest 迁移器,按 hash 创建并发布新版本 |
|
||||
| WF-DEF-04 | seed 发现任何 published 就跳过 | 永远停留旧版本 | 按内容 hash 和目标版本升级,写版本迁移审计 |
|
||||
| WF-DEF-05 | DBCatalog 压扁完整定义 | 多阶段配置不能驱动运行 | 删除生产 flatten 路径,运行只读取冻结实例 |
|
||||
| WF-DEF-06 | 测试流程声明 product_manager 上游,执行服务又硬查 approved SRS | 两个智能工作流不能独立运行 | 删除流程级依赖;改用统一项目上下文快照和多来源血缘 |
|
||||
|
||||
### 4.2 项目实例和生命周期
|
||||
|
||||
| 编号 | 当前事实 | 风险 | 整改 |
|
||||
|---|---|---|---|
|
||||
| WF-INS-01 | planning / active 和唯一 live 骨架已存在 | 可复用但未闭环 | 扩展 awaiting/completed/terminated 完整转换 |
|
||||
| WF-INS-02 | 完成最后阶段只更新实例 | 项目仍为 active,无法配置下一流程 | 同事务更新项目可选择状态并清空 current live 指针 |
|
||||
| WF-INS-03 | 无受控终止 API | 异常流程永久锁死或只能改库 | 增加申请、影响预览、创建者二次确认和终止原因 |
|
||||
| WF-INS-04 | 激活 token 明文保存,消费与激活分事务 | 失败后 token 已失效或可泄露 | 只存 hash,并在激活事务内锁定、消费 |
|
||||
| WF-INS-05 | 冻结子任务只写 key/enabled/status | executor、模板、质量门禁仍依赖可变定义 | 激活时把完整运行元数据写入实例表并以实例表为权威 |
|
||||
|
||||
数据库已添加 executor/template/quality gate 列,但当前实例写入 SQL 仍只插入 task key、enabled 和 status,证明冻结快照尚未真正成为执行权威。[^instance-runtime-metadata]
|
||||
|
||||
### 4.3 文档、三权和运行时授权
|
||||
|
||||
| 编号 | 当前事实 | 风险 | 整改 |
|
||||
|---|---|---|---|
|
||||
| WF-DOC-01 | 启用文档要求三权且互斥 | 基础规则正确 | 再校验三人均为 active 项目成员且账户有效 |
|
||||
| WF-DOC-02 | 禁用文档不会写三权 | 基础持久化正确 | 增加 `skipped_disabled` 和全入口拒绝 |
|
||||
| WF-DOC-03 | 访问过滤按 task key 判断 | 同 key 重复实例可能串权 | 所有动作使用 `doc_task_instance_id` |
|
||||
| WF-DOC-04 | 无 live 实例时访问过滤默认不限制 | 完成后旧任务入口可能恢复可用 | 正式项目按治理模式 fail closed;legacy 仅限显式迁移标记 |
|
||||
| WF-DOC-05 | 运行入口仍接受 task key 并查扁平目录 | 可能绕过阶段和冻结绑定 | 请求只传 doc task instance id,服务端解析 executor/template/duty |
|
||||
| WF-DOC-06 | DocGov 状态机可验证具体审核/批准人 | 可复用 | 文档必须外键绑定 doc task instance 和版本 |
|
||||
|
||||
现有阶段访问代码确实会从 live 快照中排除禁用任务,这是可保留的基础;但当没有 live 实例或实例 completed 时会返回 unrestricted,因此不能把它视为禁用文档全生命周期的完整保障。[^stage-access]
|
||||
|
||||
### 4.4 前端、通知和对话
|
||||
|
||||
| 编号 | 当前事实 | 风险 | 整改 |
|
||||
|---|---|---|---|
|
||||
| WF-UI-01 | 旧切换器硬编码三项,但名称不一致 | 用户认知混乱 | 统一为三个正式名称,数据来自服务端目录 |
|
||||
| WF-UI-02 | 新治理 API 失败时回退旧直接切换 UI | 可重新打开不合规路径 | 删除回退;治理不可用时只读并明确报错 |
|
||||
| WF-UI-03 | 旧切换在版本冲突后自动重试 | 可能覆盖用户最新选择 | 展示冲突并要求重新确认,不自动提交高风险操作 |
|
||||
| WF-UI-04 | 项目设置只显示 stage/task key | 不利于业务确认 | 显示正式阶段名、文档名、启用状态、三权和影响摘要 |
|
||||
| WF-UI-05 | live 配置缺少完整只读审计视图 | 创建者不清楚冻结内容 | 展示版本、hash、激活人/时间、所有 enabled/disabled 和职责 |
|
||||
| WF-NOTIFY-01 | readiness 通知和 24h 提醒已存在 | 基础可复用 | 增加状态转换、已读/已处理、失效和重算 |
|
||||
| WF-DLG-01 | 对话推进旧商务阶段 | 可越过新实例门禁 | 对话调用同一实例 AdvanceStage command |
|
||||
| WF-CTX-01 | 产品经理仅在无材料时拼装部分项目事实;测试工程师只注入 SRS | “全部项目内容”没有统一、可复现的输入语义 | 建立项目上下文快照、来源清单、权限过滤、冲突优先级和 hash 血缘 |
|
||||
|
||||
旧前端切换器在治理不可用时仍调用 `/active-workflow`,并在冲突后自动取新版本再次切换;这两个行为都应删除。[^legacy-switch-ui] 旧服务端路由在迁移完成后应返回 `410 WORKFLOW_SWITCH_API_RETIRED`,而不是继续作为备用入口。[^legacy-route]
|
||||
|
||||
### 4.5 开发数据库现场快照
|
||||
|
||||
2026-09-12 对当前 `shuimu-context-pg-dev / agent_system_dev` 做只读查询得到:
|
||||
|
||||
```text
|
||||
workflow_definitions = 92
|
||||
published workflow versions = 92
|
||||
main = version 1, schema 1, 1 stage
|
||||
product_manager = version 1, schema 1, 1 stage
|
||||
test_manager = version 1, schema 1, 1 stage
|
||||
project_workflow_instances: active 32, completed 47
|
||||
projects.lifecycle_status: active 97, planning 51
|
||||
completed 实例已存在、无 live 实例但项目仍为 active:47 个
|
||||
测试命名定义(pg_* / test_*):88 个
|
||||
```
|
||||
|
||||
这些数字主要反映当前开发环境和集成测试污染,不能直接当成生产数据;但它们证明目录查询没有隔离正式定义与测试定义,也直接复现了“实例已完成而项目仍 active”的生命周期断点。PG 测试在未设置 `TEST_DATABASE_URL` 时默认连接开发库,部分定义发布测试又没有清理工作流定义,因此必须纳入整改。[^test-db-default][^test-definition-no-cleanup]
|
||||
|
||||
## 5. 目标技术模型
|
||||
|
||||
### 5.1 单一运行权威
|
||||
|
||||
```text
|
||||
Published Workflow Version
|
||||
│ 创建 planning plan
|
||||
▼
|
||||
Project Workflow Instance + immutable config snapshot
|
||||
│ 激活时物化
|
||||
├── Stage Instances
|
||||
│ └── Doc Task Instances
|
||||
│ ├── frozen executor/template/quality gate
|
||||
│ ├── duty assignments
|
||||
│ ├── controlled document versions
|
||||
│ └── task runs
|
||||
├── Stage Advance Requests / Notifications
|
||||
└── Audit / Outbox Events
|
||||
```
|
||||
|
||||
激活后,任何运行请求不得再从“最新发布定义”、前端 task key 或 legacy catalog 推导行为。最新定义只用于创建未来实例;已运行实例永远引用自己的冻结数据。
|
||||
|
||||
### 5.2 定义 schema 建议
|
||||
|
||||
文档任务应至少明确以下字段:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "research",
|
||||
"title": "调研报告",
|
||||
"default_enabled": true,
|
||||
"creator_configurable": true,
|
||||
"blocking_when_enabled": true,
|
||||
"executor_key": "bizdev.research.v1",
|
||||
"quality_gate_key": "quality.generic.v1",
|
||||
"template": {"asset_key": "research", "version": 1},
|
||||
"output_doc_type": "research",
|
||||
"output_doc_title": "调研报告"
|
||||
}
|
||||
```
|
||||
|
||||
发布校验必须增加:
|
||||
|
||||
- workflow key 属于三个正式 key 之一,且对外名称准确;
|
||||
- 阶段 key、position、任务 key 均唯一且非空;
|
||||
- 每个阶段至少一个文档任务;
|
||||
- executor、quality gate 和 ready 模板版本全部存在;
|
||||
- 三个正式流程精确满足 7 / 1 / 1 文档清单;
|
||||
- 三个正式工作流均不声明流程级 `required_upstream_workflow`;
|
||||
- 项目上下文输入策略、来源权限和冲突优先级完整;
|
||||
- 禁用策略、完成策略和参与策略完整;
|
||||
- 发布后版本不可原地修改。
|
||||
|
||||
当前 v2 校验只检查 schema 版本、阶段位置、executor/quality gate 注册和输出类型,尚不足以守住上述业务契约。[^validator-v2]
|
||||
|
||||
### 5.3 数据结构增量
|
||||
|
||||
优先扩展现有表,不重复建模:
|
||||
|
||||
- `workflow_definitions`:增加 `project_selectable`、`catalog_order`、`official_code`;
|
||||
- `workflow_versions.definition_json`:采用新禁用语义并保留版本 hash;
|
||||
- `project_workflow_instances`:增加 `completed_at/by`、`terminated_at/by/reason`、`previous_instance_id`;
|
||||
- `project_stage_instances`:增加 `ready_at`、`completed_at/by`;
|
||||
- `project_doc_task_instances`:持久化 `executor_key`、`quality_gate_key`、模板 asset/version、output type/title;禁用任务状态为 `skipped_disabled`;
|
||||
- `documents`:增加 `doc_task_instance_id`,受控文档版本唯一绑定;
|
||||
- `project_context_snapshots`:记录项目、任务、截止时间、汇总 hash、创建人和冻结状态;
|
||||
- `project_context_snapshot_sources`:逐项记录 source type/id/version/hash、权限范围、权威等级、是否实际引用;
|
||||
- `task_runs`:增加 `workflow_instance_id`、`stage_instance_id`、`doc_task_instance_id`、`context_snapshot_id`;
|
||||
- `document_lineages`:从单一“上游 SRS”扩展为多来源 lineage,允许对话、材料、事实、决策和文档版本作为来源;
|
||||
- `stage_advance_requests`:保留 readiness revision,补 `idempotency_key`、`superseded_at`;
|
||||
- 审计事件:至少记录 plan saved、activated、document disabled/enabled、duty assigned、stage ready、stage advanced、workflow completed/terminated。
|
||||
|
||||
### 5.4 API 收敛
|
||||
|
||||
建议正式接口:
|
||||
|
||||
| 方法与路径 | 用途 | 关键约束 |
|
||||
|---|---|---|
|
||||
| `GET /api/v1/workflows/catalog` | 返回严格三项正式目录 | 只含 project_selectable + published |
|
||||
| `GET /api/v1/projects/{id}/settings` | 规划或冻结配置视图 | 项目访问控制 |
|
||||
| `PUT /api/v1/projects/{id}/workflow-plan` | 选择流程、开关文档、设置三权 | 仅创建者、仅 planning、乐观锁 |
|
||||
| `POST /api/v1/projects/{id}/activation-preview` | 完整影响与校验 | 无空流程、三权和上下文策略通过 |
|
||||
| `POST /api/v1/projects/{id}/workflow-instances/activate` | 冻结并激活 | 创建者二次确认、原子 token |
|
||||
| `GET /api/v1/workflow-instances/{id}` | 运行和历史详情 | 项目 + 阶段可见性 |
|
||||
| `GET /api/v1/workflow-instances/{id}/stages/{key}/readiness` | 门禁详情 | 返回所有启用文档状态 |
|
||||
| `POST /api/v1/workflow-instances/{id}/stages/{key}/advance` | 创建者推进或完成 | 事务内重算、幂等 |
|
||||
| `POST /api/v1/workflow-instances/{id}/termination-preview` | 终止影响 | 未决任务、文档和通知清单 |
|
||||
| `POST /api/v1/workflow-instances/{id}/terminate` | 受控终止 | 创建者、原因、二次确认 |
|
||||
| `POST /api/v1/doc-task-instances/{id}/runs` | 启动编制 | enabled + active stage + duty |
|
||||
|
||||
旧 `/projects/{id}/active-workflow` 和依赖扁平 workflow key 的 run 接口先记录迁移告警,完成客户端切换后返回 410。
|
||||
|
||||
## 6. 实施顺序
|
||||
|
||||
### Phase 0:冻结错误扩散和数据盘点
|
||||
|
||||
1. 给项目目录增加服务端正式白名单,立即只暴露三个目标 key。
|
||||
2. 禁止测试默认连接开发库;CI 必须显式提供隔离的 `TEST_DATABASE_URL`。
|
||||
3. 备份并分类 92 个定义及其引用:正式、历史、测试、被实例引用。
|
||||
4. 未被任何实例引用的测试定义在开发环境清理;被引用定义只退役,不物理删除。
|
||||
5. 修复开发环境中 completed instance 与 project lifecycle 不一致的数据,但先输出 dry-run 清单。
|
||||
|
||||
### Phase 1:发布三个唯一正式定义
|
||||
|
||||
1. 修订三个 manifest 的正式名称与 schema;商务流程补齐 7 个文档。
|
||||
2. 为 `feasibility_dev` 和 `user_requirements` 注册专用 executor,或明确映射到通用任务 executor;禁止使用含混的法规 executor 代替。
|
||||
3. 从 `test_manager` manifest、默认目录和校验模型中删除 `required_upstream_workflow=product_manager`,使三个流程在流程级完全独立。
|
||||
4. 增加严格发布校验和 7 / 1 / 1 契约测试。
|
||||
5. 实现 hash 驱动的版本升级:已有 v1 时创建 v2/v3,而不是退出或覆盖。
|
||||
6. `medical_device_development`、`non_medical_software` 及其他定义全部 `project_selectable=false` 并退役。
|
||||
|
||||
### Phase 2:补齐实例状态机和禁用语义
|
||||
|
||||
1. 重构 plan validator:creator-configurable 文档可关闭;启用文档三权必填;空工作流不可激活。
|
||||
2. 校验三权人员为有效项目成员、账户有效且三权互斥。
|
||||
3. 激活时完整物化运行元数据,以实例为唯一权威。
|
||||
4. 阶段推进事务内重算门禁,删除“推进时强制批准文档”的 SQL。
|
||||
5. 完成最后阶段时同步更新项目状态,使其可创建下一 planning 实例。
|
||||
6. 实现受控终止,保证 live 实例不会永久锁住项目。
|
||||
|
||||
### Phase 3:运行、文档治理和权限合流
|
||||
|
||||
1. 建立通用项目上下文快照服务,覆盖项目事实、项目级对话、文档、材料、决策、历史输出和知识命中。
|
||||
2. 产品经理和测试工程师分别从同一快照服务取数;删除测试任务中“查找已批准 system_reqs,否则拒绝”的特例。
|
||||
3. 所有任务启动改用 `doc_task_instance_id`;服务端解析 task/executor/template/stage/duty/context snapshot。
|
||||
4. 文档创建、查看、编辑、提交、审核、批准均校验同一 doc task instance。
|
||||
5. disabled、非当前阶段、非责任人、实例非 live 均 fail closed。
|
||||
6. SSE、异步 task run、恢复/取消、RAG 检索、Agent tools 使用同一策略决策。
|
||||
7. 审批回调按具体文档版本更新具体 doc task instance,不再按项目 + task key 批量更新。
|
||||
8. 把 SRS 单来源 lineage 改成 source manifest 多来源血缘;只在实际引用来源变化时标记输出待复核。
|
||||
|
||||
### Phase 4:通知、对话和前端闭环
|
||||
|
||||
1. readiness 边沿触发状态和通知,补 read/acted/dismissed API。
|
||||
2. 把对话“推进/完成工作流”绑定到项目实例 command;保留明确确认卡。
|
||||
3. 项目设置只显示三项,按正式名称显示阶段和文档。
|
||||
4. active/awaiting 时显示冻结只读视图,隐藏所有切换动作。
|
||||
5. completed/terminated 后显示“配置下一个工作流”,而不是修改旧实例。
|
||||
6. 删除旧切换回退、冲突自动重试和 `WorkflowPrerequisiteBanner` 的产品经理前置提示。
|
||||
7. 在运行预览中展示项目上下文截止时间、来源数量、被排除的私有/无权内容和冲突项。
|
||||
|
||||
### Phase 5:迁移和发布
|
||||
|
||||
1. 新项目只允许使用新的三个正式版本。
|
||||
2. 尚未激活的 planning v1 计划自动重建为新版本草稿,并要求创建者重新确认三权。
|
||||
3. 已激活 v1 实例不静默改写:真实业务实例由创建者选择继续兼容完成或受控终止后重建;开发/测试垃圾实例按确认后的清理脚本处理。
|
||||
4. 先 shadow 计算新旧 readiness 差异,再开启新推进服务。
|
||||
5. 通过全套验收后关闭 legacy route 和 flatten catalog。
|
||||
|
||||
## 7. 验收标准
|
||||
|
||||
### 7.1 目录和定义
|
||||
|
||||
- 任意项目、任意普通用户或管理员在项目选择页都只能看到 3 个工作流。
|
||||
- 正式名称精确为“商务对接流程 / 智能产品经理流程 / 智能测试工程师流程”。
|
||||
- 定义快照精确为 7 / 1 / 1;缺一、多一、重复 key、模板未 ready 或 executor 未注册均无法发布。
|
||||
- 三个正式定义均没有流程级上游依赖;产品经理和测试工程师可被分别独立选择和运行。
|
||||
- 服务重启、数据库迁移和旧数据存在时,目录结果仍稳定为三项。
|
||||
|
||||
### 7.2 选择和冻结
|
||||
|
||||
- 只有项目创建者可保存、激活和推进;普通成员、系统管理员默认均被拒绝。
|
||||
- live 实例存在时,UI、API 和对话三个入口均不能切换。
|
||||
- 工作流完成或受控终止后,创建者可以配置下一实例;旧实例保持只读可追溯。
|
||||
- 两个浏览器同时配置或推进时只有一个成功,另一个收到版本冲突并重新确认。
|
||||
|
||||
### 7.3 文档开关和三权
|
||||
|
||||
- 启用文档缺任一职责、职责重复、责任人非 active 项目成员时不能激活。
|
||||
- 禁用文档没有职责行、没有受控文档、没有运行按钮,也不能通过手工 API、SSE 或对话启动。
|
||||
- 对禁用文档的编制、提交、审核、批准请求全部稳定返回 `DOC_TASK_DISABLED`。
|
||||
- 再启用只允许发生在 planning;激活后不能原地改变。
|
||||
|
||||
### 7.4 阶段门禁和提醒
|
||||
|
||||
- 当前阶段 N 个启用文档中任一未批准,创建者按钮和对话推进均被阻断并返回清单。
|
||||
- 全部批准后只产生一次首提醒;24 小时未处理才产生一次升级提醒。
|
||||
- readiness 后文档被驳回或标 stale 时,旧推进请求失效,确认动作不能成功。
|
||||
- 推进事务不会修改任何文档审批状态。
|
||||
- 最后一阶段确认后实例为 completed,项目立即可配置下一流程。
|
||||
|
||||
### 7.5 安全、恢复和真实链路
|
||||
|
||||
- 跨项目、非成员、非职责人、未来阶段成员、已退出成员全部有服务端负例。
|
||||
- API、SSE、异步任务、断线恢复、搜索、导出、RAG 和 Agent tool 的判定一致。
|
||||
- 服务重启后能恢复 live 实例、当前阶段、禁用状态、职责和 pending 推进请求。
|
||||
- 使用真实 PostgreSQL 和真实 PI Agent 分别跑完商务 7 文档、产品 1 文档、测试 1 文档链路。
|
||||
- 项目从未运行产品经理流程且不存在 SRS 时,测试工程师仍可依据项目对话、文档和材料成功生成唯一测试方案;输出包含逐项来源追溯和待确认清单。
|
||||
- 项目已有 SRS 时,该文档被当作高权威来源纳入,但移除它不会导致工作流定义级依赖错误;是否需要重新生成由本次 source manifest 判断。
|
||||
- 项目私聊/个人草稿未共享时不进入上下文;共享后可被新快照发现。跨项目内容在检索和快照层都有负例。
|
||||
- 同一组项目输入分别启动产品经理和测试工程师时,两者快照可复现、来源清单一致,输出目标和模板不同。
|
||||
- 测试结束后业务数据库中不残留 `pg_*`、`test_*` 定义或测试项目。
|
||||
|
||||
## 8. 已确认的业务决策及实施解释
|
||||
|
||||
2026-09-12 已确认以下决策,后续实现和验收以此为准:
|
||||
|
||||
1. **允许关闭单文档流程的唯一文档,但空工作流不能激活。** 配置可以保存,激活预览必须明确阻断并提示重新启用文档或选择其他工作流。
|
||||
2. **智能产品经理和智能测试工程师解耦。** 两者都直接使用当前项目知识边界内的对话、文档、材料、事实和决策。任何一方的产出都不是另一方的启动前置;已有 SRS 仅作为高权威输入来源。
|
||||
3. **开放项目创建者受控终止工作流。** 必须二次确认、填写原因、处理或取消在途任务并形成审计;completed 和 terminated 都允许创建下一工作流实例,但历史含义必须区分。
|
||||
|
||||
这些决策合理且彼此一致。第 2 项的实施建议是“流程解耦、数据可组合、来源可追溯”,而不是取消质量控制:测试工程师必须自己从项目上下文抽取需求和风险,生成文档内追溯矩阵,并将缺少判据的内容列为待确认,不能因为没有 SRS 就编造需求。
|
||||
|
||||
商务流程按 7 个文档落地、系统只暴露三个正式流程、运行中不可切换、阶段推进必须由创建者确认、禁用文档不得参与任何编审批动作,也均为已确认要求。
|
||||
|
||||
## 9. 建议的实施交付拆分
|
||||
|
||||
建议按以下 8 个可独立评审的变更集提交,避免一次大改难以回滚:
|
||||
|
||||
1. 正式目录隔离与测试数据库隔离;
|
||||
2. 三个正式 manifest、严格 validator 和版本升级器;
|
||||
3. planning 配置、文档开关和成员/三权校验;
|
||||
4. 激活冻结与完整实例物化;
|
||||
5. doc task instance 驱动的执行、DocGov 和统一授权;
|
||||
6. 原子 readiness / advance / complete / terminate 状态机;
|
||||
7. 通知、对话命令与前端只读/下一流程体验;
|
||||
8. 数据迁移、兼容退出、真实 PG/PI Agent E2E 和发布门禁。
|
||||
|
||||
每个变更集都应包含正向测试、越权负例、并发负例和重启恢复验证。只有第 8 项完成后,才应删除旧兼容路径并宣布三工作流治理正式生效。
|
||||
|
||||
## 10. 来源与证据
|
||||
|
||||
[^biz-seven-test]: `web/src/engine/templateFactory.test.ts:8-33`,测试精确断言 7 个任务键;读取于 2026-09-12。
|
||||
[^biz-seven-backend]: `internal/squad/service.go:128-138`,后端标准任务目录包含 7 个商务任务及产品、测试任务;读取于 2026-09-12。
|
||||
[^biz-seven-report]: `.doc/test-reports/2026-09-08-project-init-template-cloning-test-report.md:12-25,51-60`,历史专项测试把商务全生命周期固定为 7 个受控交付物;读取于 2026-09-12。
|
||||
[^bootstrap-five]: `internal/workflowdef/bootstrap.go:63-74,78-115`,启动种子包含三个旧流程及两个额外行业流程;读取于 2026-09-12。
|
||||
[^main-v2-missing]: `internal/workflowdef/manifests/main.v2.json:1-50`,清单只定义 intake、research、feasibility_reg、prelim_design、cdo_quote;读取于 2026-09-12。
|
||||
[^manifest-loader]: `internal/workflowdef/manifest_loader.go:9-32` 仅提供嵌入读取和文件名映射;仓库检索未发现 `V2ManifestFiles` 的运行时调用;读取于 2026-09-12。
|
||||
[^seed-no-upgrade]: `internal/workflowdef/store.go:364-372`,已有任意 latest published version 时直接返回;读取于 2026-09-12。
|
||||
[^catalog-flatten]: `internal/workflowdef/catalog.go:27-41,50-82`,数据库目录将版本压为首阶段首任务;读取于 2026-09-12。
|
||||
[^plan-disable-conflict]: `internal/projectinstance/validator.go:37-90,105-139`,required 或 blocking 任务关闭时校验失败;读取于 2026-09-12。
|
||||
[^advance-forces-approved]: `internal/projectinstance/stage_store.go:71-158`,推进事务把启用任务状态强制更新为 approved;读取于 2026-09-12。
|
||||
[^project-lifecycle-gap]: `internal/projectinstance/stage_store.go:128-158` 只完成实例,`internal/projectinstance/service.go:119-135` 又只允许 planning 项目保存下一计划;读取于 2026-09-12。
|
||||
[^dialogue-old-advance]: `internal/coordinator/engine.go:672-811`,对话推进调用 `bizdevSvc.ExecuteStage` 并直接改变旧成熟度上下文;读取于 2026-09-12。
|
||||
[^settings-all-definitions]: `internal/projectinstance/service.go:94-113`,项目设置枚举全部有 latest published version 的定义;读取于 2026-09-12。
|
||||
[^template-stage-map]: `web/src/engine/templateFactory.ts:37-39,87-89,158-160,228-230,286-288,331-333,392-394`,7 个商务模板当前归属为 V0.1 一项、V0.5 五项、V1.0 一项;读取于 2026-09-12。
|
||||
[^biz-stage-five]: `internal/bizdev/service.go:204-223`,旧商务阶段仅映射 1 + 3 + 1 个任务;读取于 2026-09-12。
|
||||
[^executor-missing]: `internal/workflow/registry.go:5-15`,商务 executor 缺少 feasibility_dev 和 user_requirements;读取于 2026-09-12。
|
||||
[^test-upstream]: `internal/workflowdef/manifests/test_manager.v2.json:1-23`,测试流程声明 product_manager 前置依赖;读取于 2026-09-12。
|
||||
[^test-hard-dependency]: `internal/bizdev/service.go:349-380,673-687`,测试任务硬查同项目 approved SRS、自动注入并记录单一 SRS 血缘;读取于 2026-09-12。
|
||||
[^context-input-foundation]: `internal/squad/service.go:35-55`、`internal/squad/workspace.go:262-408` 和 `internal/bizdev/service.go:250-294`,现有运行参数及工作区已支持项目、材料、前序文档、知识和部分项目事实输入;读取于 2026-09-12。
|
||||
[^instance-schema]: `deploy/postgres/goose/00017_2026-09-12-project-workflow-instances.sql:13-52`,实例状态和 one planning/one live 唯一索引;读取于 2026-09-12。
|
||||
[^plan-structure]: `internal/projectinstance/types.go:21-48`,计划已包含文档 enabled 和三权;读取于 2026-09-12。
|
||||
[^duty-write-enabled-only]: `internal/projectinstance/store.go:244-280`,禁用文档不会写职责行;读取于 2026-09-12。
|
||||
[^readiness-current]: `internal/projectinstance/gate.go:5-53` 和 `internal/projectinstance/stage_service.go:15-63`,现有门禁忽略禁用任务并限制创建者;读取于 2026-09-12。
|
||||
[^approval-key-too-wide]: `internal/projectinstance/stage_store.go:176-191`,批准同步按 project_id + task_key 更新;读取于 2026-09-12。
|
||||
[^notify-ready]: `internal/server/workflow_approval_hook.go:17-44` 和 `internal/notification/service.go:38-107`,批准回调、推进请求、outbox 与创建者通知;读取于 2026-09-12。
|
||||
[^notify-reminder]: `internal/notification/reminder.go:35-91,94-171`,24 小时提醒和 confirmed 状态;读取于 2026-09-12。
|
||||
[^stage-banner]: `web/src/components/workflow/StageAdvanceBanner.tsx:29-95,111-151`,前端轮询 readiness/通知并提供确认按钮;读取于 2026-09-12。
|
||||
[^instance-runtime-metadata]: `deploy/postgres/goose/00023_2026-09-12-instance-integrity.sql:8-11` 已添加运行元数据列,而 `internal/projectinstance/store.go:254-259` 插入时未写这些列;读取于 2026-09-12。
|
||||
[^stage-access]: `internal/projectinstance/stage_access.go:15-71,90-104`,live 实例中排除禁用任务,但无 live/completed 时不限制;读取于 2026-09-12。
|
||||
[^legacy-switch-ui]: `web/src/components/workflow/ProjectWorkflowSwitcher.tsx:16-23,38-76,173-236`,旧名称、旧直切换和冲突自动重试仍存在;读取于 2026-09-12。
|
||||
[^legacy-route]: `internal/server/server.go:157-169`,新项目实例 API 与旧 active-workflow/run API 同时暴露;读取于 2026-09-12。
|
||||
[^validator-v2]: `internal/workflowdef/validator_v2.go:9-47`,现有 v2 校验范围有限;读取于 2026-09-12。
|
||||
[^test-db-default]: `internal/projectinstance/pg_integration_test.go:19-49` 和 `internal/server/workflow_governance_pg_test.go:26-61`,未设置 TEST_DATABASE_URL 时连接本地开发库;读取于 2026-09-12。
|
||||
[^test-definition-no-cleanup]: `internal/workflowdef/publish_test.go:37-72`,发布测试创建带时间戳定义但未注册清理;读取于 2026-09-12。
|
||||
|
||||
开发数据库数字来源:2026-09-12 在本机容器内对 `workflow_definitions`、`workflow_versions`、`project_workflow_instances` 和 `projects` 执行只读聚合查询。该快照仅用于诊断当前开发环境,不代表生产环境。
|
||||
@@ -0,0 +1,15 @@
|
||||
# 整改方案索引
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [gap-matrix.md](./gap-matrix.md) | 发布缺口 SSOT |
|
||||
| [2026-09-12-comprehensive-audit-and-remediation-plan.md](./2026-09-12-comprehensive-audit-and-remediation-plan.md) | 综合缺陷与整改 |
|
||||
| [2026-09-12-remediation-tasks-and-acceptance-checklist.md](./2026-09-12-remediation-tasks-and-acceptance-checklist.md) | 任务拆分与验收 |
|
||||
| [2026-09-12-quick-reference-guide.md](./2026-09-12-quick-reference-guide.md) | 症状→原因→方案速查 |
|
||||
| [2026-09-11-production-ready-workflow-governance-plan.md](./2026-09-11-production-ready-workflow-governance-plan.md) | 生产就绪治理 |
|
||||
| [2026-09-12-permissions-settings-three-workflows-implementation-plan.md](./2026-09-12-permissions-settings-three-workflows-implementation-plan.md) | 权限+三工作流 |
|
||||
| [2026-09-12-phase1-iam-authz-implementation-plan.md](./2026-09-12-phase1-iam-authz-implementation-plan.md) | Phase1 IAM |
|
||||
| [2026-09-12-phase2-workflow-designer-implementation-plan.md](./2026-09-12-phase2-workflow-designer-implementation-plan.md) | Phase2 设计器 |
|
||||
| [2026-09-12-three-workflows-strict-governance-remediation.md](./2026-09-12-three-workflows-strict-governance-remediation.md) | 三工作流严格治理 |
|
||||
|
||||
审计入口:[../audit/INDEX.md](../audit/INDEX.md)
|
||||
@@ -0,0 +1,8 @@
|
||||
# 整改方案
|
||||
|
||||
实施方案、分波次计划、发布缺口 SSOT。
|
||||
|
||||
| 文档 | 说明 |
|
||||
|------|------|
|
||||
| [gap-matrix.md](./gap-matrix.md) | 发布 blocker SSOT |
|
||||
| [INDEX.md](./INDEX.md) | 方案索引 |
|
||||
@@ -0,0 +1,71 @@
|
||||
# 整改缺口复核矩阵(SSOT)
|
||||
|
||||
**更新**: 2026-09-13
|
||||
**分支**: dev
|
||||
**production_ready**: no(CI 真实 PI E2E / 前端人工抽检未完成;main 本地冒烟已通过)
|
||||
**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md)
|
||||
**Agent 手册**: [AGENTS.md](../AGENTS.md) · [PROJECT.md](../PROJECT.md)
|
||||
|
||||
> Codex 2026-09-12 再审计项与本轮回环证据见下表「Codex 再审计」区段。
|
||||
|
||||
---
|
||||
|
||||
## Phase A/B/C 原审计项
|
||||
|
||||
| ID | 审计描述 | 状态 | 证据 | 计划动作 |
|
||||
|---|---|---|---|---|
|
||||
| BUG-01 | 完成后 lifecycle 未更新 | PASS | `stage_remediation_test.go`;`scripts/fix-completed-instance-lifecycle.sql`;dev 执行 UPDATE 47 | 已完成 |
|
||||
| BUG-02 | 推进强制批文档 | PASS | `AdvanceStage` 无 doc UPDATE | 已完成 |
|
||||
| BUG-03 | 无 skipped_disabled | PASS | memStore `skipped_disabled` | 已完成 |
|
||||
| BUG-04 | 对话走旧 bizdev | PASS | `engine.go` live 门控 | 已完成 |
|
||||
| BUG-05 | 拒绝逻辑分散 | PASS | `document_access.go` + `stage_access_helpers.go` | 已完成 |
|
||||
| BUG-06 | token 明文/重放 | PASS | `activation_token_test.go` | 已完成 |
|
||||
| BUG-07 | 完成后下一流程 | PASS | 同 BUG-01 | 已完成 |
|
||||
| BUG-08 | 测试库隔离 | PARTIAL | `db/testdb.go` Require/Skip | CI 设 `TEST_DATABASE_URL` |
|
||||
| BUG-09 | 版本冲突自动重试 | PASS | `StageAdvanceBanner` reload | 已完成 |
|
||||
| BUG-10 | 无审计视图 | PASS | settings + UI | 已完成 |
|
||||
| BUG-11 | 旧 API 未下线 | PARTIAL | 治理开启时 410 | 保持 + 文档标注 |
|
||||
| BUG-12 | 前端名称硬编码 | PASS | catalog API | 已完成 |
|
||||
| MISSING-01 | 上下文快照 | PASS | `ctxmgr.CollectProjectDialogue` | 已完成 |
|
||||
| MISSING-02 | 终止 | PASS | `GetTerminationPreview` | 已完成 |
|
||||
| MISSING-04 | E2E | PASS | 三正式工作流 PG+PI E2E | 已完成 |
|
||||
|
||||
---
|
||||
|
||||
## Codex 2026-09-12 再审计
|
||||
|
||||
| ID | 描述 | 状态 | 证据 |
|
||||
|---|---|---|---|
|
||||
| AUTH-TASK-RUN | `/tasks/run` 缺项目鉴权 | PASS | `handlers.go` RequireProjectAccess;`task_run_authz_pg_test.go` |
|
||||
| AUTH-TASK-SSE | `/tasks/run/stream` 鉴权在 Flush 前 | PASS | `sse.go`;同上测试 |
|
||||
| DB-USERS-SEQ | 种子 users_id_seq 冷启动冲突 | PASS | `00025_...-sync-seed-sequences.sql`;dev/test setval |
|
||||
| DATA-LIFECYCLE-DEV | completed 实例对应 active 项目 | PASS | dev dry-run 47 → fix SQL → 0 |
|
||||
| DATA-TEST-WF | test 污染 active 工作流定义 | PASS | `retire-nonofficial-workflow-definitions.sql`;test UPDATE 5 |
|
||||
| TEST-ADVISOR-BRIEF | 多意图 AdvisorBrief 丢失 | PASS | `action_planner.go` enrich;`action_planner_test.go` |
|
||||
| TEST-V05-ARTIFACTS | V0.5 断言 3 vs 5 | PASS | `types_test.go` / `full_link_e2e_test.go` → 5 |
|
||||
| TEST-CHAT-MEMORY | 语义记忆 sleep 竞态 | PASS | `session_test.go` deadline 轮询 |
|
||||
| TEST-EMBEDDING-GATE | 默认打真实 embedding | PASS | `kb/integration_test.go` Short + `RUN_KB_INTEGRATION=1` |
|
||||
| HEALTH-SCHEMA-CACHE | health schema 启动缓存 | PASS | `LiveSchemaVersion` + health 实时读 |
|
||||
| GO-VET-ASSET | asset handler resp before err | PASS | `asset_handlers_test.go` err-first |
|
||||
| ENV-TEST-STALE | test 旧镜像/schema 漂移 | PASS | rebuild app;health schema_version=25 |
|
||||
| ENV-DEV-STALE | dev 二进制/schema 漂移 | PASS | docker app 重启;schema_version=25 |
|
||||
| ENV-MAIN-MISSING | main 未部署验收 | PASS | docker 创建 `data/main`;compose 注入 ADMIN/KB 密码;health/ready schema 25 |
|
||||
| DOC-SSOT | 文档叙事漂移 | PASS | 本矩阵 + superseded 标记 + ops |
|
||||
| OPS-AGENTS | 多 Agent 协作规范 | PASS | `AGENTS.md` / `PROJECT.md` / `.doc/ops` |
|
||||
|
||||
---
|
||||
|
||||
## 发布门禁(test → main)
|
||||
|
||||
```
|
||||
☑ go vet ./... 全绿
|
||||
☑ go test -short ./... 全绿
|
||||
□ TEST_DATABASE_URL 下治理 PG 集成全绿(CI)
|
||||
□ 真实 PI Agent 三工作流治理 E2E 实录(本轮 stub/short 已绿,PI 待 CI token)
|
||||
☑ lifecycle fix SQL 已在 dev 执行
|
||||
☑ test/dev health schema_version=25
|
||||
☑ main 环境部署冒烟(本地 8000 health/ready schema 25)
|
||||
□ 前端:版本冲突刷新、终止 preview 人工抽检
|
||||
```
|
||||
|
||||
**结论**: P0 授权、冷启动序列、Go 门禁、三环境本地冒烟已闭环。**发布 blocker 剩余 CI 真实 PI E2E 与前端人工抽检**。
|
||||
@@ -0,0 +1,35 @@
|
||||
# 模块与功能完成度(SSOT)
|
||||
|
||||
**更新**: 2026-09-13
|
||||
**production_ready**: no
|
||||
**发布缺口**: [../remediation/gap-matrix.md](../remediation/gap-matrix.md)
|
||||
**协作焦点**: [../ops/CURRENT.md](../ops/CURRENT.md)
|
||||
|
||||
> 本表描述**能力地图**;上线 blocker 见 gap-matrix,二者互相链接、不合并。
|
||||
|
||||
**状态枚举**: `done` | `partial` | `planned` | `deferred` | `blocked`
|
||||
|
||||
---
|
||||
|
||||
## 完成度矩阵
|
||||
|
||||
| 模块 | 能力 | 状态 | 证据 | 缺口/后续 | mutex |
|
||||
|------|------|------|------|-----------|-------|
|
||||
| 意图识别 L1 | 18 类 Intent + 三分支消解 | done | [system-design/intent-recognition](../system-design/intent-recognition/);[test-report 2026-09-07](../test-reports/2026-09-07-three-branch-intent-framework-test-report.md) | — | `intent` |
|
||||
| 对话 / ctxmgr | 多轮上下文、记忆、摘要 | partial | [system-design/multi-turn-dialogue](../system-design/multi-turn-dialogue/);P0 断链已修 | 语义摘要(D5 backlog);长任务治理 | `chat` |
|
||||
| 智能体小队 | 角色-任务-工作区-黑板 | done | [system-design/agent-squad](../system-design/agent-squad/);[test 2026-09-07](../test-reports/2026-09-07-dynamic-squad-planning-test-report.md) | 非关键步骤降级(A5/A6 backlog) | `squad` |
|
||||
| 工作流治理 | 三正式工作流 + 阶段门禁 | done | [remediation/three-workflows](../remediation/2026-09-12-three-workflows-strict-governance-remediation.md);[test 2026-09-12](../test-reports/2026-09-12-three-workflows-governance-remediation-test-report.md) | Phase2 设计器 partial | `workflow` |
|
||||
| IAM / 鉴权 | 项目级 API 鉴权 + RBAC | done | [audit/authorization](../audit/authorization-matrix-v2.md);[test phase1](../test-reports/2026-09-12-phase1-iam-authz-test-report.md) | 旧 API 410 标注(BUG-11 partial) | `authz` |
|
||||
| 文档治理 | 法定文档生命周期 + 租约 | done | [test docgov](../test-reports/2026-09-08-docgov-lifecycle-and-claiming-framework-test-report.md) | — | `docgov` |
|
||||
| 前端工作台 | 三栏 + 块文档 + SSE | partial | [test workbench](../test-reports/2026-09-08-three-column-workbench-and-block-document-test-report.md) | 人工抽检待完成 | `web` |
|
||||
| PI Runner / 配置链 | pi-agent + MiniMax 真实链路 | done | [test piagent](../test-reports/2026-09-13-codex-audit-p0-remediation-test-report.md);[container-env](../test-reports/2026-09-13-container-env-configuration-test-report.md) | — | `pi-agent` |
|
||||
| 三环境运维 | dev/test/main + 共享 KB | done | [PROJECT.md](../../PROJECT.md) §4;四环境 healthy | — | `infra` |
|
||||
| CI / E2E | PG 集成 + 真实 PI E2E | partial | [gap-matrix BUG-08](../remediation/gap-matrix.md);[test pg-ci](../test-reports/2026-09-12-pg-ci-soak-e2e-test-report.md) | CI `TEST_DATABASE_URL` + 真实 PI E2E 实录 | `ci` |
|
||||
|
||||
---
|
||||
|
||||
## 更新规则
|
||||
|
||||
1. 模块状态变化时同步更新本表与 [gap-matrix](../remediation/gap-matrix.md)(若涉及 blocker)
|
||||
2. 同一 `mutex` 同时仅一个 Agent `in_progress`(见 CURRENT 并行认领表)
|
||||
3. 新能力行:复制模板 [../ops/templates/feature-matrix-row.md](../ops/templates/feature-matrix-row.md)
|
||||
@@ -0,0 +1,5 @@
|
||||
# 模块完成度
|
||||
|
||||
**SSOT**:[FEATURE-MATRIX.md](./FEATURE-MATRIX.md)
|
||||
|
||||
与 [remediation/gap-matrix.md](../remediation/gap-matrix.md)(发布 blocker)分离:本目录描述**能力地图**,gap-matrix 描述**上线缺口**。
|
||||
@@ -29,6 +29,7 @@ logs/
|
||||
|
||||
# Workspaces & Cache
|
||||
workspaces/
|
||||
.worktrees/
|
||||
.cache/
|
||||
tmp/
|
||||
temp/
|
||||
|
||||
Reference in New Issue
Block a user