diff --git a/docs/02-requirements.md b/docs/02-requirements.md index f0b67e5..8a199b0 100644 --- a/docs/02-requirements.md +++ b/docs/02-requirements.md @@ -54,10 +54,13 @@ - 预警必须有 ack;未 ack 自动升级,进程重启后能续跑。 - 升级链、超时、联系人和时段可按租户/站点配置。 +- 联系人与值班排班必须统一设计并共享人员、值班组和已验证通知通道主数据,但分对象、分版本管理:联系人不承载轮换字段,排班不复制手机号;升级步骤通过类型化目标引用指定人员、值班组或排班计划,不写死号码。 +- 值班排班至少覆盖站点时区、周轮换、生效日期、临时替班、空档/重叠冲突检查、当前与未来值班人预览、版本发布和审计。每次投递创建时解析当时生效的排班版本,并固化实际收件人、通道与解析版本快照;后续修改不得改写历史投递事实。 - 至少两条独立投递路径,其中一条可绕过互联网。 - 区分已发出、已送达、已看到;没有回执不能当成功。 - Alert 与 Event 保持可导航的多对多关系;被规则抑制且没有创建 Alert 的 Event 不伪装为已投递。 - 班次交接覆盖未 ack、处置中与升级中的 Alert;接班确认留痕,交接过程不暂停或重置升级链。 +- 交接班只显式转移进行中 Alert 的处置责任,不静默修改未来排班;未来班次替换通过排班临时替班并发布新版本完成。 - 静默必须限时且自动恢复,单次不超过 4 小时,无永久静默。 - 业务预警与运维告警使用不同通道和值班配置。 diff --git a/docs/04-architecture.md b/docs/04-architecture.md index ad2c8a6..48e2946 100644 --- a/docs/04-architecture.md +++ b/docs/04-architecture.md @@ -89,12 +89,15 @@ Sense ── 视频流/触发信号 ──> Brain - 高风险设备操作在本地事务内同时写期望态与审计 outbox;异步 relay 可重试、幂等投递到 Bell。T-004 只验证交互归属,不定义或实现接口契约。 - Brain 投递失败落本地队列重试,不阻塞实时推理主链路。 - Alert 先落库再投递,进程重启恢复未完成升级链。 +- 值班排班发布前必须按 Site 时区校验班次空档、重叠、联系人停用和通道验证;排班以新版本和未来生效时间发布,不原地改写历史。交接班是进行中 Alert 的显式责任转移事件,不替代排班版本变更。 - 事件证据技术默认保留 30 天并按生命周期删除;客户/法务在 M3 生产上线前确认法规适用性和最终期限,技术默认值不能覆盖其结论。 ## 8. 数据与契约 - Bell 核心实体:Tenant → Site → Area(含 `capture_policy`)以及 Role/Binding/Quota/Audit;Sense 核心实体:Device(含 `modality + capabilities`)→ StreamBinding/Zone,以及带 `source_version`/`synced_at` 的 SiteQuota/AreaPolicyProjection。两个 schema 以稳定逻辑 ID 关联,不跨 schema 写入。 - 业务实体:Rule → Event → Alert → DeliveryAttempt/Ack;Event 与 Alert 不合并。 +- Bell 通知域分为三个聚合:Contact/Team 保存身份、成员关系和已验证通道;OnCallSchedule/ScheduleVersion/ShiftException 保存时区、轮换与例外;EscalationPolicy/Step 通过 `person / team / on_call_schedule` 类型化 `target_ref` 引用目标。三者共享逻辑 ID,不复制手机号、班次或轮换字段。 +- 每个 DeliveryAttempt 创建时解析当时生效的排班版本,并保存实际收件人、通道、`schedule_version` 和解析时间快照;之后联系人或排班修改不得回写既有投递事实。 - 一个事件可触发多次预警与投递,一次预警也可聚合多个事件。 - 事件 v0.1 以 `raw/contracts/event-v0.1.schema.json` 与 `raw/contracts/README.md` 为准;未知顶层字段拒绝,只允许通过 `ext` 扩展。 - v0.1 还需代码校验时间自洽、`confidence` 当前为 null、证据文件名隐私、唯一 primary sensor 等跨字段约束。 diff --git a/docs/07-user-stories.md b/docs/07-user-stories.md index a3c2827..6c21574 100644 --- a/docs/07-user-stories.md +++ b/docs/07-user-stories.md @@ -37,9 +37,9 @@ ## US-005 配置规则与升级链 - 角色:租户管理员/站点管理员。 -- 目标:按站点和设备覆盖场景模板,配置区域、时段、持续时间和联系人升级链。 +- 目标:按站点和设备覆盖场景模板,配置区域、时段、持续时间和升级链;升级步骤引用指定人员、值班组或值班排班,不直接写死手机号。 - 价值:同一通用底座适配不同场景。 -- 验收:继承来源清楚、变更可试运行;回滚先展示版本差异与影响,并创建新的不可变版本,不改写历史;静默不超过 4 小时且自动恢复。 +- 验收:继承来源清楚、变更可试运行;升级目标可预览当前解析人和通道,投递后保留解析快照;回滚先展示版本差异与影响,并创建新的不可变版本,不改写历史;静默不超过 4 小时且自动恢复。 - 关联:RQ-C-11~RQ-C-15、RQ-C-23~RQ-C-28,IX-010~IX-012。 ## US-006 事件最小权限查看 @@ -98,6 +98,14 @@ - 验收:报表展示规则版本、样本时间窗、正样本/漏检样本、通道天数、召回率和每路每天误报数;明确不提供跨场景统一准确率;导出保留筛选与口径说明。 - 关联:RQ-C-22、`02-requirements` §8,IX-022。 +## US-013 管理联系人和值班排班 + +- 角色:租户管理员/站点管理员。 +- 目标:使用同一套人员、值班组和通知通道主数据配置可发布的值班排班,并让升级策略引用排班目标。 +- 价值:避免先把联系人和号码写死进升级链、后续再迁移到时段轮换;同时避免把联系人、班次和轮换混成一个难维护对象。 +- 验收:联系人维护身份、角色、值班组和已验证通道,不出现排班轮换字段;排班维护时区、班次、周轮换、生效日期、临时替班和版本;发布前发现空档/重叠并阻止发布,可预览当前及未来值班人;投递固化收件人、通道与排班版本快照;交接进行中 Alert 不静默修改未来排班。 +- 关联:RQ-C-24~RQ-C-27、RQ-C-33,IX-012、IX-023。 + ## 追溯规则 新增 P0 UI 任务必须引用至少一个 US 和一个 IX;若没有 UI,任务文件明确写“不适用”。需求变化先更新用户故事和交互清单,再改页面。 diff --git a/docs/08-interaction-checklist.md b/docs/08-interaction-checklist.md index 480282d..2183b1e 100644 --- a/docs/08-interaction-checklist.md +++ b/docs/08-interaction-checklist.md @@ -15,7 +15,7 @@ | IX-009 | 误报反馈 | 确认动作、可选原因、提交成功反馈;只改变 outcome,不改原始事件 | US-004 | M3 | | IX-010 | 规则编辑 | 显示租户/站点/设备继承来源,支持区域/警戒线/时段/持续时间 | US-005 | M3/M4 | | IX-011 | 规则试运行与回滚 | 明确“未正式生效”,展示命中样本与影响范围,支持取消;回滚前展示目标版本差异与影响,确认后创建并发布等价的新版本,历史版本保持不可变;版本冲突时阻止覆盖并提供刷新/另存路径 | US-005 | M4 | -| IX-012 | 升级链/静默 | 联系人顺序、超时、双通道;静默最长 4h、显示自动恢复时间、无永久选项 | US-005 | M3/M4 | +| IX-012 | 升级链/静默 | 升级步骤通过类型化目标引用指定人员、值班组或值班排班,不写死号码;显示目标解析预览、联系人顺序、超时与双通道;每次投递固化实际收件人、通道和排班版本快照;静默最长 4h、显示自动恢复时间、无永久选项 | US-005、US-013 | M3/M4 | | IX-013 | 权限与隐私 | 越权统一处理;无授权租户不展示人脸入口;不泄露流 URL/凭据 | US-006 | M3/M4 | | IX-014 | 设备模态与能力 | 一级入口为“设备”;列表可按 `modality` 筛选,添加时先选模态,详情按 `capabilities` 渐进展示;能力同时显示厂商/型号/固件/认证、探测来源与时间、探测值和生效值差异;视频设备显示画面/媒体/检测区域,未交付的非视频适配器显示 `adapter_not_ready`,不用虚构遥测或禁用的视频页签占位 | US-008 | M2/M6 | | IX-015 | 停用与收敛 | 明确区分暂停推理订阅、停用设备接入和仅踢当前会话;暂停推理必须说明“解除推理侧订阅”,并在结果中显示推理订阅、其他 reader 数与上游按需拉流状态;操作前展示对观看、录制与证据回捞的影响并二次确认;期望态立即改变、实际态经对账收敛,部分失败可逐项重试;重复请求不产生重复副作用,但每次请求均留审计结果 | US-001、US-002 | M2 | @@ -26,6 +26,7 @@ | IX-020 | 管理上下文、RBAC 与审计归属 | 全局头部显示租户、站点、账号和角色;只读角色隐藏写操作,深链越权统一拒绝且不泄露资源是否存在;Tenant/Site/Area/RBAC/配额/全局审计由 Bell 管理,Sense 只呈现消费上下文和设备操作入口,携带 tenant/site/device/return_to 深链到 Bell 审计;Bell 移动端底部导航不超过 5 项,并通过可发现的“管理”入口访问 Site/Area 与审计 | US-006、US-009、US-010 | M2/M4 | | IX-021 | 值班交接 | 清单覆盖未 ack、处置中和升级中的 Alert,显示交班人、接班人、备注及下一次升级时间;接班确认写审计,交接期间不暂停或重置升级链,未确认时不转移责任 | US-011 | M3 | | IX-022 | 规则验收报表 | 按规则版本与冻结样本窗口展示召回率、每路每天误报数和计算样本量;支持保留口径的导出;不提供跨场景统一准确率 | US-012 | M4 | +| IX-023 | 联系人与值班排班 | 在“升级链”内部以升级策略、值班与排班、联系人和通道三个二级模块统一设计;联系人与排班共享人员/值班组/已验证通道主数据但分对象维护;排班覆盖站点时区、周轮换、生效日期、临时替班、空档/重叠冲突、当前/未来值班人预览和版本发布审计;交接班只转移进行中 Alert,不暗改未来排班 | US-005、US-011、US-013 | M3/M4 | ## 全局状态 diff --git a/docs/design/bell/index.html b/docs/design/bell/index.html index 75ef0ef..0fb16cc 100644 --- a/docs/design/bell/index.html +++ b/docs/design/bell/index.html @@ -206,11 +206,35 @@ .version-diff { display: grid; gap: 8px; } .version-diff article { padding: 10px 12px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface-2); } .version-diff article strong { display: block; } + .chain-subnav { margin-bottom: 12px; padding: 4px; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 4px; border: 1px solid var(--line); border-radius: 11px; background: var(--surface); } + .chain-subnav button { min-height: 44px; border: 0; border-radius: 8px; background: transparent; color: var(--muted); font-weight: 750; } + .chain-subnav button.active { background: var(--primary-soft); color: var(--text); box-shadow: inset 0 0 0 1px rgba(139,124,246,.36); } + .chain-panel { display: none; } + .chain-panel.active { display: block; } .chain-grid { grid-template-columns: minmax(0, 1.4fr) minmax(300px, .8fr); } .chain-row { padding: 13px 14px; display: grid; grid-template-columns: 40px 1fr auto; gap: 11px; align-items: center; border-bottom: 1px solid var(--line); } .chain-row:last-child { border-bottom: 0; } .chain-num { width: 32px; height: 32px; display: grid; place-items: center; border-radius: 50%; background: var(--primary-soft); color: #cfc8ff; font-weight: 800; } .chain-row small { color: var(--muted); } + .target-ref { display: inline-block; margin-top: 3px; color: #b8e5ff; font: 12px/1.4 ui-monospace, SFMono-Regular, Consolas, monospace; } + .resolve-card { padding: 14px; } + .resolve-card h2 { margin: 0 0 4px; font-size: 15px; } + .resolve-card > p { margin: 0 0 12px; color: var(--muted); } + .resolve-list { display: grid; gap: 8px; } + .resolve-item { padding: 10px 11px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface-2); } + .resolve-item span, .resolve-item small { display: block; color: var(--muted); } + .resolve-item strong { display: block; margin: 2px 0; } + .roster-week { padding: 12px; display: grid; grid-template-columns: repeat(7, minmax(125px, 1fr)); gap: 8px; overflow-x: auto; } + .roster-day { min-width: 125px; padding: 10px; border: 1px solid var(--line); border-radius: 9px; background: var(--surface-2); } + .roster-day.current { border-color: var(--primary); background: var(--primary-soft); } + .roster-day > strong { display: block; margin-bottom: 8px; } + .shift-slot { padding: 8px 0; border-top: 1px solid var(--line); } + .shift-slot:first-of-type { border-top: 0; } + .shift-slot span, .shift-slot small { display: block; color: var(--muted); font-size: 12px; } + .shift-slot strong { display: block; margin: 2px 0; font-size: 13px; } + .object-note { padding: 11px 14px; border-top: 1px solid var(--line); color: var(--muted); } + .contact-summary { grid-template-columns: repeat(3, minmax(0, 1fr)); margin-bottom: 12px; } + .contact-summary .stat { min-height: 96px; } .chart-grid { grid-template-columns: 1.35fr .65fr; } .chart { padding: 16px; } .chart h2 { margin: 0; font-size: 15px; } @@ -233,7 +257,7 @@ .skeleton i:nth-child(2) { width: 72%; } @keyframes shimmer { to { background-position: -200% 0; } } dialog { width: min(610px, calc(100% - 28px)); max-height: 88dvh; padding: 0; border: 1px solid var(--line); border-radius: 16px; background: var(--surface); color: var(--text); box-shadow: 0 24px 80px rgba(0,0,0,.5); } - #ruleDialog, #eventDialog, #handoverDialog, #rollbackDialog { width: min(760px, calc(100% - 28px)); } + #ruleDialog, #eventDialog, #handoverDialog, #rollbackDialog, #escalationDialog, #scheduleDialog, #substituteDialog, #contactDialog { width: min(760px, calc(100% - 28px)); } dialog::backdrop { background: rgba(4,7,15,.68); backdrop-filter: blur(4px); } .dialog-head, .dialog-foot { padding: 14px 18px; border-bottom: 1px solid var(--line); display: flex; align-items: center; justify-content: space-between; gap: 10px; } .dialog-head h2 { margin: 0; font-size: 17px; } @@ -277,6 +301,7 @@ .disposition { border-left: 0; border-top: 1px solid var(--line); } .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); } .site-grid { grid-template-columns: 1fr; } + .roster-week { grid-template-columns: repeat(2, minmax(145px, 1fr)); } .rule-grid { grid-template-columns: 1fr 1fr; } .fact-grid { grid-template-columns: repeat(2, 1fr); } .pager { align-items: flex-start; flex-direction: column; } @@ -287,6 +312,9 @@ @media (max-width: 560px) { .page-head { display: grid; } .stats, .rule-grid { grid-template-columns: 1fr; } + .chain-subnav { grid-template-columns: 1fr; } + .contact-summary { grid-template-columns: 1fr; } + .roster-week { grid-template-columns: 1fr; } .form-grid { grid-template-columns: 1fr; } .form-field.full { grid-column: auto; } .video-stage { margin-inline: 8px; } @@ -414,12 +442,37 @@
-

