[BEL] 在 GoAdmin 基线上重建 Event、Receipt 与合成事件入口 #131

Closed
opened 2026-08-29 08:43:41 +08:00 by ila · 3 comments
Owner

状态

待实施

基本信息

  • 类型:需求 / 单项目
  • 主项目:Bell
  • 主 agent:Bell agent
  • 所属 Epic:#7
  • 所属 MVP:#8
  • 前置工单:#62
  • 历史对照:#17、#18(仅从 explore 提取业务语义和测试证据,不迁移旧基础框架)
  • 并行:不可与后续 Bell 告警纵切任务并行;本工单先冻结 Event/Receipt 事实
  • 独立运行:Sense、Brain 不启动,以 Bell 内部合成入口验证

原始需求与变化

  • 来源:用户于 2026-08-29 确认 MVP #8 修复方案并要求建单。
  • 目的摘要:在当前 dev 的 Bell GoAdmin 基线上重建独立告警纵切,不能把 explore 旧框架整体合回;第一步建立不可变 Event、永久幂等 Receipt 和仅限开发测试的合成事件入口。
  • 变化原因:#17/#18 的历史实现只保留于 explore,#62 明确未迁移这些业务,当前 dev 无法完成 Bell MVP 验收。

目标

  1. 在 #62 的 Gin/GORM/PostgreSQL/JWT/Casbin 链路上建立 Bell 自有 Event 与永久幂等 Receipt。
  2. 以 (producer_id, source_event_id) 作为 Bell 内部入站幂等键;相同载荷重放返回同一 Event,不同载荷冲突拒绝且保留可定位审计。
  3. Event 创建后业务事实不可修改、不可删除;Receipt 不因 Event 生命周期或重启丢失。
  4. 提供仅限显式开发/测试配置启用的合成事件入口,生产配置默认关闭且直接访问不可用。
  5. 不信任 Sense/Brain token,不读取其他项目数据库、文件或秘密。

