petstore-docs/架构决策-业务事件落库-2026-08-01.md

86 lines
4.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 架构决策BusinessEvent 业务事件落库
> 日期2026-08-01
>
> 状态:已采纳,待生产数据迁移
>
> Owner AgentBackend Core报告/留资写入点联动 Report Media Backend
>
> Service Lock`BusinessEvent*`、预约/报告/留资事件调用点、工作台报告漏斗
>
> Paired QACore Flow QA + Report Share QA
>
> Data Model Review RequiredYes
>
> Access / Privacy Review RequiredYes
## 1. 决策背景
此前本体中的 Event 多数只表达“动作发生后应存在的事实”并没有统一事件表。报告打开仅写应用日志工作台只能由前端临时拼预约、报告和留资无法可靠支持经营漏斗、StoreCustomer 时间线、回访归因和复购统计。
## 2. 冻结模型
`BusinessEvent` 是不可变事实,不是业务对象当前状态,也不是消息队列。
| 字段 | 语义 |
|---|---|
| `event_id` | 随机事件 ID不使用数据库自增 ID 做外部关联 |
| `event_type` / `event_version` | 过去时事件名与 schema 版本 |
| `store_id` | 强制门店数据范围 |
| `store_customer_id` | 可选门店客户稳定关系,供客户时间线使用 |
| `aggregate_type` / `aggregate_id` | 事件对应的 Appointment、Report 或 ReportLead |
| `actor_user_id` / `actor_role` | 操作人快照;匿名公开事件可空 |
| `source` | customer / admin / public_report / system / migration |
| `occurred_at` | 业务事实发生时间 |
| `metadata_json` | 服务端白名单低敏维度,不接受原始请求体 |
| `idempotency_key` | 可选稳定键,保证一个业务结果只落一条 |
| `create_time` | 事件入库时间 |
事件表只追加,不提供更新、软删除或通用明细 API。
## 3. 第一批真实事件
| 事件 | 可靠触发点 | 幂等口径 |
|---|---|---|
| `appointment_created` | 预约保存成功 | appointment ID |
| `appointment_status_changed` | 合法状态迁移保存成功 | appointment ID + 目标状态 |
| `service_started` | `new -> doing` | appointment ID |
| `service_completed` | `doing -> done` | appointment ID |
| `report_submitted` | 报告及图片保存成功 | report ID |
| `report_sent` | 门店员工首次显式确认宠主实际收到 | report ID`report_sent:{reportId}` |
| `report_opened` / `report_reopened` | 公开报告打开埋点 | 每次有效打开;统计按 report ID 去重 |
| `lead_submitted` | 每次留资提交成功 | 可重复记录;漏斗按 lead ID 去重 |
> 2026-08-02 增量决策:`report_sent` 已通过显式确认状态机可靠落地;复制链接、二维码和预览不构成发送。详见《架构决策-报告确认发送状态-2026-08-02》。`follow_up_completed`、`rebook_created` 仍无可靠状态机或归因字段,本阶段明确不伪造。
## 4. 隐私边界
- 事件表不得保存手机号、报告 token 或 token hash、媒体 URL、IP、openid/unionid、备注、内容全文、密码、密钥或任意请求体。
- 报告打开接口只用 token 在服务端定位 Report事件仅保存内部 report ID日志继续只记 SHA-256 前 8 位 hex。
- 管理端只开放按当前会话 `storeId` 聚合的漏斗结果,不开放事件明细。
## 5. 一致性与迁移
- 预约、状态迁移、报告提交与事件写入处于同一数据库事务。
- 留资沿用现有并发幂等事务边界;重复提交可产生动作事件,漏斗按 lead ID 去重,不放大转化数。
- 历史迁移只回填可从数据库确定的预约创建、报告提交、由报告确认的服务完成和留资提交。
- 历史报告打开与开始服务时间无法可靠恢复,不做猜测性回填。
迁移顺序:
1. `20260801_split_service_identity.sql`
2. `20260801_create_store_customer.sql`
3. `20260801_create_business_event.sql`
## 6. BusinessEvent 与 AuditLog 边界
BusinessEvent 记录“经营上发生了什么”AuditLog 记录“谁对受保护配置或数据做了什么变更”。本阶段先完成服务闭环事实,后续在门店开通、员工权限、设置修改和敏感操作进入生产化时建立独立 AuditLog不把安全审计字段混入经营事件。
## 7. 验收
- `mvn test` 全绿,迁移 SQL 集成测试通过。
- `npm run build`admin通过工作台“已打开”来自事件汇总。
- customer 访问工作台事件汇总为 403boss/staff 只能读取本店。
- 事件 metadata 隐私单测证明不含原始 token、手机号或 IP。
- 本体校验通过且 controller/entity 0 漂移。