升级链

生产前至少两条独立路径;无回执不能当作成功。

-

校园高危事件 · 默认链

已发布 v4
-
1
值班室 Web + 本地声光立即 · 站点局域网内
主路径
-
2
当班值班员短信立即 · 送达后等待 2 分钟
独立路径
-
3
校级负责人语音未 ack 时升级 · 等待 3 分钟
兜底
-

静默规则

无永久选项

静默仅影响选定规则和点位,到时自动恢复;S1 事件不可静默。

+

升级链

联系人、值班排班和升级策略统一设计、分对象管理;策略引用动态目标,不写死手机号。

当前排班覆盖完整
+
+ +
+

校园高危事件 · 默认链

每一步引用类型化目标,解析后才创建投递
已发布 v4
+
1
值班室 Web + 本地声光立即 · 站点局域网内team:DUTY-ROOM
固定值班组
+
2
当前排班值班员 · 短信立即 · 送达后等待 2 分钟on_call_schedule:SCH-CAMPUS-SECURITY@v12
动态排班
+
3
校级负责人 · 语音未 ack 时升级 · 等待 3 分钟person:USR-SCHOOL-LEAD
指定人员
+
升级策略只保存目标引用和通道偏好,不复制联系人号码或轮换字段。
+

目标解析预览

事件时间 2026-08-04 23:14 · Asia/Shanghai
排班目标校园安保值班表 · v12SCH-CAMPUS-SECURITY
当前解析结果王值班员 · 晚班短信已验证 · 语音已验证
投递快照23:14:13 已固化收件人、通道、排班 v12;后续编辑不改写本次事实
+

