支柱八 · 事件:总线、outbox 与 webhook
上级:key-designs
状态: 已在 v0.1.76 发布(2026-09-27)—— 设计与落地记录见 StandMeet 仓库的 docs/design/event-bus-outbox-webhooks.md。
StandMeet 里每一个"写完 X 顺手做 Y"过去都是在调用处手接的:和调用处耦合、不持久(重启即丢)、坏了看不见。这根支柱给它们一条路:事件和它描述的变更在同一个事务里提交(outbox),由 relay 扇出成现有 Postgres 上的持久任务,进程内由订阅方消费,出实例由签名的 webhook 投递。让 standmeet.com 跟上语料的 embed 更新 hook,就是它的一个消费者。
子节点
模型
- event-model —— 事件 = 字符串类型 + JSON,以数据形式只声明一次;
Exposure默认 internal;已声明 39 个类型。 - two-sources-of-events —— 行事实由数据库触发器捕获;语义事实显式记录。
- relay-claims-rows-not-cursor —— 每个进程里的 relay 循环用
SKIP LOCKED领取未扇出的行;按序号游标会丢事件;合并由每个订阅自行选择。 - queue-behind-ports ——
Recorder,以及Jobs/Inspector/Runtime;现在是 River,换实现上层不感知。 - code-structure —— 包布局、事务以显式参数到达用例(不进 ctx)、订阅方零胶水。
- why-not-a-broker —— 为什么不用 Kafka、RabbitMQ 或 Redis/Bull。
对外
- webhooks —— thin、签名(Standard Webhooks)、由唯一的 ACL 判定限定范围、每个端点同时只有一次投递。
- embed-update-hook —— 语料变了告诉它的 embed;standmeet.com 如何不重新部署就跟上。
异步之后的行为
- async-response-contract —— 响应只承诺已提交的事,其余给回执。
- completion-hooks —— 任务终态发一条通知;在等结果的四个调用方。
- message-loss-guarantees —— 每一跳都有保证,不存在静默丢失。
- retry-has-one-owner —— 任务层负责重试,handler 只分类失败。
- concurrency-control —— 有上限、有超时、能停下的 worker;事务里不发网络请求。
- storage-bounds —— 每种存储失控都有硬上限且看得见。
- saturation-degrades-gracefully —— 饱和时:慢下来、排队、告警。
- tasks-panel —— 队列、周期任务、事件流、投递日志在后台可见。
守住它,以及怎么到达
- no-bypass-by-structure —— 请求路径拿不到副作用能力;七条门禁守住它。
- consolidation-inventory —— 扫出的全部 101 项及各自落到哪里。
- events-test-plan —— 已有的 UT 套件和 11 个新 e2e spec、回归,以及最终全绿验收。
- events-roadmap —— P0–P5 分期及其状态,以及 2026-09-26 的决定。
相关支柱:structure(它扩展的分层与护栏)、monitor(任务面板取代了它的内存任务列表)、embed-credential-never-carries-the-code(更新 hook 挂在这个 embed 上)。