You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
40 lines
4.3 KiB
40 lines
4.3 KiB
|
14 hours ago
|
---
|
||
|
|
status: accepted
|
||
|
|
---
|
||
|
|
|
||
|
|
# 项目双轴状态机模型(crm-project:stage 非线性骨架 + status 横切 + filing 独立轴)
|
||
|
|
|
||
|
|
## Context
|
||
|
|
|
||
|
|
A5 项目管理(crm-project)需要一套生命周期模型,管理项目从冲突处理到结项的全过程。建模时存在两条路线:
|
||
|
|
|
||
|
|
- 商机域旧模型:项目寄居 `crm_opportunity` 表、`opp_status=5` 切域(票 07 共表定案)——已被 ADR-0041 / spec §2.1 路线甲推翻(项目落独立 `crm_project` 表);
|
||
|
|
- 商机域的双轴形态:`opp_status`(归属流转)+ `current_stage_id`(模板驱动阶段节点)——不能照搬:项目阶段骨架固定(原型 7 阶段全画、无可配模板),且报备/赢输是商机没有的正交语义。
|
||
|
|
|
||
|
|
约束(grilling 20260821 拍板,spec §0 会话表 #8/#9/#12):
|
||
|
|
|
||
|
|
- stage5 是**赢/输分叉点**:赢单 stage5 闭环锁死不进结项;仅输单进 stage6——阶段轴**非线性**;
|
||
|
|
- 回退 = 弹窗多步选前序节点、下限 stage1、仅管理员+销售总监;三终态锁死(结项/已关闭/赢单);
|
||
|
|
- 报备独立于双轴:建项目即触发(filing_status=1),审核通过=冲突解除(一次动作双写 stage 0→1)。
|
||
|
|
|
||
|
|
## Considered Options
|
||
|
|
|
||
|
|
- **A(选中):三轴分离**——轴1 `project_stage`(tinyint 0~6,固定骨架枚举 `ProjectStage`,非线性迁移图收敛于 `ProjectStageMachine`)+ 轴2 `project_status`(1/2/3,横切:进行中/已关闭/已结项)+ 独立轴 `filing_status`(0~3,报备)。赢输之别由 `bid_result`(0/1/2)在 stage5 表达,不新增 status 值。
|
||
|
|
- **B:照搬商机模板驱动阶段**(current_stage_id + stage_template)——项目阶段骨架产品定案固定 7 节点,模板机制是纯开销;且商机阶段节点 id 化后回退/连跳判定要查模板表,项目的回退「已经过节点」由动态留痕即可投影,否。
|
||
|
|
- **C:赢/输各占一个 status 值**——status 轴语义是「归属处境」(进行中/已关闭/已结项),赢输是 stage5 上的**业务结果**,塞进 status 会让「赢单+已关闭」「输单+已关闭」组合爆炸,否。
|
||
|
|
|
||
|
|
## Decision
|
||
|
|
|
||
|
|
1. **双轴 + 独立报备轴**落在 `crm_project` 主表三列:`project_stage`(0~6)/`project_status`(1/2/3)/`filing_status`(0~3,0 本期不可达);`bid_result`(0/1/2)住 stage5 分叉点。
|
||
|
|
2. **迁移判定收敛单点** `ProjectStageMachine`:常规推进(1→2→3→4→5)、唯一连跳 3→5(无需招投标)、回退守卫(多步选前序节点、下限 stage1、三终态锁 + 赢单锁)、关闭守卫(任意 stage、已关闭/已结项不可再关)、赢输守卫(仅 stage5 未标记)、冲突解除守卫(仅 stage0)。
|
||
|
|
3. **「已经过节点」投影**:项目动态 `project_oplog` 阶段类动作带结构化 `from_stage/to_stage`,回退可选节点 = 动态投影 ∪ {stage1}——3→5 连跳跳过的 stage4 不在可选列表(spec §3 已回写)。
|
||
|
|
4. **写侧授权双层**:状态动作(推进/关闭/赢输/冲突解除)= 负责人 ∨ 管理员/销售总监(`ProjectActionAuthorizer`,68010);阶段回退 = 管理员/销售总监(`ProjectRollbackAuthorizer`,68005)。系统无「报备专员→用户」绑定,报备审核动作暂按同一 owner∨管理口径强制(16R/D-02 拍板,细分角色随权限系统接线收紧)。
|
||
|
|
5. **动态留痕单写入口** `ProjectOplogWriter`(append-only,全事件落 `project_oplog`);状态落库走实体 `@Version` CAS(并发变化 68003)。
|
||
|
|
|
||
|
|
## Consequences
|
||
|
|
|
||
|
|
- 主流程(建档→冲突解除双写→推进→连跳→多步回退→赢单闭环/输单结项→关闭记因→三终态锁)e2e 全通(票 14/15 冒烟 35 步 + 票 17 复测主链 11 步);赢单态可被主动关闭为「已关闭」系 spec §3「任意 stage 可主动关闭」的既有口径(复测观察项,供产品复核)。
|
||
|
|
- 回退口径与 spec §3 双向回写定稿(连跳后可选节点、权限承载);报备/赢输语义不再有 schema 层歧义。
|
||
|
|
- 将来若产品要求「赢单不可关闭」「报备专员细分权限」,只需改 `ProjectStageMachine.ensureCloseable` / `ProjectActionAuthorizer` 实现各一处。
|
||
|
|
- 决策来源:crm-project-wayfinding 票 03(阶段状态机)+ grilling 补拍(spec §0 会话表 #8/#9/#12);本 ADR 即 spec §8 留痕清单的「项目双轴模型」项。
|