非目标

  • 不实现 Rule、Alert、ack、close、通知或跨项目事件契约。
  • 不修改 GoAdmin 认证/RBAC/会话基础,不复制 explore 的自研 HTTP/认证/前端外壳。
  • 不修改 Sense/**、Brain/**、contracts/**、根级构建/部署或本地 Wiki 镜像。
  • 不升级 goadmin-baseline.json 的上游 commit 或工具链。
  • 不提供真实生产者凭据或生产默认密码。

精确 write_paths

  • Bell/server/app/bell/event/**
  • Bell/server/app/bell/receipt/**
  • Bell/server/app/bell/synthetic/**
  • Bell/server/app/bell/router/event.go
  • Bell/server/app/bell/router/synthetic.go
  • Bell/server/app/bell/router/registry.go
  • Bell/server/cmd/api/server.go(仅一次接入 Bell 业务路由聚合器)
  • Bell/server/cmd/migrate/migration/version-local/*bell_event*
  • Bell/server/cmd/migrate/migration/version-local/init.go
  • Bell/server/tests/bell_event/**
  • Bell/scripts/test-event-synthetic.ps1

禁止写:Sense/**、Brain/**、contracts/**、docs/**、根级构建/部署配置,以及未列出的 Bell UI 路径。

GoAdmin 实施门禁

实施前必须读取冻结 go-admin-doc 的 Router、API、Models、DTO、Service、DB、migrate 主题,并在工单评论记录实际文件与采用方式;使用 #62 已继承的 Gin/GORM/中间件/响应/迁移链,不另建 HTTP、认证或数据库框架。

已确认技术设计

  • Event 保存业务入站快照、来源标识、发生/接收时间和内容摘要;创建后由数据库约束/触发器与服务层共同禁止 UPDATE/DELETE。
  • Receipt 保存幂等键、Event 标识和规范化载荷摘要;冲突必须返回稳定、可理解且不泄露内容的结果。
  • 合成入口使用独立配置开关与权限边界,生产默认值必须为关闭;关闭时路由不注册或返回稳定 404。
  • 所有审计不得记录 token、密码、完整敏感载荷或个人数据。
  • 不定义跨项目 wire contract;合成输入只是 Bell 项目内测试结构。

验收标准

  • 全新独立 PostgreSQL 可迁移并创建 Event/Receipt 约束。
  • 相同幂等键与相同载荷重复提交返回同一 Event,数据库只有一条 Event/Receipt。
  • 相同幂等键不同载荷被拒绝,不覆盖原 Event,并留下脱敏审计。
  • Event/Receipt 的 UPDATE/DELETE 被服务层及数据库边界拒绝,重启后仍可证明。
  • 合成入口在显式测试配置下可用,在生产默认配置下不可访问。
  • 未认证、越权、畸形和超限请求得到稳定响应,不泄露秘密。
  • Sense/Brain 未启动时完成全部验证,提交只包含授权的 Bell/** 路径。
  • 后续 Rule/Alert 可通过稳定的 Bell 内部服务/API 读取 Event,但本工单不创建 Alert。

验证

  • Go 1.26.5:go test ./...、go vet ./...、go build ./...
  • 独立 PostgreSQL:迁移、幂等并发、冲突、不可变触发器、重启恢复测试
  • 合成入口:启用/禁用、认证/RBAC、畸形输入与日志脱敏冒烟
  • python dev_scripts/harness.py check --strict
  • git diff --check 与写路径检查

风险与回退

  • 风险:幂等或不可变约束错误会制造重复/被改写事实;合成入口误开会扩大攻击面。
  • 控制:数据库唯一约束、事务、不可变触发器、生产默认关闭和直接访问测试。
  • 回退:关闭合成入口与业务路由并回退任务分支;已经写入的 Event/Receipt 不删除、不改写,数据修正另建高风险迁移工单。

设计与文档影响

  • 非 UI 任务,采用上述 API/数据/状态设计作为原型替代证据。
  • 长期事实影响 Bell 数据模型、业务规则和本地测试方法;完成时列出需更新的 Wiki 页面,由拥有共享文档路径的协调 agent 更新并同步镜像,本工单不直接写 docs/**。
## 状态 待实施 ## 基本信息 - 类型:需求 / 单项目 - 主项目:Bell - 主 agent:Bell agent - 所属 Epic:#7 - 所属 MVP:#8 - 前置工单:#62 - 历史对照:#17、#18(仅从 `explore` 提取业务语义和测试证据,不迁移旧基础框架) - 并行:不可与后续 Bell 告警纵切任务并行;本工单先冻结 Event/Receipt 事实 - 独立运行:Sense、Brain 不启动,以 Bell 内部合成入口验证 ## 原始需求与变化 - 来源:用户于 2026-08-29 确认 MVP #8 修复方案并要求建单。 - 目的摘要:在当前 `dev` 的 Bell GoAdmin 基线上重建独立告警纵切,不能把 `explore` 旧框架整体合回;第一步建立不可变 Event、永久幂等 Receipt 和仅限开发测试的合成事件入口。 - 变化原因:#17/#18 的历史实现只保留于 `explore`,#62 明确未迁移这些业务,当前 `dev` 无法完成 Bell MVP 验收。 ## 目标 1. 在 #62 的 Gin/GORM/PostgreSQL/JWT/Casbin 链路上建立 Bell 自有 Event 与永久幂等 Receipt。 2. 以 `(producer_id, source_event_id)` 作为 Bell 内部入站幂等键;相同载荷重放返回同一 Event,不同载荷冲突拒绝且保留可定位审计。 3. Event 创建后业务事实不可修改、不可删除;Receipt 不因 Event 生命周期或重启丢失。 4. 提供仅限显式开发/测试配置启用的合成事件入口,生产配置默认关闭且直接访问不可用。 5. 不信任 Sense/Brain token,不读取其他项目数据库、文件或秘密。 ## 非目标 - 不实现 Rule、Alert、ack、close、通知或跨项目事件契约。 - 不修改 GoAdmin 认证/RBAC/会话基础,不复制 `explore` 的自研 HTTP/认证/前端外壳。 - 不修改 `Sense/**`、`Brain/**`、`contracts/**`、根级构建/部署或本地 Wiki 镜像。 - 不升级 `goadmin-baseline.json` 的上游 commit 或工具链。 - 不提供真实生产者凭据或生产默认密码。 ## 精确 write_paths - `Bell/server/app/bell/event/**` - `Bell/server/app/bell/receipt/**` - `Bell/server/app/bell/synthetic/**` - `Bell/server/app/bell/router/event.go` - `Bell/server/app/bell/router/synthetic.go` - `Bell/server/app/bell/router/registry.go` - `Bell/server/cmd/api/server.go`(仅一次接入 Bell 业务路由聚合器) - `Bell/server/cmd/migrate/migration/version-local/*bell_event*` - `Bell/server/cmd/migrate/migration/version-local/init.go` - `Bell/server/tests/bell_event/**` - `Bell/scripts/test-event-synthetic.ps1` 禁止写:`Sense/**`、`Brain/**`、`contracts/**`、`docs/**`、根级构建/部署配置,以及未列出的 Bell UI 路径。 ## GoAdmin 实施门禁 实施前必须读取冻结 go-admin-doc 的 Router、API、Models、DTO、Service、DB、migrate 主题,并在工单评论记录实际文件与采用方式;使用 #62 已继承的 Gin/GORM/中间件/响应/迁移链,不另建 HTTP、认证或数据库框架。 ## 已确认技术设计 - Event 保存业务入站快照、来源标识、发生/接收时间和内容摘要;创建后由数据库约束/触发器与服务层共同禁止 UPDATE/DELETE。 - Receipt 保存幂等键、Event 标识和规范化载荷摘要;冲突必须返回稳定、可理解且不泄露内容的结果。 - 合成入口使用独立配置开关与权限边界,生产默认值必须为关闭;关闭时路由不注册或返回稳定 404。 - 所有审计不得记录 token、密码、完整敏感载荷或个人数据。 - 不定义跨项目 wire contract;合成输入只是 Bell 项目内测试结构。 ## 验收标准 - [ ] 全新独立 PostgreSQL 可迁移并创建 Event/Receipt 约束。 - [ ] 相同幂等键与相同载荷重复提交返回同一 Event,数据库只有一条 Event/Receipt。 - [ ] 相同幂等键不同载荷被拒绝,不覆盖原 Event,并留下脱敏审计。 - [ ] Event/Receipt 的 UPDATE/DELETE 被服务层及数据库边界拒绝,重启后仍可证明。 - [ ] 合成入口在显式测试配置下可用,在生产默认配置下不可访问。 - [ ] 未认证、越权、畸形和超限请求得到稳定响应,不泄露秘密。 - [ ] Sense/Brain 未启动时完成全部验证,提交只包含授权的 `Bell/**` 路径。 - [ ] 后续 Rule/Alert 可通过稳定的 Bell 内部服务/API 读取 Event,但本工单不创建 Alert。 ## 验证 - Go 1.26.5:`go test ./...`、`go vet ./...`、`go build ./...` - 独立 PostgreSQL:迁移、幂等并发、冲突、不可变触发器、重启恢复测试 - 合成入口:启用/禁用、认证/RBAC、畸形输入与日志脱敏冒烟 - `python dev_scripts/harness.py check --strict` - `git diff --check` 与写路径检查 ## 风险与回退 - 风险:幂等或不可变约束错误会制造重复/被改写事实;合成入口误开会扩大攻击面。 - 控制:数据库唯一约束、事务、不可变触发器、生产默认关闭和直接访问测试。 - 回退:关闭合成入口与业务路由并回退任务分支;已经写入的 Event/Receipt 不删除、不改写,数据修正另建高风险迁移工单。 ## 设计与文档影响 - 非 UI 任务,采用上述 API/数据/状态设计作为原型替代证据。 - 长期事实影响 Bell 数据模型、业务规则和本地测试方法;完成时列出需更新的 Wiki 页面,由拥有共享文档路径的协调 agent 更新并同步镜像,本工单不直接写 `docs/**`。
ila added the kind/taskproject/bellscope/independentpriority/p0 labels 2026-08-29 08:43:41 +08:00
Author
Owner

状态:进行中(2026-08-29)

前置 #62 已关闭并通过用户验收;当前 dev 与 origin/dev 均为 96bd4ad2c8c5f010a0caa1746154471dd0d031cc,工作区 clean。任务分支:feature/131-bell-event-receipt。

已核对冻结来源 HEAD:

  • go-admin f06540883b41d03782bb6b2c4150f298f328c6b6
  • go-admin-ui 67d393d713877572fab0b897296a4c1d525fc81d
  • go-admin-doc 424855aacf6905f3fde860c3331385cb25529a0d

已读取 go-admin-doc:cmd/migrate、Router、API、Models、DTO、Service、DB。采用方式:业务路由沿用 Gin + JWT + Casbin 中间件链;请求使用 API/DTO 绑定与统一响应;持久化使用 GORM/PostgreSQL;新迁移只写 version-local,不修改冻结上游迁移。不会新建 HTTP、认证、RBAC 或数据库框架。

写路径严格限定为 #131 列出的 Bell/**;Sense、Brain、contracts、docs 和 UI 不写。

## 状态:进行中(2026-08-29) 前置 #62 已关闭并通过用户验收;当前 `dev` 与 `origin/dev` 均为 `96bd4ad2c8c5f010a0caa1746154471dd0d031cc`,工作区 clean。任务分支:`feature/131-bell-event-receipt`。 已核对冻结来源 HEAD: - go-admin `f06540883b41d03782bb6b2c4150f298f328c6b6` - go-admin-ui `67d393d713877572fab0b897296a4c1d525fc81d` - go-admin-doc `424855aacf6905f3fde860c3331385cb25529a0d` 已读取 go-admin-doc:`cmd/migrate`、Router、API、Models、DTO、Service、DB。采用方式:业务路由沿用 Gin + JWT + Casbin 中间件链;请求使用 API/DTO 绑定与统一响应;持久化使用 GORM/PostgreSQL;新迁移只写 `version-local`,不修改冻结上游迁移。不会新建 HTTP、认证、RBAC 或数据库框架。 写路径严格限定为 #131 列出的 `Bell/**`;Sense、Brain、contracts、docs 和 UI 不写。
Author
Owner

状态:待验收(2026-08-29)

#131 已按确认范围完成并经 PR 合入 dev。

最终差异

  • 新增 Bell 自有不可变 Event、永久幂等 Receipt 与追加式 IngestAudit;不嵌入 GoAdmin 可更新/软删除模型。
  • 以 (producer_id, source_event_id)、规范化载荷 SHA-256、PostgreSQL transaction advisory lock 和唯一索引实现并发幂等。
  • 同载荷重放返回原 Event;不同载荷返回稳定 409,原事实不覆盖,并另行提交只含标识、摘要、结果和操作者的冲突审计。
  • PostgreSQL 迁移增加 Event/Receipt 外键、严重度约束,以及 Event、Receipt、审计表的 UPDATE/DELETE 拒绝触发器;服务层不暴露更新或删除入口。
  • 新增受 GoAdmin JWT 保护的 GET /api/v1/bell/events/:id;新增仅管理员可用的 POST /api/v1/bell/synthetic-events。
  • 合成入口要求非生产模式且 BELL_SYNTHETIC_EVENTS_ENABLED=true/1;prod/production 即使显式开关仍不注册路由。
  • 合成请求在进入 GoAdmin 通用操作日志前替换为固定脱敏标记,真实请求体仅在当前请求上下文短暂传递;审计不保存 token、密码或完整事件载荷。
  • 未启动或依赖 Sense、Brain,未定义跨项目 wire contract。

验证证据

  • GOTOOLCHAIN=go1.26.5 go test ./...:通过。
  • GOTOOLCHAIN=go1.26.5 go vet ./...:通过。
  • GOTOOLCHAIN=go1.26.5 go build ./...:通过。
  • pwsh -NoProfile -File .\scripts\test-event-synthetic.ps1 -Verbose:通过,输出:
    BELL_131_SMOKE events=2 receipts=2 concurrent=12 audit=redacted immutable=true restart=true production_synthetic=404
  • 集成覆盖:全新隔离 PostgreSQL 17 迁移;12 路并发同键收敛为一个 Event/Receipt;同载荷重放;异载荷冲突;畸形/超限输入;未认证;管理员权限辅助测试;GoAdmin 操作日志无完整载荷;数据库 UPDATE/DELETE 被拒;重启后读取;生产路由 HTTP 404。
  • python dev_scripts/harness.py check --strict:通过。
  • git diff --check:通过。
  • 写路径检查与敏感信息扫描:通过;提交仅含 #131 授权的 Bell/**。

提交与合并

  • 实现提交:8f7d91310b7d86d521a710a884f7470607431b77
  • PR:#135
  • dev 合并提交:689de560bb0d8928de77dd5ed2cae9ead581e3ef
  • Gitea MCP 合并调用返回空正文并报告解析错误;随后通过 MCP 回读确认 PR 已成功合并,未重复调用。

文档影响与未验证项

  • 长期事实影响 Bell 数据模型、业务规则、API 和本地验收方法。按工单写路径约束,本任务未修改 Wiki/镜像;需由后续拥有共享文档路径的协调工单更新对应 Bell Wiki 并同步 docs/。
  • 无生产数据迁移、真实生产者或外部通知验证(均不在本工单范围)。

工单保持 open,等待用户验收;未关闭 #131,未合入 main。

## 状态:待验收(2026-08-29) #131 已按确认范围完成并经 PR 合入 `dev`。 ### 最终差异 - 新增 Bell 自有不可变 `Event`、永久幂等 `Receipt` 与追加式 `IngestAudit`;不嵌入 GoAdmin 可更新/软删除模型。 - 以 `(producer_id, source_event_id)`、规范化载荷 SHA-256、PostgreSQL transaction advisory lock 和唯一索引实现并发幂等。 - 同载荷重放返回原 Event;不同载荷返回稳定 409,原事实不覆盖,并另行提交只含标识、摘要、结果和操作者的冲突审计。 - PostgreSQL 迁移增加 Event/Receipt 外键、严重度约束,以及 Event、Receipt、审计表的 UPDATE/DELETE 拒绝触发器;服务层不暴露更新或删除入口。 - 新增受 GoAdmin JWT 保护的 `GET /api/v1/bell/events/:id`;新增仅管理员可用的 `POST /api/v1/bell/synthetic-events`。 - 合成入口要求非生产模式且 `BELL_SYNTHETIC_EVENTS_ENABLED=true/1`;`prod/production` 即使显式开关仍不注册路由。 - 合成请求在进入 GoAdmin 通用操作日志前替换为固定脱敏标记,真实请求体仅在当前请求上下文短暂传递;审计不保存 token、密码或完整事件载荷。 - 未启动或依赖 Sense、Brain,未定义跨项目 wire contract。 ### 验证证据 - `GOTOOLCHAIN=go1.26.5 go test ./...`:通过。 - `GOTOOLCHAIN=go1.26.5 go vet ./...`:通过。 - `GOTOOLCHAIN=go1.26.5 go build ./...`:通过。 - `pwsh -NoProfile -File .\scripts\test-event-synthetic.ps1 -Verbose`:通过,输出: `BELL_131_SMOKE events=2 receipts=2 concurrent=12 audit=redacted immutable=true restart=true production_synthetic=404` - 集成覆盖:全新隔离 PostgreSQL 17 迁移;12 路并发同键收敛为一个 Event/Receipt;同载荷重放;异载荷冲突;畸形/超限输入;未认证;管理员权限辅助测试;GoAdmin 操作日志无完整载荷;数据库 UPDATE/DELETE 被拒;重启后读取;生产路由 HTTP 404。 - `python dev_scripts/harness.py check --strict`:通过。 - `git diff --check`:通过。 - 写路径检查与敏感信息扫描:通过;提交仅含 #131 授权的 `Bell/**`。 ### 提交与合并 - 实现提交:`8f7d91310b7d86d521a710a884f7470607431b77` - PR:#135 - `dev` 合并提交:`689de560bb0d8928de77dd5ed2cae9ead581e3ef` - Gitea MCP 合并调用返回空正文并报告解析错误;随后通过 MCP 回读确认 PR 已成功合并,未重复调用。 ### 文档影响与未验证项 - 长期事实影响 Bell 数据模型、业务规则、API 和本地验收方法。按工单写路径约束,本任务未修改 Wiki/镜像;需由后续拥有共享文档路径的协调工单更新对应 Bell Wiki 并同步 `docs/`。 - 无生产数据迁移、真实生产者或外部通知验证(均不在本工单范围)。 工单保持 open,等待用户验收;未关闭 #131,未合入 `main`。
Author
Owner

验收结论:通过

  • 用户于 2026-08-29 09:18:52 +08:00 明确确认“#131通过验收”。
  • 验收基线:dev@689de560bb0d8928de77dd5ed2cae9ead581e3ef(PR #135)。
  • 结论:#131 已完成,关闭单元工单。
  • 本次仅回写验收与父工单进度;未执行 dev → main,未创建任务归档。
  • Bell 长期 Wiki 更新仍按共享文档协调边界另行处理,本次不直接修改 Wiki 或 docs/**。
## 验收结论:通过 - 用户于 2026-08-29 09:18:52 +08:00 明确确认“#131通过验收”。 - 验收基线:`dev@689de560bb0d8928de77dd5ed2cae9ead581e3ef`(PR #135)。 - 结论:#131 已完成,关闭单元工单。 - 本次仅回写验收与父工单进度;未执行 `dev → main`,未创建任务归档。 - Bell 长期 Wiki 更新仍按共享文档协调边界另行处理,本次不直接修改 Wiki 或 `docs/**`。
ila closed this issue 2026-08-29 09:19:02 +08:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: ila/yovision#131