10 KiB
10 KiB
合同详情页与高风险动作归位
Goal
独立建设符合“列表查找、详情处理”的合同工作区,明确合同详情的信息顺序、权限边界、证据表达、终止状态和高风险动作位置;不把从零新增详情能力混入采购/资产的路由搬迁。
Background
- 当前
ContractsRegistryPage是“列表 + 内联新建/编辑器”,只有showEditor/editorId,没有 selected ID、?id=详情或独立详情态。 - 当前客户端只有合同列表查询、创建、PATCH、续约和台账导出;服务端没有单条详情 GET。
- 当前持久状态只有
draft/active/archived,expired是按到期日推导的展示状态;Prismastatus为VarChar(32),新增terminated本身无需改列类型或回填历史状态。 - 当前合同审计为 best-effort:写入失败只记录服务日志而不阻断业务。终止属于高风险状态变更,原因和审计不得沿用该失败策略。
- 合同可关联项目;
ConfidentialDocumentRef可关联合同,但它是涉密资料索引,不是正文文件库。 docs/需求-合同附件归档规约.md已规划非涉密附件受控入库,并把它列为详情页之后的独立开发步骤。本轮不做附件能力是范围裁剪,不是永久产品边界。
Scope
- 合同列表改为纯查找入口,详情承担状态、摘要、证据、历史和动作面板。
- 证据区本轮只承载归档位置、离线档案号和涉密资料索引;非涉密附件能力按
docs/需求-合同附件归档规约.md第 13 节第 4 项另建 task。 - 增加
terminated及terminated_at / terminated_reason / terminated_by三列,终止原因至少 10 个字,状态/终止字段/审计事务一致提交。 - 迁移、状态机、权限和审计变更实施后必须完成只读 reviewer;生产 migration 和部署另行获批。
Requirements
R1 页面与信息结构
- 合同列表只负责查找、筛选、状态摘要、到期/续签提醒、台账导出和进入详情;现有内联新建/编辑器随详情工作区落地移除。
- 合同详情信息顺序固定为:
状态与下一步 → 业务摘要 → 证据区 → 变更/操作历史 → 动作面板。 - PC 动作面板位于详情右侧;移动端如本轮提供详情表达,只保留查看和底部安全区轻动作,不复制 PC 管理能力。
- 建立稳定合同详情路由、单条 GET 合同和客户端 detail query;服务端沿用当前合同范围权限,不扩大普通用户可见范围。
R2 证据区本轮范围裁剪
- 本轮证据区只展示:归档位置
archive_location、离线档案号offline_archive_no、涉密资料索引ConfidentialDocumentRef。 - 必须显示业务引导:“涉密资料请登记线下归档位置”,解释
archive_location非空必填的原因。 - 版式为后续附件类型分区预留扩展位置,但本轮不渲染空附件区,也不在列表显示“附件完整性”列。
- 本轮不新增合同正文或非涉密附件的上传、预览、下载与附件审计;该能力按
docs/需求-合同附件归档规约.md第 13 节第 4 项另建 Trellis task。 - 不得把“不在本轮上传合同文件”写成永久产品边界。
R3 状态模型
- 本轮状态值域为
draft / active / terminated / archived / expired,其中expired继续由日期推导,terminated为新增持久状态,用户文案为“已终止”。 - “作废”不新增另一状态;已编号或已生效合同不再执行时统一进入“已终止”,合同编号不得释放或复用。
terminated采用专用字段terminated_at / terminated_reason / terminated_by;终止原因 trim 后至少 10 个字,三项在详情状态区可直接读取。- 状态不变量固定为:
status = terminated当且仅当三个终止字段均非空;其他状态三个字段均为空。服务层在事务内强制该不变量。 terminated_by关联员工并使用onDelete: Restrict,终止人不得因员工记录变化丢失。- 已签署、履行中、已完成等状态后置;真实使用证明现有字段不足时另建 task。
- 归档后普通字段锁定;授权修正只能追加变更记录,不覆盖历史事实。
R4 动作矩阵
- 编辑:常规动作,按当前管理权限和状态开放。
- 续约:常规动作,只在既有允许状态开放,沿用新草稿 + 原合同归档语义。
- 归档/恢复:状态动作;归档后锁定普通字段,恢复及修正必须留痕。
- 终止:高风险动作;原因至少 10 个字,输入区持续显示要求,按钮禁用时明确显示“请填写终止原因,至少 10 个字”;二次确认展示合同编号、相对方、金额和后果,状态写入、三个终止字段与审计必须同一事务成功。
- 本轮不在合同详情放审批通过、驳回、退回或转审;如后续启用合同审批,只展示状态和进入统一审批中心的入口。
- 本轮不在合同详情放付款写动作;只展示授权付款摘要和“查看付款”入口。
- 台账导出继续属于列表筛选范围动作,不变成单条合同“下载”。
R5 关联、历史与权限
- 跨模块只做“摘要 + 跳转”:项目、采购和付款只展示当前 API/关联模型能证明且当前用户有权查看的摘要;无稳定关联字段时不虚构数据。
- 详情展示合同创建、编辑、状态变化、归档/恢复、续约、终止和归档后修正历史;高风险写操作不得因审计失败而静默成功。
- 普通用户无权访问时不泄露合同是否存在;管理员和授权角色仍受服务端范围约束。
- 深链、刷新、返回、无权限、不存在和 dirty-form 离开均有可解释结果。
R6 数据迁移、审查与发布
- 新增三个可空字段和
terminated_byRestrict 外键的 Prisma migration;历史合同不回填终止事实,新增列允许空值,仅终止接口可原子写入完整三项。 - migration 必须经过
prisma:validate、聚焦路由/服务测试、迁移状态检查及既有数据兼容验证;禁止用数据库重置代替迁移。 - 实施完成后启动只读 reviewer,重点检查状态机、权限、事务审计、迁移兼容和隐私;reviewer 不修改代码。
- 生产部署需另行明确批准;部署后必须显式验证 migration 状态、
/ready、合同列表/详情和权限负向路径,不能只依赖 runbook 或 init 成功日志;失败时停止并按设计回滚。 - migration 为纯增量可空列;代码回滚前如已产生终止记录,先保留审计追溯并评估字段信息损失,再决定是否 drop 三列,不自动执行破坏性 schema 回滚。
Acceptance Criteria
- 合同列表不再承载记录编辑器,只保留查找、筛选、提醒、导出和进入详情。
- 合同详情具有稳定深链,并按“状态与下一步、业务摘要、证据区、历史、动作面板”展示。
- 证据区展示归档位置、离线档案号和涉密资料索引,并出现“涉密资料请登记线下归档位置”;不渲染空附件区或列表附件完整性列。
- 本轮没有新增合同正文/非涉密附件上传、预览或下载;PRD 明确其为后续独立能力而非永久禁止。
- 状态值域支持
terminated;终止原因至少 10 个字,操作者和时间可在详情直接读取,合同编号不释放。 - 服务层与聚焦测试证明
terminated与三个终止字段满足全有或全空不变量,terminated_by使用 Restrict 外键。 - 终止原因不足 10 字时界面邻近显示禁用原因;满足要求后,确认展示合同编号、相对方、金额和后果,状态、三字段与审计同事务成功或共同失败。
- 归档后普通字段锁定;授权修正追加记录,不覆盖原历史。
- 编辑、续约、归档/恢复按权限和状态显示;审批类与付款类写动作不进入合同详情。
- 项目/采购/付款只做有权限且有真实数据来源的摘要与跳转,不复制对方流程。
- 无权限详情请求不泄露合同事实;不存在、深链刷新、返回和 dirty-form 行为可解释。
- 如包含 migration,Prisma 校验、迁移兼容、聚焦后端测试、前端 Playwright、typecheck/build 和 Trellis 门禁通过。
- 只读 reviewer 完成状态机、权限、事务审计、迁移与隐私审查,且未修改代码。
Out of Scope
- 本轮不做非涉密附件上传、预览、下载或附件审计;按合同附件归档规约第 13 节第 4 项另建 task。
- 不接入合同审批;如需要按规约第 7 节另建 task 接入统一审批中心。
- 不做电子签章、法务审查、条款库、版本协同或完整 CLM。
- 不新增已签署、履行中、已完成等尚缺事实字段支撑的状态。
- 不复制采购、资产、付款或项目完整流程。
- 不写入生产合同正文、真实附件、完整归档路径或真实业务数据。
Accepted Risk
- “已终止”是不可逆终态,本轮不提供恢复、续约或再归档路径。必填至少 10 个字的原因、合同编号/相对方/金额/后果确认和事务审计用于降低误操作风险;若后续出现真实误终止案例,另建 task 评估受控管理员修正路径。
Open Questions
- 无;需求范围与终止持久化方案均已确认。
Test Plan
cd server && npm run prisma:format && npm run prisma:validate && npm run prisma:generatecd server && node --check src/routes/contractsRegistry.jscd server && npm test -- tests/unit/routes/contractsRegistry.test.js tests/unit/routes/exports.contractsRegistry.test.jscd server && npx prisma migrate status(只读;不得用 reset 或未经批准 deploy)。cd client && npm run typecheck && npm run build- 聚焦 Playwright 覆盖合同列表/详情、证据引导、终止原因禁用提示、确认摘要、状态成功/重复终止、归档锁定、权限负向和窄屏动作。
- 实施后启动只读 reviewer,检查状态不变量、专用终止接口、事务审计失败回滚、
terminated不参与过期/续约、Restrict 外键、迁移兼容和敏感字段裁剪。 - 运行 task validate、process contract、docs registry、Trellis governance、敏感内容检查和
git diff --check。