diff --git a/docs/domain-events.md b/docs/domain-events.md new file mode 100644 index 00000000..e658e881 --- /dev/null +++ b/docs/domain-events.md @@ -0,0 +1,63 @@ +# 领域事件清单(P19 冻结版) + +**快照日期**:2026-03-07 +**目标**:冻结 `hyb-oa` 当前采购与资产域对外发布的标准事件名称、触发时机与最小载荷,为未来 ERP / IM / AI 适配提供统一事实源。 + +## 1. 使用原则 +- 本文档只定义**领域事件名与边界**,不代表当前已实现事件总线。 +- 未来若落地 Outbox / webhook / MQ,事件名与载荷应保持向后兼容。 +- 事件仅表达“已经发生的领域事实”,不表达待办命令。 + +## 2. 标准事件清单 + +| 事件名 | 触发时机 | 领域对象 | 最小载荷字段 | 推荐消费者 | 备注 | +| --- | --- | --- | --- | --- | --- | +| `purchase_request.submitted` | 采购申请提交成功后 | `purchase_request` | `purchaseRequestId`, `requestNo`, `applicantId`, `departmentId`, `legalEntityId`, `costCenterId`, `supplierId`, `budgetPoolId`, `totalAmount`, `status` | IM 通知、ERP 预处理、AI 摘要 | 仅表示进入 `reviewing` | +| `purchase_request.approved` | 采购申请审批通过后 | `purchase_request` | `purchaseRequestId`, `requestNo`, `approvedBy`, `legalEntityId`, `costCenterId`, `supplierId`, `budgetPoolId`, `totalAmount`, `status` | ERP、IM、AI | 对应预算 `confirm` 已完成 | +| `purchase_request.rejected` | 采购申请审批驳回后 | `purchase_request` | `purchaseRequestId`, `requestNo`, `actorId`, `reason`, `status` | IM、AI | 若存在预算预留,应已释放 | +| `purchase_request.withdrawn` | 申请人撤回采购申请后 | `purchase_request` | `purchaseRequestId`, `requestNo`, `actorId`, `status` | IM、AI、ERP 补偿 | 表示由 `reviewing` 回到 `draft` | +| `asset.card.created` | 资产卡片创建成功后 | `asset_card` | `assetId`, `assetNo`, `name`, `categoryId`, `legalEntityId`, `costCenterId`, `purchaseRequestId`, `status` | ERP、IM、AI | 资产域不接 workflow | +| `asset.assigned` | 资产领用成功后 | `asset_card` | `assetId`, `assetNo`, `employeeId`, `assignedAt`, `location`, `status` | IM、AI | 对应新增 open assignment | +| `asset.returned` | 资产归还成功后 | `asset_card` | `assetId`, `assetNo`, `employeeId`, `returnedAt`, `location`, `status` | IM、AI | 对应关闭 open assignment | +| `asset.transferred` | 资产调拨成功后 | `asset_card` | `assetId`, `assetNo`, `fromEmployeeId`, `toEmployeeId`, `fromLocation`, `toLocation`, `transferredAt`, `status` | ERP、IM、AI | 可只改位置,不一定改归属人 | +| `inventory_check.completed` | 盘点任务完成后 | `inventory_check` | `inventoryCheckId`, `checkNo`, `scopeType`, `scopeRefId`, `completedAt`, `itemCount`, `summary` | ERP、IM、AI | `summary` 建议包含 matched/missing/extra/damaged 计数 | + +## 3. 事件名与运行时对象映射 + +| entityType | 推荐事件前缀 | 当前事实源 | +| --- | --- | --- | +| `purchase_request` | `purchase_request.*` | `P17A` / `P17B` | +| `asset_card` | `asset.*` | `P18A` / `P18B` | +| `inventory_check` | `inventory_check.*` | `P18B` | + +## 4. 最小 Envelope 建议 + +未来若落地事件投递,建议统一使用如下 envelope: + +```json +{ + "eventName": "purchase_request.submitted", + "eventId": "uuid", + "occurredAt": "2026-03-07T23:22:00+08:00", + "actorId": "user-id", + "entityType": "purchase_request", + "entityId": "entity-id", + "payloadVersion": 1, + "payload": {} +} +``` + +## 5. 兼容性规则 +- 事件一旦对外承诺,名称不得随意修改。 +- 新增字段必须保持向后兼容;删除字段需要单独版本升级。 +- 载荷字段命名应与 HTTP camelCase 输出保持一致,不直接暴露数据库 snake_case 列名。 + +## 6. 明确不纳入 P19 的事件 +- `purchase_request.archived`:待未来需要对接采购归档通知时再冻结 +- `inventory_check.started`:当前不作为外部关键事实源 +- `asset.repaired` / `asset.retired`:待未来维修/报废专项后再定义 + +## 7. 推荐的首批消费场景 +- IM:采购提交、采购审批结果、资产领用归还、盘点完成提醒 +- ERP:采购审批通过摘要、资产卡片新增摘要、盘点完成摘要 +- AI:审批摘要、异常提示、主数据重复建议、盘点结果总结 diff --git a/docs/integration-boundaries.md b/docs/integration-boundaries.md new file mode 100644 index 00000000..7dcb72f8 --- /dev/null +++ b/docs/integration-boundaries.md @@ -0,0 +1,138 @@ +# 集成边界冻结(P19) + +**快照日期**:2026-03-07 +**当前基线**:`P18B` 已完成并进入 `docs/feature-matrix.md`。 +**目标**:冻结 `hyb-oa` 在 ERP/财务、IM/协同、AI 与 MCP 使用上的边界,作为后续专项实施的约束,不直接引入任何运行时代码。 + +## 1. 总体原则 + +### 1.1 只通过边界集成 +- 外部系统只允许通过两种形式接入: + - 领域事件(推荐,后续可落到 Outbox) + - 显式 API 适配层 +- 禁止外部系统直写核心业务表。 +- 禁止为了对接外部系统,在核心事务表中提前加入 ERP 私有字段、IM 私有字段或 AI 中间状态字段。 + +### 1.2 核心域优先 +- `purchase_request`、`asset_card`、`inventory_check` 等领域模型继续由业务服务自己维护。 +- 集成层只能消费既有领域事实,不能反向篡改领域判定逻辑。 +- 若未来需要双向同步,必须先定义“系统主责方(source of truth)”,再设计幂等回写接口。 + +### 1.3 回滚优先 +- 所有未来集成必须支持“关闭适配器后核心域仍可独立运行”。 +- 外部调用失败只能影响外围联动,不得阻断核心单据保存、审批和查询。 +- 对外推送必须具备可重试、可补偿、可审计能力。 + +## 2. ERP / 财务适配边界 + +### 2.1 允许进入适配层的对象 +- 主数据:`LegalEntity`、`CostCenter`、`Supplier` +- 采购:`purchase_request` 的审批结果、预算占用确认结果、PO/合同归档摘要 +- 资产:`asset_card` 基础卡片信息、归属变更摘要、盘点完成摘要 + +### 2.2 推荐适配方式 +- **主数据同步**: + - 由 `hyb-oa` 输出标准化读模型或事件 + - ERP 适配器负责字段映射与批量/增量同步 +- **财务凭证/单据接口**: + - 先生成中间格式(例如 JSON/CSV/显式 API payload) + - 再由独立适配器调用外部 ERP +- **失败处理**: + - 在适配层重试 + - 失败记录在适配层日志/事件投递表,不回写核心事务状态为“失败” + +### 2.3 明确禁止事项 +- 禁止在 `PurchaseRequest`、`AssetCard`、`BudgetPool` 等核心表中直接加入 ERP 专有主键、分录号、凭证表字段。 +- 禁止应用直接连写 ERP 主表。 +- 禁止把 ERP 状态机复制到 `hyb-oa` 核心路由中。 + +### 2.4 建议的后续专项 +- `P19+ERP-1`:主数据同步协议 +- `P19+ERP-2`:采购审批结果导出/回写协议 +- `P19+ERP-3`:资产台账摘要导出协议 + +## 3. IM / 协同适配边界 + +### 3.1 允许能力 +- 飞书 / 企微消息通知 +- 待办提醒 +- 深链跳转(例如采购审批详情、资产盘点详情) +- 审批摘要的只读推送 + +### 3.2 边界约束 +- IM 适配器只消费领域事件,不直接读取或修改数据库。 +- IM 适配器可以构造消息文案、跳转链接、卡片摘要,但不能替代工作流审批判定。 +- 任何“点击消息即审批”的能力,必须仍然回到 `hyb-oa` 的鉴权与工作流接口执行。 + +### 3.3 禁止事项 +- 禁止把 IM 用户标识写入核心审批流状态字段。 +- 禁止在 IM 侧持久化领域真相状态并反向覆盖业务库。 + +## 4. AI 增强边界 + +### 4.1 允许能力 +- 审批摘要生成 +- 采购/资产异常提示 +- 主数据重名与重复建议 +- 文档/制度/流程问答检索 + +### 4.2 强制约束 +- AI 只做建议,不直接写库。 +- AI 输出必须允许人工复核和拒绝。 +- 任何模型调用都不得绕过现有权限校验。 +- 若未来接入外部大模型,必须先明确脱敏策略与日志留存边界。 + +### 4.3 禁止事项 +- 禁止 AI 自动创建、审批、归档业务单据。 +- 禁止 AI 直接修改预算、工作流、资产归属等核心状态。 + +## 5. 领域事件交付规范 + +### 5.1 事件最小结构 +后续若引入事件投递,建议统一包含: +- `eventName` +- `eventId` +- `occurredAt` +- `actorId` +- `entityType` +- `entityId` +- `payloadVersion` +- `payload` + +### 5.2 幂等要求 +- 同一 `eventId` 必须可安全重放。 +- 消费端必须以 `eventId` 或 `entityId + status/version` 方式做幂等。 +- 不允许消费端以“收到多次事件”为理由修改核心业务状态。 + +## 6. MCP 基线 + +### 6.1 当前结论 +- `P19` 阶段 **不启用 MCP**。 +- 当前仓库中 **不创建** `docs/mcp-tools.md`,因为尚未进入实际 MCP 使用场景。 + +### 6.2 首次启用前置条件 +若未来需要启用 MCP,固定顺序如下: +1. 明确真实用途(数据库只读排障、GitHub PR/Issue/CI 协作等) +2. 新增 `docs/mcp-tools.md` +3. 使用 `mcp-tools-catalog` 生成工具目录 +4. 在执行合同中记录启用原因、风险与禁用边界 + +### 6.3 允许的 MCP 范围 +- `postgres MCP`:只读排障、迁移核对、账本核对 +- `github MCP`:PR / Issue / CI 协作 + +### 6.4 禁止事项 +- 禁止在没有 `docs/mcp-tools.md` 的前提下默认启用 MCP +- 禁止用 MCP 绕过仓库内已存在的本地验证命令 +- 禁止将 MCP 用作写生产数据的通道 + +## 7. 本阶段明确不做 +- 不实现 Outbox 表 +- 不新增对外 webhook +- 不接入 ERP、飞书、企微或大模型 SDK +- 不修改任何路由、Prisma 模型、前端页面和工作流逻辑 + +## 8. 下一步专项建议 +- 若优先打通 ERP,请先开“主数据同步协议”专项 +- 若优先做协同体验,请先开“IM 待办通知”专项 +- 若优先做智能化,请先开“审批摘要与异常提示”专项