解析与版本规则

不可变历史

每次投递创建时按站点时区解析当时生效的排班版本,并保存实际收件人、通道与版本快照。未来排班版本只影响其生效时间后的新投递。

静默规则

无永久选项

静默仅影响选定规则和点位,到时自动恢复;S1 事件不可静默。

+
+ +
+
当前排班v12已发布 · 08-01 生效
站点时区Asia/Shanghai跨午夜班次按站点时间
当前值班王值班员晚班 · 至明日 08:00
未来 14 天覆盖100%0 空档 · 0 重叠
+

校园安保值班表

周轮换 · 白班 08:00–20:00 / 晚班 20:00–08:00
+
今天 · 周二
白班林值班员08:00–20:00
晚班王值班员20:00–08:00
+
周三
白班赵值班员08:00–20:00
晚班周值班员20:00–08:00
+
周四
白班林值班员08:00–20:00
晚班王值班员20:00–08:00
+
周五
白班赵值班员08:00–20:00
晚班周值班员20:00–08:00
+
周六
白班林值班员08:00–20:00
晚班王值班员20:00–08:00
+
周日
白班赵值班员08:00–20:00
晚班周值班员20:00–08:00
+
下周一
白班林值班员08:00–20:00
晚班王值班员20:00–08:00
+
边界:临时替班进入新排班草稿并经发布后影响未来班次;值班交接只转移进行中 Alert 的责任,不会暗改这里的轮换。
+

