Files
XQKqueue/docs/scenic-queue-system-plan.md
2026-07-16 11:40:34 +08:00

755 lines
60 KiB
Markdown
Raw Permalink 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.

# 景区项目排队叫号系统:案例调研与完整规划
> 文档状态v1.1 已确认开发基线
> 调研日期2026-07-10人数与双叫号模式修订2026-07-15
> 当前阶段:关键产品与技术决策已确认,已获授权进入开发。
> 适用前提:绿地项目;一个景区内存在多个游玩项目,每个项目可能有多个通道、设备或服务批次。
术语说明:`ETA` 是 Estimated Time of Arrival 的缩写。本系统技术文档用它指预计时间,但游客和员工界面统一写“预计等待时间”或“预计叫号时间”,不展示英文缩写。
## 1. 结论先行
系统定义为一个“以排队单和叫号批次为核心、四类终端共享同一实时事件流、首期硬件接口由模拟器验证”的现场运营系统,而不是四套相互同步的页面。真实硬件和本地设备网关属于后续专项。
核心方案是:
1. 每张 `QueueTicket` 对应一个排队号码,并保存创建后不可修改的同行人数 `party_size`。手机号和同行人数必填,姓氏和称谓选填;人数必须落在项目配置的连续范围内。每次取号生成不可猜测的排队单 ID、可读票号和私密查询令牌。
2. 同一手机号在同一项目可同时持有多个活动号码,以支持家人共用联系人手机号。发现重复时员工端必须展示脱敏的活动号码提示,经员工明确确认后方可继续,并记录审计;数据库不得设置“项目 + 手机号”的活动唯一约束。
3. “批量叫号”建模为独立 `CallBatch`。项目可支持按号码、按人数或两种方式;两种方式均严格 FIFO、连续、不手选、不跳号。按人数时选择合计人数不超过目标的最长队首前缀不拆分号码。
4. 预计等待时间只配置“单人预计间隔时间”,按本号前方所有号码的实际人数累加,不包含本号自身同行人数;界面显示易懂的预计时间和更新时间,不建设通用预测平台。
5. PostgreSQL 是唯一事实源,中心服务是唯一写入权威。景区完全断外网或客户端无法确认中心权威时,停止数字化取号与叫号,只展示最后快照并切换纸质号码、人工广播等现场预案。
6. 前端采用 React后端采用 Go + GORM数据库采用 PostgreSQL保持模块化单体和单仓库不拆分微服务。
7. 首期硬件范围只包含统一设备接口、成功/失败模拟器和测试日志不接真实打印机、广播、LED 或扫码设备;真实硬件取得型号、协议、驱动、网络拓扑及回执能力后另行立项。
8. 推荐先以一个项目做现场试点,跑通多人取号—号码/人数叫号—游客状态页/公示屏—到场—完成—预计时间校准的完整闭环,再扩展全景区。
9. 一个系统支持多个项目:所有队列、规则、票号、权限、设备和统计都带 `project_id`,但共用一套代码、数据库和部署,不为每个项目复制系统。
## 2. 已知需求、目标与边界
### 2.1 已确认需求
- 员工端 H5员工使用账号登录后进行取号和叫号项目支持两种方式时同时展示号码栏与人数栏每次叫号自动结束上一批并严格按 FIFO 选择连续号码。
- 游客端 H5查看自身排队情况、预计等待时间和当前进度。
- 大屏 Web实体公示屏公开展示最新叫号与队列概况其公开投影继续使用绑定的只读地址。
- 管理端 Web统一承载运营概览、项目规则和大屏中心大屏中心只展示公开票号与运行状态并可进入管理员全屏监控。账号、权限、日志和真实硬件配置仍按后续范围扩展。
- 一个号码可绑定多名同行游客;手机号和同行人数必填,姓氏和称谓选填,称谓默认“游客”,不采集法定性别。
- 员工端、游客状态页和内部登录卡采用 390px 手机设计宽度;更窄设备缩到 100%,页面高度保持自适应。管理端和公示屏不套用此宽度。
- 同一手机号允许创建多个活动号码;重复时先脱敏提示、再由员工确认并审计。
- 每项目配置支持的叫号方式、单号人数范围,以及号码/人数两种方式各自的默认值与防误触单次上限。
- 过号后原号码保持 `MISSED` 并失效;仍需排队时创建新号码进入队尾,原号码保留关联审计。
- 预计等待时间统一按项目配置的单人间隔和本号前方实际人数累加计算。
- 员工端和大屏端预留稳定硬件接口;首期只交付接口、模拟器和测试日志。
- 中心服务是唯一写入权威,完全断网时停止数字化写入并执行人工预案。
- 员工与管理员首期使用系统内置账号密码登录,预留后续 OIDC/SSO 接口。
- 前端采用 React后端采用 Go + GORM数据库采用 PostgreSQL。
- 操作和业务规则尽量简单,系统采用轻量架构,不引入没有实际需求支撑的复杂逻辑。
- 运营数据看板作为管理端首页模块开发,不单独建设看板应用。
- 员工端、管理端及运营看板不提供匿名访问;游客状态页和公示屏使用各自受控的无账号访问方式。
- 同一系统支持多个景区项目,各项目的数据、规则、人员授权和设备绑定相互区分。
### 2.2 产品目标
- 减少游客必须停留在实体队伍中的时间,同时不牺牲安全容量控制和公平性。
- 让员工在高峰、多人并发和设备故障时仍能明确知道“谁被叫了、为什么被叫、设备是否收到”。
- 让游客看到可理解但不过度承诺的实时进度。
- 让管理人员能解释一次异常、查看一次叫号记录、调整项目的预计时间参数并审计人工干预。
- 让员工只用少量高频按钮完成日常工作,高级异常操作收进二级入口。
### 2.3 MVP 明确不做
- 不自行建设售票、支付、闸机安全控制和车辆启航控制;只预留接口并接收/发送受控事件。
- 不使用机器学习、复杂滚动权重或预测平台;先用项目级简单参数计算预计等待时间。
- 不承诺“精确到某一分钟”的等待时间。
- 不把浏览器直连硬件作为唯一生产方案。
- 游客自助取号已按 2026-07-15 需求开放为当前实现:只允许选择正在运行的项目,使用手机号、选填姓氏/称谓和私密状态令牌;短信/微信通知仍不在范围内。
- 不拆微服务,不引入通用工作流引擎、规则 DSL、事件溯源或独立消息中间件。
- 不单独部署运营数据看板;它是管理端的一部分。
- 不做跨项目自动调度、跨项目队列迁移或多租户计费MVP 只做一个景区内的多项目隔离。
### 2.4 简单优先原则
- 员工主流程固定为:选择项目 → 取号 → 叫下一批 → 到场/完成;重叫、过号和“重新取号”放入“更多”,手选/重排/撤回放 P1。
- 每个项目只配置当前实际需要的少量参数,不提供可编程规则编辑器。
- 管理端只保留一个运营看板、项目管理、账号权限、日志和设备配置入口。
- 底层仍使用数据库事务、幂等和审计保证不重号、不重复叫号;“简单”指界面与部署简单,不牺牲核心正确性。
## 3. 成熟案例调研
调研优先使用景区官方、政府部门、厂商官方文档和开发者文档。案例用于验证产品模式,不代表其内部技术实现已公开;厂商宣传性指标不视为独立审计结果。
| 案例 | 已核验做法 | 对本项目的启示 | 不能据此推断 |
|---|---|---|---|
| 梵净山红云金顶 | 游客扫码进入预约排队,小程序显示预约号和当前叫号;接近时提醒;现场广播和电子屏按连续号段批量叫号 | 最贴近本项目的国内闭环;一个叫号批次要同时驱动 H5、提醒、广播、大屏和入口核验 | 公开资料没有披露员工 UI、并发算法和具体硬件协议 |
| 长江索道 | 售票窗口、自助机、微信公众号、OTA 等多入口取号;按号段、分时段乘坐;游客可线上查看进度并离开现场等待 | 所有入口应进入统一取号 API排队单可关联外部票务凭证但核心状态机不应依赖某一票务渠道 | 不能假定所有景区都需要实名身份证核销 |
| 陶然亭公园游船 | 云排队、叫号登船、智能广播、运营统计,并与游船定位、启航、收银等场景结合 | 排队最终可能联动运营控制;安全关键命令必须独立授权、审计并与普通显示命令隔离 | 大屏页面不应直接获得启航等安全控制权 |
| Disney World Virtual Queue | 通过 App 加入 boarding group同行组统一操作被召回后在 return window 内核销;名额有限且项目可动态启停 | 可借鉴项目开关、回场窗口和容量配额;同行组模型不采用 | 其官方页面当前可能没有正在运行的虚拟队列,不能照搬具体发放时点 |
| Universal Hollywood/Orlando、Europa-Park、USJ | 以同行组/已登记门票加入;选择或分配 return time迟到、取消、再次取号规则因项目而异 | 可借鉴迟到规则的明确告知;本项目已冻结为过号后新号排队尾 | 不存在适用于所有项目的一套迟到规则,且外部同行组规则不适用于本项目 |
| Universal Volcano Bay TapuTapu | 腕带通过园区 reader 加入虚拟队列,倒计时并振动提醒;设备可挂起/解绑,腕带本身不存个人信息 | 核销凭证和提醒终端应抽象化;硬件丢失、重绑、禁用和回执必须可管理 | 首期 H5 无需复制专用射频腕带体系 |
| Waitwhile | Customer 与 Visit 分离Visit 有 WAITING/SERVING/COMPLETE 等状态、位置和 ETA提供个人状态页、公共屏、Webhooks 和审计条目 | 访客与一次排队访问分离、个人页与公共屏分离、事件订阅和全量审计是成熟通用模式 | 通用服务场景的“窗口叫一个人”不能直接覆盖景区按容量装载的批次逻辑 |
主要来源:
- [梵净山扫码预约、实时进度与号段广播](https://www.gzrd.gov.cn/gzwh/202505/t20250530_87945751.html)
- [长江索道智能分流与多入口取号](https://www.cq.gov.cn/ywdt/bmts/201809/t20180921_8655058.html)
- [长江索道在线查看排队进程](https://www.cq.gov.cn/zwgk/zfxxgkml/zdlyxxgk/ggwh/ly/zxdt/202503/t20250311_14394287.html)
- [陶然亭公园云排队、广播与游船运营联动](https://gygl.beijing.gov.cn/xxgk/xxgk_gyxx/202203/t20220321_2635717.html)
- [Disney World Virtual Queue](https://disneyworld.disney.go.com/en_CA/guest-services/virtual-queue/)
- [Universal Studios Hollywood Virtual Line](https://www.universalstudioshollywood.com/web/en/us/plan-your-visit/virtual-line)
- [Universal Orlando Virtual Line](https://www.universalorlando.com/web/en/us/plan-your-visit/virtual-line)
- [Europa-Park VirtualLine](https://www.europapark.de/en/theme-park/info/plan-your-visit/virtualline-europa-park)
- [Universal Studios Japan 预约乘坐](https://www.usj.co.jp/web/zh/cn/enjoy/numbered-ticket/yoyakunori)
- [Universal Volcano Bay TapuTapu FAQ](https://www.universalorlando.com/web/en/us/plan-your-visit/taputapu-faq)
- [Waitwhile Visit API](https://developers.waitwhile.com/reference/listvisits)、[Webhooks](https://developers.waitwhile.com/reference/webhooks-2)、[游客状态页](https://help.waitwhile.com/en/articles/9949637-the-customer-status-page-real-time-updates-for-your-customers)
### 3.1 通用排队厂商能力对照
本次公开样本显示大屏、游客状态页、ETA、通知和单号叫号已有多家成熟实现但在所核验资料中“将多张独立排队单作为一次业务批次原子叫出”并不是普遍公开的能力。
| 产品 | 批量/分组证据 | 硬件与边缘 | API 透明度 | 规划判断 |
|---|---|---|---|---|
| Waitwhile | 公开帮助文档明确支持多选 Visit/活动参与者后批量 Alert、Serve并有 `partySize` | 浏览器电视/语音;官方明确无正式离线模式 | 最高:公开 REST、批量 Visit、Webhooks、认证、限流和重试 | 最适合借鉴游客体验、批量操作和开放事件,但真实硬件仍需自建设备网关 |
| Qmatic | 公开资料核验到 Call next、指定号码、Recall、Recycle、No-show未核验到多人原子批叫 | 本地 Orchestra/Queue Agent、打印、候客屏、柜台屏、语音体系成熟 | Data Connect 只读且非实时;操作接口资料有限 | 最适合借鉴“中央配置 + 分支 Agent + 设备配置” |
| Wavetec | 核验到 Next、Random/Priority Call、Recall未核验到多人批叫 | 本地 Controller、打印、屏幕、语音、恢复后云同步案例较完整 | 案例有双向 REST完整公开接口有限 | 最适合借鉴本地现场控制、设备冗余和云边同步 |
| Qtrac | 官网有 customer or group 措辞,但不能证明 group 等于多张独立票Auto Call 仍是逐个 | 浏览器大屏、语音、票据机/扫码可选;偏云端 | 有 API Library/Integration Hub 概述,无完整公开端点 | 采购前必须演示批量原子语义和断网行为 |
| QLess | 有群组群发消息,未核验到批量改变多张票的叫号状态 | 通用 kiosk、monitor、短信/语音;偏云端 | 宣称 API 覆盖广,缺少公开端点/Webhook 细节 | 群发通知不能被当作批量叫号 |
值得关注的景区类厂商案例是 [Waitwhile 的 SUMMIT One Vanderbilt](https://waitwhile.com/case-studies/summit-one-vanderbilt/):游客扫码或由员工平板登记,填写同行人数,系统按设施吞吐召集下一组。案例数据属于厂商自报;其“单号人数 + 运营批次”思路可用于对照,本项目仍使用更简单的连续 FIFO 规则。
参考资料:[Waitwhile 多选与批量操作](https://help.waitwhile.com/en/articles/8061037-navigating-the-visits-page)、[Waitwhile 离线说明](https://help.waitwhile.com/en/articles/11603596-does-waitwhile-work-without-internet)、[Qmatic Serve View](https://docs.qmatic.io/en/staff-user-guides/user-guide--serve-view.html)、[Qmatic Queue Agent](https://docs.qmatic.io/en/service-and-branch-configuration/branch-configuration/about-branches.html)、[Qmatic Data Connect 限制](https://data-connect.docs.qmatic.io/developerguide.html)、[Wavetec 本地分支与云同步案例](https://www.wavetec.com/es/case-studies/wasl-properties-customer-experience-transformation/)、[Qtrac](https://qtrac.com/virtual-queuing/)、[QLess](https://www.qless.com/products/)。
### 3.2 本次公开样本观察与规划推导
公开样本反复出现以下事实(其中同行组是外部案例特征,不是本项目规则):
- 身份、排队单、公开票号和核销凭证是不同概念。
- 同行组通常由一人操作,但核销和容量按全组人数计算。
- 设施容量决定发号和批量放行,不只是队伍长度决定。
- 系统可以暂停发号、补放名额、切换实体队列或停止某个项目。
- ETA/return window 是动态引导,不是服务承诺。
基于这些事实,本项目作出以下规划推导:
- 通知失败不应改变已提交的排队事实;游客主动查询页仍需可用。
- 扫码器、NFC、腕带、打印机、广播和屏幕都只是同一业务事件的不同执行端。
- 员工 H5、游客 H5、大屏和硬件必须共享同一服务端事实源不能各自维护队列。
## 4. 核心领域模型
| 概念 | 定义 | 关键字段/约束 |
|---|---|---|
| 景区 `Site` | 运营与权限边界 | 名称、时区、营业日、隐私/留存策略 |
| 项目 `Attraction` | 一个游玩/乘坐项目 | 代码、名称、队列类型、容量模型、状态 |
| 队列场次 `QueueSession` | 某项目在某营业日/时段的一条运行队列 | 营业日、开闭时间、状态、单调修订号、预计时间设置 |
| 服务资源 `ServiceResource` | 通道、入口、船、车辆、窗口或操作位 | 类型、容量、在线状态、所属项目 |
| 游客 `Visitor` | 受保护的最小访客资料,不以手机号唯一 | 内部 ID、加密手机号、手机号 HMAC 索引、选填姓氏、选填称谓、称谓默认“游客”、留存时间 |
| 排队单 `QueueTicket` | 一个排队号码及其同行游客人数 | 内部 ID、公开票号、不可变 `party_size`、私密查询令牌、顺序键、状态、来源、版本、可选原过号票关联 |
| 叫号批次 `CallBatch` | 一次原子批量放行 | 批次序号、叫号方式、请求数量、实际号码数、实际人数、成员票 ID、操作人、项目设置快照、状态 |
| 叫号尝试 `CallAttempt` | 初叫、重叫及其渠道结果 | 次数、时间、到期时间、语音/屏幕/通知回执 |
| 预计时间设置 `WaitEstimateConfig` | 每个项目当前使用的简单参数 | 模板、平均速度或批容量/间隔、缓冲分钟、上次修改人、上一版值 |
| 预计时间记录 `WaitEstimateRecord` | 只记录关键业务节点的预计值 | 排队单、取号/叫号节点、预计区间、计算时间、项目设置摘要 |
| [后续真实硬件专项] 设备与网关 | 物理设备的注册、能力与连接 | 设备类型、能力、驱动、在线状态、凭证、最后心跳 |
| [后续真实硬件专项] 设备命令 `DeviceCommand` | 可幂等执行的一次硬件动作 | 命令 ID、业务事件/叫号尝试 ID、过期时间、载荷、状态、错误和回执 |
| [后续真实硬件专项] 设备事件 `DeviceEvent` | 扫码、按钮、心跳等设备上行事实 | 设备事件 ID、设备 ID、业务关联、服务端接收时间、验签/去重状态 |
| 审计日志 `AuditEntry` | 谁在何时因何改变了什么 | 操作人/设备、前后值摘要、理由、关联票/批次、IP/终端 |
多项目采用同库同表方案:`QueueSession``ServiceResource``QueueTicket``CallBatch`、设备绑定和审计记录都直接包含 `project_id`。票号唯一约束使用“项目 + 营业日 + 票号”账号通过项目授权表访问一个或多个项目。管理端可以跨项目汇总员工端和公示屏默认只进入一个当前项目。MVP 不建立复杂的组织/租户继承,也不为每个项目单独建库或部署。
`project_id` 是强制安全边界:所有项目级记录(包括 `CallAttempt`、预计时间设置/记录、设备命令/事件、审计和统计)都必须携带它;唯一键、查询、更新、报表和事件频道均按它约束。项目范围由服务端根据登录账号授权、私密查询令牌或设备绑定确定,不能信任客户端自行提交的 `project_id`
`Visitor``QueueTicket` 分开:同一手机号可能多次来访,也可同时作为多位游客的联系人;一次排队的状态、预计等待时间、叫号和审计不写回身份资料。同一手机号的活动排队单不设唯一约束。删除/匿名化访客资料后,仍可保留不含个人信息的运营统计。
## 5. 状态机与运营规则
### 5.1 排队单状态
```mermaid
stateDiagram-v2
[*] --> WAITING: "取号成功"
WAITING --> CALLED: "进入叫号批次"
CALLED --> ARRIVED: "到场/核验"
ARRIVED --> SERVING: "进入通道/开始服务"
SERVING --> COMPLETED: "完成"
CALLED --> MISSED: "宽限到期/员工判定"
WAITING --> CANCELLED: "游客或员工取消"
CALLED --> CANCELLED: "异常取消"
ARRIVED --> CANCELLED: "授权异常处理"
COMPLETED --> [*]
MISSED --> [*]
CANCELLED --> [*]
```
说明:
- MVP 员工界面把 `ARRIVED``SERVING` 合成一个“已到场/入场”按钮;数据层可保留两个时间点,首期可在同一次操作中写入。
- `MISSED` 不能恢复为 `WAITING`,也不能直接删除。游客仍需排队时,由员工创建一张新排队单和新票号进入队尾,并记录原票、新票、原因和操作人关联。
- 任何逆向状态变更都需更高权限、原因和审计。
### 5.2 项目/队列状态
| 状态 | 新取号 | 新叫号 | 已叫号核验 | 预计等待时间展示 |
|---|---:|---:|---:|---|
| `CLOSED` 未开放 | 否 | 否 | 否 | 未开放 |
| `OPEN` 运行中 | 是 | 是 | 是 | 正常 |
| `PAUSED` 暂停 | 否 | 否 | 是 | 隐藏分钟,展示暂停原因 |
| `FINISHED` 当日结束 | 否 | 否 | 否 | 已结束 |
MVP 只保留这四种状态。暂停、恢复和结束均记录操作人、原因,并更新游客页和公示屏。[P1] 只有现场确实需要时,再拆分“仅暂停取号”“仅暂停叫号”和“清队中”。
### 5.3 MVP 已确认规则
- 每个项目每天生成独立票号序列,例如 `A-0238`;内部 ID 使用随机 UUID/ULID不从票号推断记录数。
- 同一手机号在同一项目存在活动排队单时,员工端先展示脱敏重复提示;员工确认后仍可创建新号码,确认动作和关联活动号码进入审计。
- [P1] 优先队列、人工插队和配额规则不进入 MVP。
- 当日结束不批量物理删除;按状态关场并保留审计。
- [P1] 手工修改位置不进入 MVP。
- 每张排队票保存创建时确认的 `party_size`;创建后不提供修改、拆分或合并,需纠正时取消原号并重新取号。
- MVP 固定严格 FIFO按号码时取队首连续 N 张;按人数时取合计人数不超过目标的最长连续队首。两种方式都不跳号、不手选。
- 闭园前由管理员将项目切为 `PAUSED` 停止新取号/叫号,处理完现场后切为 `FINISHED`;复杂自动清队规则后移。
## 6. 批量叫号:完整业务定义
### 6.1 项目可配置两种叫号方式
`CALL_NEXT` 接收明确的 `mode``count`
- `TICKET`:从队首选择最多 `count` 张连续有效等待票;队列不足时选择全部剩余票。
- `PEOPLE`:从队首选择 `party_size` 合计不超过 `count` 的最长连续前缀。不得拆号或跳过大号;若队首单号人数已超过目标,则拒绝并提示所需最小人数。
项目可配置只支持 `TICKET`、只支持 `PEOPLE``BOTH``BOTH` 时员工端同时展示两栏,不设置隐含默认模式。两种模式分别配置默认输入值和单次防误触上限;防误触上限不等同于项目容量上限。
[P1] 手选、跳号、按班次和预叫只有在试点证明必要后再单独设计。
### 6.2 叫号批次生命周期
`CallBatch` 本身有明确状态,不能只从成员列表临时猜测:
```mermaid
stateDiagram-v2
[*] --> ACTIVE: "叫号事务提交"
ACTIVE --> PARTIALLY_RESOLVED: "部分成员到场/过号/取消"
ACTIVE --> RESOLVED: "所有成员已有结果"
PARTIALLY_RESOLVED --> RESOLVED: "最后一名待到场成员有结果"
RESOLVED --> [*]
```
- `ACTIVE`:至少一名成员仍为 `CALLED`,到场窗口尚未全部结束。
- `PARTIALLY_RESOLVED`:部分成员已到场/过号/取消,仍有成员等待响应。
- `RESOLVED`:没有成员仍处于 `CALLED`;记录汇总结果和结束原因,不可删除。
- 入口的“待到场批次名额”在批次 `RESOLVED` 时释放。
- MVP 不做预叫和批次撤回;叫错号由主管记录异常并通过人工现场处理,不设计复杂逆向状态。[P1] 若试点证明撤回必需,再增加 `WITHDRAWN`
### 6.3 原子执行规则
员工点击“确认叫号”后,服务端在一个事务内:
1. 校验员工权限、资源归属和请求格式;若幂等键已有成功结果,直接返回原批次。
2. 先锁定 `QueueSession`/队列修订行(或用 `UPDATE ... WHERE revision = expected` 做 CAS再校验项目状态和客户端看到的修订号修订不符立即返回冲突。
3. 在同一串行化边界内,从队首按原始顺序读取等待票。
4. 校验项目是否支持请求模式及其防误触上限,按号码数或人数目标选择连续 FIFO 前缀,并生成包含模式、请求值、实际号码数、实际人数和成员的不可变快照。
5. 创建 `CallBatch`、成员记录和首次 `CallAttempt`,把成员从 `WAITING` 更新为 `CALLED`
6. 增加队列修订号,同时写入审计和同库的“待发送事件”记录,然后提交。
7. 提交成功后再发布实时事件、通知和硬件命令。
多个员工同时叫号时,只能有一个事务在预期修订号上成功;后到请求在获得锁后会发现修订已变化,收到新的队列快照并要求重试,绝不继续使用旧候选集。
API 语义为 `callNext(project_id, mode, count, expected_revision)`。服务端不信任客户端候选集,始终在锁内重新选择队首。响应同时返回实际号码数与实际人数;每个项目新一批叫号会自动完成上一活动批次。
### 6.4 连续 FIFO 与“不超过目标”
- 每张有效等待票代表一个号码,`party_size` 表示该号绑定人数;批次号码数与人数必须分别统计。
- “连续”指队列顺序连续:只跳过已取消、已过号等非 `WAITING` 记录,不因票号数值存在自然缺口而回填或重排。
- 人数模式只接受不超过目标的最长连续前缀;目标值可能未被填满,这是严格 FIFO 和不拆号的正常结果。
- 号码模式仅限制本次号码数量,不另设这些号码的合计人数硬上限。
- 大屏仅在公开票号数值确实连续时压缩为号段;否则完整列出本批票号,业务成员始终以 ID 列表为准。
- [P1] 手选、跳号、轮椅位/舱位等多维容量约束在有明确项目需求时另行扩展。
### 6.5 重叫、到场、过号与设备失败
- 重叫沿用同一 `CallBatch`,增加 `CallAttempt`,不新建一批并再次改变队列位置。
- 到场/过号可逐张处理;批次不要求全员同一结果。
- 叫号提交后,即使语音、短信或大屏失败,队列状态也不回滚。系统重试设备命令并醒目标注“播报未确认”。
- 初叫与每次人工重叫都生成新的 `call_attempt_id`;同一次尝试向每台设备生成独立 `command_id`,网络重试沿用原 `command_id`。因此可以避免传输重试造成重复播报,同时又允许员工有意发起一次新的重叫。
## 7. 预计等待时间(技术简称 ETA
### 7.1 展示口径
游客默认看到:
- 当前状态与公开票号;
- 前方号码数与前方实际人数;
- 预计等待区间,例如 2535 分钟;
- 估算状态(正常、暂停、暂不可估);
- 最近更新时间;
- 免责声明:现场运营、天气、设备和安全检查可能导致变化。
“前方人数”只统计本号前面的等待票 `party_size` 之和,不包含本号自身同行人数。仍不显示“准确 29 分钟”,因为它会被游客理解为承诺。
### 7.2 MVP 简单计算模板
每个项目只选择一种模板,员工和管理员不需要理解公式:
| 模板 | 适用项目 | 简单计算 |
|---|---|---|
| 单人间隔 | 所有项目 | 前方实际人数 × 单人预计间隔时间 |
首期只保留单人间隔模板,不建设装箱、排班或约束求解引擎;班次、车辆、多资源联合调度放到确有项目需要时再扩展。
预计值统一四舍五入到 5 分钟并显示为区间。项目暂停、权威队列数据陈旧或参数缺失时直接写“暂无法估算”,不叠加复杂修正系数;设备模拟失败不改变预计时间结果。
### 7.3 项目级设置
管理端每个项目只保留以下字段:
- 单人预计间隔时间;
- 暂停时是否隐藏预计时间;
- 最后修改人、修改时间和上一版值。
MVP 保存修改日志并允许恢复上一版,不做草稿审批流、定时发布、复杂权重、异常值规则和可编程公式。
### 7.4 异常与校准
- 新项目直接使用管理员填写的项目参数,不要求先积累历史样本。
- 项目暂停、权威队列数据缺失或参数缺失时隐藏分钟数,显示明确原因;设备模拟失败独立展示,不影响预计时间。
- MVP 只在取号、叫号两个关键节点记录预计值,不保存每次页面刷新的快照。
- 管理看板只显示“近期平均误差”和“偏早/偏晚次数”,让管理员据此调整项目参数;高级统计放到后续版本。
- 首期只预测“预计叫到时间”。若未来确有二次候场,再单独增加“预计开始体验时间”。
## 8. 四端产品规划
### 8.1 员工端 H5
| 模块 | MVP 能力 |
|---|---|
| 登录与工作台 | 必须账号登录;从已授权项目中选择当前项目,查看项目状态、网络和设备摘要 |
| 取号 | 手机号和同行人数必填,姓氏/称谓选填;人数按项目范围校验且创建后不可修改;重复活动号码确认后可继续并留审计 |
| 队列 | 等待/已叫/过号/到场列表逐号展示 `party_size`,并在账号授权范围内展示票号、完整手机号、姓氏/称谓、状态和取号时间 |
| 叫号控制台 | 按项目展示号码栏、人数栏或两栏;提交后显示实际号码数、实际人数与成员预览,叫号后可到场、完成 |
| 更多操作 | 重叫、过号、取消、过号后重新取新号、暂停/恢复;默认折叠,不占主流程;授权手选/重排放 P1 |
| 设备 | 首期显示接口未启用/模拟成功/模拟失败、测试日志和降级指引 |
关键体验:防误触上限在服务端强制;每个候选号码旁显示同行人数;按钮响应后展示服务端实际号码数与人数,不用乐观假成功掩盖并发冲突。
### 8.2 游客端 H5
MVP 推荐使用取号后生成的随机查询链接/二维码进入个人状态页:
- 票号、项目、本号人数、取号时间;
- 当前状态、前方号码数、前方人数、预计等待时间区间、更新时间;
- 被叫后明显的到场窗口、位置导航和核验码;
- 暂停、停运、闭园等运营公告;
- 取消排队(若业务允许)与隐私说明。
链接丢失后的恢复建议使用“手机号 + 短信验证码”或“票号 + 手机号验证”。仅凭姓氏、称谓或手机号后四位不得查看个人队列详情。
### 8.3 大屏 Web
- 项目名称、运行/暂停状态、当前批次、最近若干批次、入口/通道;
- 等待号码数/总人数、当前预计等待时间区间、更新时间、运营公告;
- 只显示票号,不显示手机号、姓氏或称谓;首期不提供公开身份字段配置;
- 16:9 和超宽屏响应式、全屏/开机自启、保活、断线状态和最近快照;
- 浏览器声音自动播放需首次人工授权/受控终端策略;真实语音硬件和设备网关属于后续专项;
- 设备配对码换取只读、限项目、可吊销的大屏令牌。
### 8.4 管理端 Web
| 模块 | 能力 |
|---|---|
| 运营看板 | 管理端首页;项目筛选、等待号码数/人数、正在叫号、近期吞吐、设备模拟异常和活动号码明细;活动号码在管理员权限内对应展示项目、票号、完整手机号、姓氏/称谓与状态 |
| 景区与项目 | 项目、营业时间、票号前缀、单号人数范围、项目开关 |
| 叫号设置 | 支持模式、号码/人数默认值及各自防误触上限、宽限时间;高级重排策略不进入 MVP |
| 预计等待设置 | 每项目填写单人预计间隔时间;显示上一版值和修改日志 |
| 账号与权限 | 账号、角色、项目范围、禁用、会话、重置、MFA/SSO 预留 |
| 日志与报表 | 队列流转、员工操作、配置、登录、通知、设备日志与导出 |
| 设备接口 | MVP 只配置“未启用/模拟器”、测试成功/失败和记录;注册、心跳、回执与驱动管理属于后续真实硬件专项 |
| 隐私治理 | 字段展示策略、数据留存、匿名化任务、访问审计、导出审批 |
管理看板是管理端的首页模块,与项目配置、账号和日志共用一个应用。游客公示大屏仍是只读展示路由,用于现场公开叫号;它不是另一套运营看板系统。
管理端和运营看板必须经过账号登录与路由权限校验后才能加载;员工端同样必须登录,且每次请求由服务端校验账号角色和项目范围。首期采用系统内置账号密码,不提供共享或匿名员工/管理员入口;密码使用安全哈希,登录有速率限制,支持会话吊销和管理员重置,并预留 OIDC/SSO 接口但首期不接企业身份源。
多项目交互约束:管理端顶部保留当前项目筛选,可查看“全部项目”汇总;进入配置和日志详情时必须选定一个项目。员工登录后只看到被授权项目,切换项目会清空当前选择。每台公示屏默认绑定一个项目,避免把不同项目号码混在一起。
## 9. 权限模型
采用“内置账号密码登录 + RBAC + 项目范围”:
员工、项目主管、运营管理员、审计员和景区超级管理员均使用可追溯的个人账号登录;管理端首页与运营看板至少要求运营管理员、项目主管(限本项目)或更高角色。公示屏设备令牌与游客私密查询令牌不是员工/管理员账号,不能进入后台或员工功能。
| 角色 | 典型权限 |
|---|---|
| 景区超级管理员 | 全景区配置、角色、关键集成;不默认查看明文个人信息 |
| 运营管理员 | 项目/规则、暂停恢复、报表、异常审批 |
| 项目主管 | 本项目批量叫号、异常重排、人工覆盖、设备重试 |
| 一线员工 | 取号、正常批量叫号、到场/完成、受限查询 |
| 审计员 | 只读日志和脱敏导出 |
| 大屏设备 | 只读某项目公开投影 |
| 设备网关 | 只收其绑定设备的命令并回传状态 |
MVP 敏感动作采用 step-up 验证或主管批准:批量取消、导出、项目异常停运和安全控制集成。[P1] 若启用手工插队/选号或批次撤回,同样适用。员工端与管理端的授权业务列表按本次确认直接显示完整手机号,用于现场联系和号码核对;页面请求仍受账号、角色、项目范围和访问日志保护。普通项目参数修改直接保存并留审计,不增加审批流。
## 10. 推荐技术架构
首期采用“一个模块化单体应用 + 一个 PostgreSQL”。前端使用 React后端使用 Go + GORM员工 H5、游客 H5、公示屏和管理端放在同一代码仓库可按路由或构建入口区分认证、项目管理、排队、预计时间、实时推送和管理看板都在同一个后端部署中。生产数据库结构通过版本化 SQL 迁移管理,不依赖 GORM 启动时自动建表。真实本地硬件与现场设备网关不在首期范围。
MVP 不设置独立 API 网关、认证服务、预计时间服务、实时服务、报表服务或消息中间件;这些只是代码模块,不是部署单元。
```mermaid
flowchart LR
Staff["员工 H5 / React"] --> App["Go + GORM 单体 API"]
Visitor["游客 H5 / React"] --> App
Screen["React 公示屏只读路由"] --> App
Admin["React 管理端 + 运营看板"] --> App
App --> DB[("PostgreSQL")]
App --> Push["内置 SSE失败时轮询"]
Push --> Staff
Push --> Visitor
Push --> Screen
App --> Jobs["同应用后台任务"]
Jobs --> Adapter["设备适配接口 / 模拟器"]
Adapter -. 后续真实硬件专项 .-> LocalGW["可选本地设备网关"]
LocalGW --> Devices["语音、LED、打印、扫码"]
```
### 10.1 组件职责
- React 前端:员工 H5、游客 H5、公示屏和管理端共享业务契约但按终端任务拆分路由与界面密度。
- Go + GORM 单体 API内置账号密码登录与项目授权、取号、叫号、预计时间、管理配置、运营看板和各端最小数据接口核心 `CALL_NEXT` 使用显式 GORM 事务和 PostgreSQL 行锁。
- PostgreSQL唯一事实源用普通事务、行锁、唯一约束和 `project_id` 组合索引保证正确性。
- 内置实时推送REST 写入 + SSE 单向更新;连接失败回退 5 秒轮询,不先引入 WebSocket 集群。
- 同应用后台任务:处理数据库中的待发送记录、简单统计和过期状态;不依赖独立消息队列。
- 设备适配接口:首期只提供统一命令结构、成功/失败模拟器和测试日志;厂商适配器或本地网关属于后续真实硬件专项。
- MVP 不要求 Redis。只有压测证明会话、限流或多实例推送需要时再加入。
### 10.2 实时一致性
- 每条队列有单调递增 `queue_revision`,每个事件有唯一 ID 与序号。
- SSE 订阅按服务端确认的项目权限过滤;普通员工和项目设备不能订阅其他项目事件。
- 客户端检测到事件缺口时拉取最新快照,而不是猜测中间状态。
- 大屏重连时先读快照,再订阅新事件;旧叫号只恢复画面,不自动重播声音。
- 所有写 API 支持 `Idempotency-Key`;网络重试不会重复取号或重复叫号。
- 公共读模型允许最终一致(目标 2 秒内),叫号写和成员选择必须强一致。
## 11. 硬件集成规划
### 11.1 为什么不能只做浏览器直连
截至 2026-07WebUSB 与 Web Serial 仍被 MDN 标注为有限可用并要求安全上下文设备选择通常需要用户手势。Chrome 对公网页面访问本地网络又增加了 Local Network Access 权限提示。这些能力可用于受控终端试点,但不足以覆盖任意手机、浏览器和厂商驱动。
来源:[MDN WebUSB](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API)、[MDN Web Serial](https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API)、[Chrome Local Network Access](https://developer.chrome.com/blog/local-network-access)。
### 11.2 可选设备网关
MVP 先定义设备适配接口和模拟器。只有确认的真实硬件无法通过普通网络接口稳定接入时才在景区本地运行轻量网关Windows/Linux/工控机/边缘盒子均可评估):
- 通过 mTLS MQTT、WSS 或 HTTPS 长连接接收标准命令;
- 适配串口、USB、TCP/UDP、厂商 SDK、ESC/POS、HTTP 等协议;
- 本地持久化未完成命令,按过期时间和重试策略执行;
- 上报心跳、驱动版本、设备状态、执行回执和诊断信息;
- 断线后不自行生成新叫号,只执行已确认且未过期的命令;
- 支持模拟设备驱动,开发阶段无需真实硬件即可做端到端测试。
### 11.3 标准命令、设备事件与回执(后续真实硬件专项)
下行 `DeviceCommand`(系统要求设备执行)建议:
- `DISPLAY_RENDER`:大屏/LED 更新;
- `VOICE_ANNOUNCE`:语音播报;
- `PRINT_TICKET`:打印排队凭条;
- `INDICATOR_SET`:指示灯/蜂鸣器;
- `DEVICE_HEALTH_POLL`:主动健康检查。
上行 `DeviceEvent`(设备向系统报告)建议:
- `SCAN_VERIFIED`:扫码/NFC 核验结果;
- `BUTTON_PRESSED`:物理按钮输入;
- `DEVICE_HEARTBEAT`:设备心跳和能力状态;
- `COMMAND_ACK`:命令接收、执行或失败回执。
三个标识不能混用:
- `business_event_id`:一次已提交的业务事实,例如某叫号批次进入 `ACTIVE`,供四端关联;
- `call_attempt_id`:初叫或某次有意重叫,每次播报意图一个新值;
- `command_id`:某次尝试下发给某台设备的一条命令;传输重试沿用它并由设备去重。
命令信封至少包含:`command_id``business_event_id``call_attempt_id`(适用时)、`site_id``project_id``device_id``type``schema_version``issued_at``expires_at``payload`。回执状态:`RECEIVED``EXECUTING``SUCCEEDED``FAILED_RETRYABLE``FAILED_FINAL``EXPIRED`
浏览器公示屏从单体应用的内置实时接口读取公开数据LED/串口屏在启用设备网关后接收命令。同一物理终端必须选定唯一主传输,禁止 Web 与设备命令同时渲染造成重复。
安全关键的闸机、车辆启航或安全联锁不复用普通大屏/语音权限;需要独立命令域、双向确认、白名单和现场安全评审。
## 12. 核心接口草案
以下是边界,不是最终 URL
- `POST /staff/tickets`:员工取号;含不可变 `party_size` 与幂等键。
- `GET /staff/queues/{id}/snapshot`:员工队列快照和修订号。
- `POST /staff/queues/{id}/call-batches`:提交 `mode``count`、队列修订号与幂等键,服务端在锁内选择连续 FIFO 前缀。
- `POST /staff/call-batches/{id}/recall`:重叫。
- `POST /staff/tickets/{id}/arrive|serve|complete|miss|cancel`:明确状态动作。
- `POST /staff/tickets/{id}/replacement`:为已过号票创建新票号并排到队尾,记录新旧票关联;不修改原票状态和位置。
- `GET /public/status/{opaqueToken}`:游客个人最小投影。
- `GET /display/{pairedDevice}/snapshot`:大屏公开投影。
- `GET /events?...`SSE 订阅,带最后事件序号恢复。
- `PUT /admin/projects/{id}/wait-estimate`:保存该项目的简单预计时间设置,并记录上一版。
- [P1] `POST /integrations/webhooks`:确有外部集成时注册签名 Webhook。
- [后续真实硬件专项] 设备连接:命令下发、回执、心跳、能力和日志接口。
所有员工/管理接口先由服务端校验目标资源所属项目和账号的项目授权;公示屏项目来自设备绑定,游客项目来自私密查询令牌。任何接口都不能仅凭客户端传入的 `project_id` 放行。
若 P1 启用对外 Webhook必须签名、重放防护和失败重试消费者失败不能阻塞核心叫号事务。
## 13. 数据隐私与安全
### 13.1 合规事实基线
- 手机号、姓氏、性别与游客关联后属于个人信息。《个人信息保护法》要求处理目的明确、范围最小、事前告知并采用实现目的所必要的最短保存时间;处理者、目的、方式、种类、期限和权利渠道均应告知。[法律原文](https://www.cac.gov.cn/2021-08/20/c_1631050028355286.htm)
- 2025 年四部门个人信息保护专项行动明确把线下消费场景强制收集非必要手机号、生日、性别列为治理重点。因此“作为取号标识”不能自动证明三项都必须收集。[专项行动公告](https://www.cac.gov.cn/2025-03/28/c_1744867353112759.htm)
- 三个字段本身不在法律第 28 条明确列举的敏感个人信息类别中,但多项信息汇聚后的风险需整体评估;不满 14 周岁未成年人的个人信息属于敏感个人信息。[国家标准 GB/T 45574-2025](https://openstd.samr.gov.cn/bzgk/std/newGbInfo?hcno=F9F3A2EBF49E9B4D73AD8C8912986D5A)
- 大屏或广播若仍能对应到具体游客,属于公开个人信息的处理场景,需评估单独同意和个人信息保护影响评估要求;手机号打星只是掩码,不自动等于匿名化。
- 《网络数据安全管理条例》要求隐私规则醒目、易访问,并说明保存期限和到期处理;短信、云服务、硬件厂商等受托方需合同约束目的、范围和安全义务。[条例原文](https://app.www.gov.cn/govdata/gov/202409/30/520076/article.html)
这些内容是产品/技术规划依据,不替代项目法务意见。
### 13.2 已确认的最小必要身份字段
- 手机号必填,用于联系、查重和找回;姓氏与称谓选填,称谓可选“先生、女士、游客”,未填写时默认“游客”。
- 系统不采集法定性别;称谓只用于人工核对,不推断或记录性别。
- 同一手机号可对应多个同时活动的号码。重复检测只触发脱敏提示和员工确认,不阻止创建;确认结果必须审计。
- 系统身份使用内部 ID公开身份使用票号个人查询使用高熵令牌或验证码。
- 同行人数可包含未成年人,不为组内每个人额外采集手机号、姓名或法定性别;联系人手机号可被多个活动号码复用。
### 13.3 存储与展示
- 手机号密文存储;另存带服务端密钥的 HMAC 用于等值查找,不能用裸 SHA 哈希。
- 完整手机号不进入 URL、埋点、普通日志、Webhook 默认载荷或大屏。
- 大屏和广播只使用票号,不显示或播报手机号、姓氏、称谓;首期不提供公开身份字段配置。
- 员工端和管理端在账号及项目授权范围内直接展示完整手机号与票号、姓氏/称谓、状态的对应关系;接口不得跨项目返回,普通日志不得记录响应中的完整值。
- 游客私密状态页只显示联系手机号尾四位用于本人核对,不显示完整手机号。
- 游客状态令牌不可枚举、可撤销、有有效期;敏感操作再次验证手机号。
### 13.4 最小必要与留存
- 取号前展示处理目的、字段、使用方式、保存期限、查询/删除渠道和运营主体。
- 营销短信/画像不得借用排队服务的同一授权。
- 排队记录与手机号、姓氏、称谓的个人关联在完成、取消或过号后保留 30 天,期满删除个人关联。
- 原始排队业务事件保留 90 天,期满不可逆匿名化为统计数据;匿名运营指标可继续保存。
- 登录、权限及网络安全日志至少保留 6 个月。
- 后台操作审计保留 1 年。
- 个人信息保护影响评估及相关处理记录保留 3 年。
- 上述期限实现为受权限与审计保护的系统配置;正式上线前由运营与法务复核,任何调整都必须遵守最短必要原则并记录依据。
### 13.5 安全控制
- 全链路 TLS首期内置账号密码使用安全哈希、登录限流、会话吊销和管理员重置。MFA/OIDC/SSO 只预留扩展接口,不作为首期能力。
- 密钥进入 KMS/专用密钥管理,不写配置文件或日志。
- RBAC + 项目范围 + 字段级脱敏;导出需审批、带水印和过期下载地址。
- 速率限制、验证码/短信验证码防批量查询和撞库。
- 管理、叫号、个人信息访问、规则和设备命令全部审计。
- 备份加密、恢复演练、依赖与镜像扫描、漏洞响应和日志告警纳入上线门槛。
## 14. 日志、报表与运营指标
### 14.1 日志分类
- 业务流转:取号、位置/优先变化、批次、重叫、到场、过号、重排、取消、完成。
- 账号安全:登录、失败、登出、重置、授权变化、查看明文、导出。
- 配置:项目、容量、预计时间参数及上一版恢复、隐私留存。
- 设备:注册、心跳、命令、回执、重试、驱动错误、人工降级。
- 通知:创建、发送、送达/失败,但正文和手机号需脱敏。
### 14.2 核心指标
- 当前/峰值等待号码数和人数(分别统计,不再假定两者相等);
- 今日平均/最长实际等待时长;
- 每小时吞吐、批次人数、容量利用率;
- 过号率、取消率、过号后重新取号率、人工跳过率;
- 近期预计时间平均误差、偏早/偏晚次数;
- 实时推送延迟、大屏陈旧时间;
- 设备模拟命令成功率/延迟;[后续真实硬件专项] 再统计真实设备离线时长;
- 员工异常操作、权限拒绝和批次冲突。
## 15. 非功能目标(评审基线)
下列是建议验收基线,最终需按实际峰值容量校准:
| 维度 | 建议目标 |
|---|---|
| 叫号正确性 | 并发和重试下同一排队单至多进入一个有效叫号批次;状态变更 100% 可审计 |
| 操作延迟 | 设计负载下,取号/叫号 API P95 ≤ 800msP99 ≤ 1.5s(不含外部短信/硬件完成) |
| 实时性 | 已提交叫号到在线 H5/大屏 P95 ≤ 2s降级轮询陈旧时间 ≤ 5s |
| 可用性 | 营业时段核心服务月可用性目标 99.9%;中心服务不可达时停止数字化取号/叫号并切换人工预案 |
| 数据恢复 | 需在部署决策后确认 RPO/RTO数据库做时间点恢复与定期演练 |
| 容量 | 以确认的峰值“取号/秒、叫号/秒、在线游客、屏幕、项目数”的 2 倍做压力验收 |
| 隐私 | 大屏、普通日志和分析事件中 0 个完整手机号;越权访问测试全部拒绝并留痕 |
| 设备接口 | MVP 模拟成功/失败且不影响核心队列;真实硬件纳入后再验收命令幂等、过期、重试和回执 |
上线前必须取得实际容量输入:项目数、日票量、峰值每分钟取号、最大并发游客、员工/大屏/网关数、单批容量、最长营业时长和网络质量。
## 16. 测试与验收计划
### 16.1 测试层级
- 状态机单元/性质测试:所有允许和禁止的转移、逆向操作、营业日边界。
- 并发测试:多员工同时叫下一批、客户端超时重试、重复提交、队列暂停竞态。
- 双模式选号测试:号码模式取队首 N 张;人数模式取不超过目标的最长连续前缀,并覆盖队首单号超目标、不拆号、不跳号和欠载结果。
- 预计时间测试:只累加本号前方实际人数,覆盖前方 0 人、暂停、参数缺失和五分钟取整。
- 实时测试:掉线补快照、事件缺口、乱序/重复事件、大屏旧声音不重播。
- 设备接口测试MVP 模拟成功/失败;[后续真实硬件专项] 再测网关超时、重复命令、坏载荷、离线、过期和部分设备失败。
- 端到端测试:四端共享同一排队单/批次事实。
- 隐私与安全:越权、枚举令牌、日志泄露、导出、会话吊销、密钥轮换。
- 现场 UAT弱网、噪声、阳光屏幕、扫码速度、员工戴手套/单手操作、节假日批量压力。
### 16.2 必过场景
1. 两名员工基于同一修订号并发叫号,只有一方成功,成员无重复、顺序严格 FIFO 且两端得到明确结果。
2. 服务端已成功、员工手机超时后重试,不生成第二批。
3. 模拟语音适配器失败但公示屏成功,业务批次保持有效;真实设备重试语义留到后续专项验收。
4. 大屏断线十分钟后恢复,只显示最新状态,不重播十分钟前语音。
5. 项目暂停后停止新叫号,游客显示暂停而不是继续倒计时。
6. 队首人数依次为 3、4、2按人数目标 8 时只叫前两号共 7 人;不得越过第二号再选择第三号,也不得拆号。
7. 队首单号 5 人而目标为 4 时拒绝叫号;提高到 5 后才允许叫出该号。
8. 过号后创建的新号码位于队尾并继承原号同行人数,且可追溯原号码、新号码、原因、操作人和所有叫号尝试。
9. 已登录员工只能获得其授权项目的完整手机号对应数据,游客只获得本人私密状态页中的手机号尾四位,大屏和设备令牌无法获得任何手机号或管理数据。
10. 修改项目人数范围、叫号方式或预计时间参数后立即生效并记录前后值;既有号码的 `party_size` 保持不变。
11. 营业日结束、跨午夜、时区、时钟漂移和夏令时测试不破坏票号与人数统计。
12. A 项目员工、SSE 订阅、公示屏令牌和设备绑定均无法读取或操作 B 项目数据;客户端伪造 `project_id` 也被服务端拒绝并留痕。
## 17. 部署、弱网与灾备分支
为满足轻量化要求MVP 已确认采用方案 A。断外网时不允许数字化写入方案 B 仅在未来需求正式变更后单独扩展立项。
### 方案 A中心服务为唯一写入权威
- 员工、游客和公示屏访问中心服务;首期不部署现场设备网关。
- 优点:架构简单、无双向数据冲突、运维成本低。
- 弱点:景区完全断外网时无法安全创建新票或叫新批次;只能展示最后快照并切换人工预案。
### [P1] 方案 B景区本地边缘节点为现场写入权威
- 员工、大屏和硬件走本地网络;边缘节点向云端同步公开读模型、管理数据和备份。
- 优点:断外网时现场仍可取号/叫号;硬件延迟更稳定。
- 弱点:需要本地服务器、监控、升级、备份和云边同步;游客使用蜂窝网络时的个人页需处理云端陈旧提示。
### 方案 C云、边都可独立写入
- 不建议首期采用。离线合并队列顺序、票号和批次会产生复杂冲突,很难证明公平且安全。
MVP 以方案 A 和纸质号码、人工广播等应急预案为准。断网时各端保留最后成功快照和更新时间,禁用新取号/叫号;恢复后先拉取权威快照与 `queue_revision` 再重新开放写操作。方案 B 会增加本地服务器、同步、监控和升级成本,不在首期建设。方案 C 不进入规划。
## 18. 分阶段交付
### 阶段 0开发基线与脚手架约 1 周)
- 将 v1.1 已确认决策落实为领域模型、API 契约、数据库迁移和验收场景。
- 创建 React 前端、Go + GORM 后端和 PostgreSQL 的单仓库脚手架,接通本地开发与自动化测试。
- 跟班观察普通日和高峰日,补充实际容量、网络与设备资料;这些现场输入用于校准,不改变已确认基线。
### 阶段 1可运行垂直切片约 2 周)
- 先跑一个试点项目,但数据库和权限从第一天包含 `project_id`
- 员工多人取号、号码/人数双模式叫号、游客状态页、公示屏更新和管理基础配置。
- PostgreSQL 事务、幂等、审计和设备模拟器从第一条链路就具备。
### 阶段 2MVP 完整闭环34 周)
- 最小必要身份字段、重复手机号确认审计、到场/过号/新号排队尾,以及按前方人数计算的预计时间规则。
- 多项目选择、项目权限、管理端运营看板、日志报表、实时降级、隐私与安全加固。
- 设备适配接口、成功/失败模拟器和测试日志;不加入真实设备适配器或本地网关。
### 阶段 3单项目现场试点与硬化23 周)
- 灰度运行、预计时间对照、并发和弱网演练、员工培训、应急预案。
- 先由旧流程兜底,再逐步把新系统切为权威;每日复盘预计时间误差和异常。
### 阶段 4全景区多项目扩展12 周)
- 批量增加项目、容量验证、设备绑定和员工项目授权。
- 按项目逐个上线,可独立回退,不全景区一次性切换。
以上约 912 周,是 45 人小团队、单一试点项目、无复杂票务改造且硬件接口范围明确时的粗略范围,不是承诺。建议由产品/UX、前端、后端、QA 组成,设备集成按实际硬件兼职或外协。真实硬件认证、短信/微信、票务/闸机和离线边缘部署会另行增加范围。
## 19. MVP 与后续版本
### MVP
- 员工代取与游客自助取号均要求手机号和同行人数;单号人数按项目范围校验且创建后不可修改。
- 同一手机号允许多个活动号码;员工确认重复提示后继续创建并留审计。
- 一个系统支持多个项目;员工按授权选择项目,各项目独立队列、票号、参数、设备和统计。
- 项目可按号码、按人数或同时支持两种叫号;严格 FIFO、连续、不拆号、不跳号并支持重叫、到场、过号、过号后新号排队尾、取消和完成。
- 游客私密状态页;大屏公开投影;实时事件与轮询降级。
- 简单的预计等待时间区间、暂停/停运降级。
- 管理端运营看板,以及项目/设置/账号/权限/日志/设备管理。
- 统一设备接口、成功/失败模拟器和测试日志;不接真实硬件。
- 中心服务唯一写入;断网停写并切换纸质号码和人工广播预案。
- 系统内置账号密码、RBAC 和项目权限;预留 OIDC/SSO。
- 已确认的个人关联 30 天、业务事件 90 天、安全日志 6 个月、后台审计 1 年和影响评估记录 3 年留存策略。
- 基础无障碍随 MVP 交付WCAG 2.2 AA 与 GB/T 37668-2019 基线、键盘/焦点、状态消息、对比度、200% 缩放和 reduced motion。
### P1
- 短信/微信通知、票务/闸机凭证核验。
- 优先队列、多个资源/班次、高级报表和预计时间统计、多语言,以及 AAA 级/专项辅助设备等无障碍增强。
- 更多硬件驱动、设备远程诊断、离线部署增强和独立设备网关。
- 员工手选、跳号、预叫、批次撤回和多维容量约束。
### P2
- 跨项目推荐与错峰引导、预约时段和同时持有号码策略。
- 在数据质量达标后评估更高级预测模型。
- 多景区/多租户、开放平台和外部运营数据中台。
## 20. 决策台账
### 20.1 已确认开发基线
- 四类访问视图:员工 H5、游客私密状态 H5、实体只读公示大屏以及包含运营概览、项目管理和大屏中心的 PC 管理端。
- 一个系统支持多个景区项目,所有业务通过 `project_id` 强隔离,但不为每个项目重复部署。
- 一个号码可绑定多名同行游客;手机号与同行人数必填,姓氏/称谓选填,称谓默认“游客”,不采集法定性别。
- 同一手机号允许多个活动号码;重复时脱敏提示、员工确认并审计。
- 每项目配置单号人数范围、支持的叫号方式,以及两种方式各自的默认值和防误触单次上限;不增加独立项目总容量上限。
- 过号后原号失效;重新排队必须创建新号进入队尾,并保留新旧票关联审计。
- 预计等待时间只保留单人预计间隔时间,并按本号前方实际人数计算。
- 中心服务是唯一写入权威;断网停写并切换纸质号码、人工广播等预案。
- 员工和管理员使用内置账号密码、RBAC 与项目权限,预留 OIDC/SSO。
- 前端 React后端 Go + GORM数据库 PostgreSQL模块化单体、单仓库、版本化 SQL 迁移。
- 首期硬件只做统一接口、成功/失败模拟器和测试日志。
- 留存采用已确认的 30 天个人关联、90 天原始业务事件、至少 6 个月安全日志、1 年后台审计和 3 年影响评估相关记录。
- 员工代取和游客自助取号共用统一排队事实源;公开创建接口只返回票号、手机号尾号和私密状态令牌,大屏仍只显示票号。
- 界面显示预计等待时间区间和更新时间,不承诺精确分钟,也不展示 ETA 缩写。
### 20.2 开发期间需要补齐的现场输入
下列输入用于参数校准、现场验收和后续集成立项,不是开始开发的阻塞项,也不得被解释为上述基线仍未确认:
- 试点项目的峰值容量、营业时间、单号人数范围、两种叫号默认值/防误触上限、宽限时间和单人间隔;
- 景区 VI、员工设备、大屏尺寸/阅读距离与网络质量;
- 纸质号码、人工广播、现场负责人和恢复联网后的应急切换流程;
- 未来真实硬件的型号、协议、驱动、网络拓扑、回执能力和安全边界;
- 票务、闸机、微信、短信等后续集成的明确范围。
### 20.3 主要风险与验证
| 风险 | 应对与验证 |
|---|---|
| 批量叫号重复/跳号 | 服务端原子事务、幂等、队列修订号、并发压测和审计回放 |
| 双模式与并发队列变更 | 锁定队列修订行后读取队首连续号码;覆盖人数欠载、队首超目标、取消穿插和并发叫号测试 |
| 预计时间被理解成承诺 | 区间、更新时间、停运降级;管理看板观察近期平均误差 |
| 大屏泄露个人信息 | 独立公开读模型、默认仅票号、自动化隐私测试 |
| 浏览器/硬件不兼容 | 首期用适配器契约和模拟器隔离;后续真实硬件专项再评估本地网关与指定设备认证清单 |
| 外网中断 | 已选择中心唯一写入;断网停写、展示最后快照并演练纸质号码/人工广播预案 |
| 规则被员工绕过 | 权限分层、主管审批、异常比例告警和不可删除审计 |
| 项目停运引发客诉/聚集 | 一键暂停/停运、全端公告、停止显示预计分钟、批量通知和现场预案 |
## 21. 开发启动状态
用户已经确认本文件 v1.1 的关键产品与技术决策,并明确授权执行。人数与双模式规则以本次修订为准,替代旧版“一人一号/固定 N”描述。
开发启动后按以下门槛推进:
- 首个里程碑先完成单试点项目垂直切片,再扩展完整管理看板与多项目体验;
- 状态机、号码/人数双模式叫号、过号新号排队尾、项目隔离和留存任务必须进入自动化验收;
- 首批项目容量、峰值、网络、VI 和设备资料在现场 UAT 前核实并用于校准;
- 隐私告知、展示、导出规则与已确认留存配置在正式上线前由责任人复核;
- 中心服务断网停写、RPO/RTO、纸质号码与人工广播预案在试点切换前演练
- 真实硬件不属于首期验收,任何接入必须以单独确认的型号和协议范围立项。