版本与例外

全量审计
版本生效时间变更状态发布人
v122026-08-01 00:00暑期周轮换当前生效林工
v112026-07-01 00:00赵值班员加入白班组历史周管理员
+
+ +
+
联系人64 名值班员 · 2 名负责人
已验证通道11 / 121 个语音号码待验证
被排班引用4删除前必须解除引用
+

联系人和通知通道

只维护身份、角色、值班组和通道;班次与轮换在排班模块维护
联系人角色值班组通知通道排班引用状态操作
王值班员
USR-DUTY-WANG
值班员校园安保组短信 ✓ · 语音 ✓ · Web ✓SCH-CAMPUS-SECURITY可用
林值班员
USR-DUTY-LIN
值班员校园安保组短信 ✓ · Web ✓SCH-CAMPUS-SECURITY可用
校级负责人
USR-SCHOOL-LEAD
站点负责人校级负责人组短信 ✓ · 语音待验证升级策略 v4部分可用
联系人通道变更只影响后续新投递;已创建投递保留当时的收件人和通道快照。联系人被排班或策略引用时不能直接删除。
+
@@ -471,9 +524,17 @@

事件详情

不可变事实
事件编号—
点位—
规则—
证据—

触发的预警

-

值班交接

白班 · 林值班员 → 晚班
ALT-1842 · 未 ack下一次升级 01:42
ALT-1841 · 处置中王值班员现场核查
ALT-1839 · 升级中短信重试 2/3

交接期间升级链继续计时,不暂停、不重置。接班人确认前,当前责任关系保持不变。

+

值班交接

白班 · 林值班员 → 晚班
ALT-1842 · 未 ack下一次升级 01:42
ALT-1841 · 处置中王值班员现场核查
ALT-1839 · 升级中短信重试 2/3

交接期间升级链继续计时,不暂停、不重置;只转移这些进行中 Alert 的处置责任,不修改未来排班。未来班次变化请在“值班与排班”创建替班版本。

版本历史与回滚

RULE-007 · 历史版本不可变
当前 v7 · 2026-08-01 正式发布持续 3 秒 · 全天 · 4 个点位 · 区域 v7
目标 v6 · 2026-07-18 历史版本持续 5 秒 · 夜间 22:00–06:00 · 3 个点位 · 区域 v6
影响评估将减少 1 个点位并收窄时段;预计每日预警 -18%。确认后创建并发布 v8,使其配置等价于 v6,v6/v7 均保持不变。
+ +

编辑升级步骤

默认链 v5 草稿 · 不直接保存手机号

保存的是类型化目标引用与通道偏好。每次投递创建时按站点时区解析生效排班,再固化收件人、通道和排班版本快照。

+ +

发布值班排班

历史版本不可变

发布前重新检查空档、重叠、联系人停用和通道验证。新版本只影响生效时间后的投递,不回写 v12 或既有投递快照。

+ +

创建临时替班

保存到 v13 草稿,发布后生效

临时替班修改未来排班。若只是把正在处置的 Alert 交给下一班,请使用值班台“交接班”,不要改排班。

+ +

新建联系人

联系人不包含班次和轮换字段

联系人保存身份、角色、值班组与已验证通道。加入哪个班次、何时轮换由“值班与排班”模块引用联系人 ID 完成。