docs: 初始化仓库,加入需求、开发说明和任务拆分
This commit is contained in:
+581
@@ -0,0 +1,581 @@
|
||||
# NixMsg 产品需求
|
||||
|
||||
| 项 | 内容 |
|
||||
|---|---|
|
||||
| 版本 | 0.4 |
|
||||
| 日期 | 2026-09-30 |
|
||||
| 状态 | 待复核后交给开发 |
|
||||
| 读者 | 产品负责人、开发组、后续审核 |
|
||||
| 配套 | [DEVELOPMENT.md](./DEVELOPMENT.md) 是实现规范。两者冲突时,以本文已确认的产品行为为准,并在 `docs/DEVIATIONS.md` 记录 |
|
||||
| 修订 | 见第 11 节 |
|
||||
|
||||
## 1. 这是什么
|
||||
|
||||
NixMsg 是一套自建的消息中转服务。设备、程序、App 都作为「端」连到同一台服务器,端只用一个固定端口。端之间用端编号互发小消息,或在群里发同一条消息。
|
||||
|
||||
服务器负责:身份(开通、自助注册、登录)、在线状态、弱网重传、可选的离线暂存、定时和延迟发送、撤回、送达结果。服务器不保存聊天记录,也不提供业务聊天界面。业务界面由接入方自己做。我们提供管理后台和各语言 SDK。
|
||||
|
||||
一条消息的正文最大 256 KiB。更大的文件本期不传,以后用「先上传、再发链接」的方式做。
|
||||
|
||||
## 2. 要解决的问题
|
||||
|
||||
- 端与端之间隔着 NAT,不能互相直连,需要一台中转。
|
||||
- 网络会抖、会断。已经交给服务器的消息要尽量送到,对方短暂掉线时不要立刻丢掉。
|
||||
- 对方长时间不在线时,发送方自己决定留不留、留多久。
|
||||
- 发送方可以反悔,也可以指定过一会儿再发。
|
||||
- 多个端要能收同一条消息。
|
||||
- 有的端不希望陌生人给它发消息。
|
||||
- 接入方要在自己的 App 里让用户注册、登录、改密码,但不能让陌生人随便注册。
|
||||
- 接入方语言不同,需要少写连接代码;没有现成 SDK 的设备要能按协议直接接。
|
||||
|
||||
## 3. 名词
|
||||
|
||||
| 名词 | 含义 |
|
||||
|---|---|
|
||||
| 端 | 一个通讯身份。有唯一编号、登录密码,既能发也能收。程序、设备、App 登录后都是端。端由管理员开通,或在管理员开启注册后自己注册 |
|
||||
| 群 | 若干端的集合。发到群里的一条消息,内容只有一份,每个成员各有自己的送达结果 |
|
||||
| 登录密码 | 端连接服务器时使用。防止别人冒充这个编号 |
|
||||
| 会话令牌 | 用密码登录成功后服务器发给端的一串随机字符。之后断线重连都用它,不用密码,也和 IP 无关。每次用密码登录都会换新的,旧的立即作废 |
|
||||
| 对话密码 | 端自己可选的一道门。别人要单聊它,或把它拉进群,得先知道这道密码。不设置则谁都能给它发 |
|
||||
| 对话授权 | 服务器记住的「甲可以向乙单聊」。输对一次对话密码,或乙主动给甲发过单聊,都会形成授权。乙改对话密码后授权失效 |
|
||||
| 注册安全码 | 管理员设置的一串字符。开启自助注册后,注册时必须带上它。更换后只影响之后的注册 |
|
||||
| 提交 | 发送方把消息交给服务器,服务器写入存储并返回成功 |
|
||||
| 发送时刻 | 服务器真正开始投递的时间。可以是立即、延迟若干秒,或指定的未来时间 |
|
||||
| 投递 | 服务器把消息推给接收端 |
|
||||
| 收下 | 接收端处理完并向服务器确认。这时才算送到 |
|
||||
| 确认超时 | 消息推给在线端后,等它确认的最长时间,默认 5 分钟 |
|
||||
| 离线保留 | 发送时刻对方不在线时,把消息留在服务器,等它上线再推。按条选择 |
|
||||
| 保留时间 | 离线保留的最长期限,从发送时刻起算。超时还没收下就作废 |
|
||||
| 抖动宽限 | 对方刚断线的一小段时间(默认 60 秒)。这段里即使本条没有选择保留,也先等它重连 |
|
||||
| 撤回 | 发送方取消一条对方还没收下、且还没作废的消息 |
|
||||
| 回执 | 服务器告诉发送方某个接收端的最终结果:已收下、已过期、已丢弃、已拒绝。撤回的结果从撤回请求的返回里得到,不再发回执 |
|
||||
| 记录 | 不含正文的投递痕迹:谁发给谁、何时提交、何时发送、结果如何。给管理后台查询 |
|
||||
| 圈子 | 这一台服务器上的全部端。谁都能看到别人在不在线 |
|
||||
|
||||
## 4. 谁在用
|
||||
|
||||
| 角色 | 做什么 |
|
||||
|---|---|
|
||||
| 程序或设备 | 主要使用者。自动收发,收到就处理 |
|
||||
| 人 | 通过接入方自己的 App 或网页看消息、点发送;管理员开启注册时,也可以在接入方 App 里自己注册。本期不提供这套界面 |
|
||||
| 管理员 | 使用自带的网页后台:开通端、开关注册和设置注册安全码、改密码、看在线、管群、查送没送到 |
|
||||
|
||||
典型场景:
|
||||
|
||||
1. 后台给设备下发一条指令。设备当时不在线,指令保留 24 小时,上线后送到。设备回复时,若后台设了对话密码且曾经给设备发过单聊,设备不用再输密码。
|
||||
2. 人在网页里给一个端发消息,发出后 10 秒内可以撤回。
|
||||
3. 约定明天 8 点发到一个群。到点时按当时的群成员投递;选了保留的,不在线的成员上线后仍能收到同一条内容。
|
||||
4. 发送前先看对方在不在线,或列出当前在线的端。
|
||||
5. 接入方在自己的 App 里内置注册安全码,用户在 App 里注册、登录、改密码。管理员更换安全码后,旧版 App 不能再注册新用户,已注册的用户照常使用。
|
||||
|
||||
## 5. 本期做、本期不做
|
||||
|
||||
### 5.1 本期做
|
||||
|
||||
| 编号 | 能力 | 优先级 |
|
||||
|---|---|---|
|
||||
| F01 | 开通和管理端 | P0 |
|
||||
| F02 | 登录,同一编号只能一处在线 | P0 |
|
||||
| F03 | 查看在线和端目录 | P0 |
|
||||
| F04 | 上下线通知 | P0 |
|
||||
| F05 | 单聊 | P0 |
|
||||
| F06 | 群发 | P0 |
|
||||
| F07 | 消息内容与 256 KiB 上限 | P0 |
|
||||
| F08 | 至少送达一次、确认、去重、顺序 | P0 |
|
||||
| F09 | 离线保留和保留时间 | P0 |
|
||||
| F10 | 断线抖动宽限 | P0 |
|
||||
| F11 | 定时发送 | P0 |
|
||||
| F12 | 发送延迟(反悔窗口) | P0 |
|
||||
| F13 | 撤回 | P0 |
|
||||
| F14 | 回执 | P0 |
|
||||
| F15 | 对话密码和授权 | P0 |
|
||||
| F16 | 群管理 | P0 |
|
||||
| F17 | 网页管理后台和管理 API 令牌 | P0 |
|
||||
| F18 | 正文删除和投递记录 | P0 |
|
||||
| F19 | Go、Java/Android、JS/TS、Python SDK | P0 |
|
||||
| F20 | 无 SDK 时按协议用 MQTT 接入 | P0 |
|
||||
| F21 | 端只用一个固定端口,后台可用单独端口 | P0 |
|
||||
| F22 | 单文件或 Docker 部署、备份、升级、监控指标 | P0 |
|
||||
| F23 | 端自助注册(管理员开关、注册安全码) | P0 |
|
||||
|
||||
### 5.2 本期不做
|
||||
|
||||
- 大文件、分块、断点续传。后续另行做「上传文件后发送链接」。
|
||||
- 服务器保存历史供翻看。历史由各端自己存。
|
||||
- 同一编号同时在多台设备登录。要多台就开通多个端。
|
||||
- 多机集群。
|
||||
- 注册审核、邮箱或手机号验证。注册只靠注册安全码把关。
|
||||
- 忘记密码自助找回。忘记登录密码由管理员重置。
|
||||
- 端自己注销。需要时由管理员在后台删除。注意:接入方的 iOS App 如果提供注册,苹果审核要求 App 内能删除账号,届时需要补这项能力。
|
||||
- 已读(人有没有看)。只有「端有没有收下」。
|
||||
- 编辑已发消息。可以撤回后重发。
|
||||
- 端到端加密。传输可以用 TLS,服务器在投递完成前能看到正文。
|
||||
- 手机系统推送(APNs、FCM 等)。注意:手机 App 退到后台后,连接通常会被系统挂起,没有系统推送就收不到新消息提醒;人用的聊天场景要考虑这一点。
|
||||
- 管理员在后台代发或代撤回。
|
||||
- 多个管理员角色。本期一个管理员账号。
|
||||
- 嵌入式 C 语言 SDK。小设备按 F20 直接接 MQTT。
|
||||
|
||||
## 6. 功能需求
|
||||
|
||||
优先级 P0 为本期必须完成。每条都包含规则和验收。
|
||||
|
||||
### F01 开通和管理端
|
||||
|
||||
端由管理员开通,或在管理员开启注册后由端自己注册(F23)。两种方式开出来的端没有区别。
|
||||
|
||||
- 编号 1–64 字符,只能是小写字母、数字、`_`、`.`、`-`,全局唯一。留空则服务器生成,形如 `e_` 加 8 位小写字母数字。不允许大写,是为了避免 `Alice` 和 `alice` 这类看起来相同的编号互相冒充。
|
||||
- 名称可选,最多 64 个 Unicode 字符。备注可选,最多 200 字符。
|
||||
- 登录密码 8–128 字符,不能以 `nst_` 开头(这个前缀留给会话令牌)。留空则生成随机密码,只在创建成功时显示一次。
|
||||
- 对话密码可选,4–64 字符。空表示不设防。
|
||||
- 可设置默认发送延迟,单位秒,默认 0。
|
||||
- 支持批量开通:上传 CSV 文件(UTF-8),列为编号、名称、登录密码、对话密码、默认延迟、备注,一次最多 1000 行。先整体检查,有任何一行不合格就一行都不开通,并列出出错的行和原因。密码留空则生成,生成的密码只在结果里出现这一次,可以下载保存。
|
||||
- 可改名称、备注、默认延迟、启停、删除、重置登录密码、设置或清除对话密码、踢下线、解除登录锁定。重置登录密码会让它的会话令牌作废。踢下线只断开当前连接,令牌不变,SDK 会自动重连;要让它连不上,请停用。
|
||||
- 停用:立刻断开,不能再登录;发给它的新消息提交失败;尚未送到它的消息作废,原因 `endpoint_disabled`;它自己发出、还没推送出去的消息也作废,原因 `sender_disabled`。重新启用后可以正常登录,已作废的消息不恢复。
|
||||
- 删除:在停用的效果之外(原因记为 `endpoint_deleted`、`sender_deleted`),退出所有群;它当群主的群转给最早加入的成员,群里没有别人则解散;清掉与它相关的授权、它的待送回执和它发出的消息记录。编号删除后可以重新开通或注册,新端不继承任何旧数据。
|
||||
|
||||
验收:
|
||||
|
||||
- 一次批量开通 1000 个端成功,生成的密码不写入日志。CSV 里有一行编号重复时,一个端都不开通,并指出是哪一行。
|
||||
- 停用后该端立刻离线,发给它的新消息被拒绝,发给它的定时未到点的消息作废;它停用前提交、还没到点的定时消息也不再发出。
|
||||
- 删除群主后,群主变为剩余成员里最早加入的那个。
|
||||
- 删除一个端后用同一编号重新开通,新端收不到旧端的回执。
|
||||
|
||||
### F02 登录、会话令牌与单连接
|
||||
|
||||
- 首次登录用端编号和登录密码。登录成功后服务器发给端一个会话令牌,之后断线重连都用这个令牌,不再用密码。令牌和 IP 无关:设备换网络、换 IP,或者服务器重启后,都直接用令牌重连。
|
||||
- 同一编号同时只有一个有效会话。每次用密码登录都换一个新令牌,旧令牌立即作废(D28):
|
||||
- 旧设备当时在线:当场被踢下线,原因是「已在别处登录」,停止自动重连并通知应用。
|
||||
- 旧设备当时不在线:之后用旧令牌重连会被拒绝,SDK 通知应用「会话已失效」并停止重连,需要重新用密码登录。
|
||||
- 用令牌重连不算新登录,令牌不变。
|
||||
- 应用应该保存令牌,而不是密码。令牌 30 天没用过自动失效(可配置,0 表示不失效),之后要重新用密码登录(D29)。应用退出登录时调用 SDK 的退出,服务器作废令牌。
|
||||
- 端可以自己改登录密码,必须提供旧密码。当前连接保持,并拿到新令牌。
|
||||
- 管理员重置登录密码、停用、删除:令牌作废,当前连接被踢下线,停止自动重连。管理员「踢下线」只断开连接,令牌不变,SDK 会自动重连。
|
||||
- 密码输错会临时锁定。锁定只针对用密码登录,用令牌重连不受影响,所以已登录的设备换 IP、断线重连都不会被锁(D18):
|
||||
- 同一编号在同一来源 IP 上 5 分钟内错 10 次,锁定这个组合 5 分钟。设备换了 IP,不会被别的 IP 上的失败牵连。
|
||||
- 同一编号不论来源 IP,1 小时内错 50 次,暂停这个编号的密码登录 1 小时,防止有人不断换 IP 猜密码。管理员可以在后台解除锁定。
|
||||
- 登录失败要分清两类:密码错误、会话已失效、编号不存在、已停用、已锁定,SDK 停止重连并通知应用;服务器暂时不可用(例如数据库故障、连接数已满),SDK 继续重连。
|
||||
|
||||
验收:
|
||||
|
||||
- A 设备在线时,B 设备用密码登录同一编号:A 被踢下线且不再重连,B 可用。
|
||||
- A 设备离线期间,B 设备用密码登录;A 恢复网络后用旧令牌重连被拒,SDK 报「会话已失效」且不再重连。
|
||||
- 设备换了 IP(例如 Wi-Fi 切到 4G)后,用令牌自动重连成功,不需要密码。
|
||||
- 错误密码达到上限后,同一 IP 用正确密码在锁定期内也被拒绝,锁定期过后可以登录;换一个 IP 用正确密码不受影响。
|
||||
- 从多个 IP 轮流猜同一编号的密码,达到总数后这个编号暂停密码登录;已登录的设备断线后用令牌照常重连;管理员解除锁定后可以用密码登录。
|
||||
- 服务器数据库不可用时,SDK 不会进入「密码错误」状态,恢复后自动连上。
|
||||
|
||||
### F03 在线状态与目录
|
||||
|
||||
任何已登录的端都可以:
|
||||
|
||||
- 查询若干编号是否在线。
|
||||
- 分页列出全部端。每项包含编号、名称、是否在线、最近上线时间、最近离线时间、是否设置了对话密码。不包含密码本身,也不包含「我是否已获授权」。
|
||||
|
||||
在线以服务器上的真实连接为准。心跳超时未收到数据即判离线。默认心跳 30 秒,超时按协议的 1.5 倍,约 45 秒。
|
||||
|
||||
验收:
|
||||
|
||||
- 正常断开后 1 秒内,别人查到的状态为离线。
|
||||
- 拔掉网线后,在心跳超时窗口内变为离线。
|
||||
- 1000 个端同时在线时,拉全表在 1 秒内返回。
|
||||
|
||||
### F04 上下线通知
|
||||
|
||||
端可以订阅某些编号的上下线,也可以订阅全部。变化时收到通知。通知尽力送达,不落库、不补发。连接断开后订阅清空,SDK 在重连后按应用上次的选择重新订阅;应用需要准确状态时,重连后再查一次在线状态。
|
||||
|
||||
验收:订阅 A 后,A 上下线各收到一次通知;没订阅的 B 上下线不收到。
|
||||
|
||||
### F05 单聊
|
||||
|
||||
- 端可以给另一个端发消息,也可以给自己发(用于定时提醒)。发给自己不需要对话密码。
|
||||
- 每条消息由发送方提供消息号,SDK 自动生成。1–64 字符,字母、数字、`_`、`.`、`-`,区分大小写。同一发送方不要重复使用消息号。
|
||||
- 服务器把消息落入存储后才返回提交成功。返回前宕机,客户端按未提交处理并重试。
|
||||
- 用同一消息号、同一请求内容重试,返回原来的结果,不产生第二条;即使对方在两次之间停用或改了对话密码,也以第一次的结果为准。同一消息号但请求内容不同(目标、正文、选项有任何不同),返回冲突。服务器至少在 24 小时内(防重窗口,可配置)识别重试;这条消息的记录还在时也一直识别。
|
||||
- 对方不存在、已停用、已删除:提交失败并给出原因。
|
||||
- 对方设了对话密码且发送方没有有效授权:提交失败,错误为需要对话密码。本条请求里带上正确密码则授权并提交成功。
|
||||
- 每个端默认每秒最多 50 个请求(可短时突发到 100,确认类请求不算),可配置。用一个端集中下发大量消息的接入方,可以调高或改用群发。
|
||||
- 每个端同时处于「等待发送」或「投递中」的消息最多 10000 条(群消息算一条),超出时提交失败;每个端排队等它收下的投递最多 10000 条,超出时新来的投递直接拒绝,原因 `queue_full`,发送方收到回执。两个上限都可配置,设为 0 表示不设上限(D25),用来防止一个端把服务器磁盘塞满。
|
||||
|
||||
验收:
|
||||
|
||||
- 提交成功后立刻杀掉服务器进程,重启后这条消息仍会投递。
|
||||
- 同一消息号连续提交两次,接收方只处理一次。同一消息号换了正文再提交,返回冲突。
|
||||
- 未授权时不带密码被拒绝;带对密码后成功,之后不带密码也能再发。
|
||||
- 一个端未完成的消息达到上限后,新提交失败;接收端排队达到上限后,新投递被拒绝,发送方收到回执。
|
||||
|
||||
### F06 群发
|
||||
|
||||
- 提交时发送方必须是群成员。到发送时刻发送者已不在群里:消息作废,不再投递。
|
||||
- 内容只存一份。每个接收成员一条投递结果。
|
||||
- 接收者是发送时刻的成员,不含发送者本人。已停用的成员收不到,结果记为已拒绝。
|
||||
- 发送时刻之后才入群的端收不到。发送时刻之前已退群的端收不到。
|
||||
- 群消息不看成员的对话密码。
|
||||
|
||||
验收:
|
||||
|
||||
- 群内 A、B、C,A 发送,B 和 C 收到同一消息号、同一内容,A 自己不收到。
|
||||
- A 发送时选了离线保留,B 当时离线,B 在保留时间内上线后收到的内容与 C 相同。
|
||||
- B 在发送时刻之后入群,收不到这条。
|
||||
|
||||
### F07 内容与大小
|
||||
|
||||
- 正文是 UTF-8 文本,或二进制(线上用 Base64)。可带内容类型。
|
||||
- 自定义键值附在消息上,序列化后不超过 4 KiB。
|
||||
- 正文解码后最大 256 KiB(262144 字节)。这个上限可以调小,本期不能调大。超过则发送端直接失败,服务器不接收。
|
||||
- 接收端可在登录握手时声明自己一次最多能收多少字节(按服务器推来的整条数据计算,不小于 1024)。某条投递超过该值:这条投递拒绝,原因 `too_large`,不重试,并回执发送方。
|
||||
- 不做分块,不做断点续传。
|
||||
|
||||
验收:
|
||||
|
||||
- 256 KiB 文本可以送达。多 1 字节在 SDK 本地失败;绕过 SDK 直接提交过大的正文,服务器拒绝且不产生投递。
|
||||
- 声明只能收 1024 字节的端,收到一条 2048 字节消息的投递结果是拒绝,发送方收到对应回执,这个端的连接不受影响。
|
||||
|
||||
### F08 投递、确认、重复和顺序
|
||||
|
||||
- 到了发送时刻且对方已完成登录握手:立刻推送。
|
||||
- 接收方处理完成后确认。SDK 默认在收到回调正常返回后自动确认;也可以改成应用自己调用确认。
|
||||
- 处理回调抛错则不确认。选了离线保留的消息,在保留时间内服务器会在重连后或确认超时后再推;不保留的消息推送后确认超时仍未确认,按已丢弃结束(D19)。应用必须能接受同一条到达多次。
|
||||
- 保证的是至少送到一次。弱网上可能重复。SDK 在进程运行期间按「发送方编号 + 消息号」去重后再交给应用,默认记住最近 10000 条;已经确认过的消息再次到达时,SDK 直接再确认一次,不交给应用。进程重启后,重启前没确认的消息可能再到一次。
|
||||
- 同一接收端按发送时刻排序;发送时刻相同则按提交先后。SDK 对同一连接上的回调串行执行。重推的消息可能排在后面的消息之后。
|
||||
- MQTT 传输层的确认只表示服务器收到了请求。对方收下以应用层确认为准。
|
||||
|
||||
验收:
|
||||
|
||||
- 弱网(延迟、丢包、随机断开)下,选择了离线保留且在保留期内的消息最终全部送达;SDK 进程不重启时,交给应用的回调不重复。
|
||||
- 服务器在已返回提交成功后强制重启,未收下的消息会继续投递。
|
||||
|
||||
### F09 离线保留
|
||||
|
||||
- 每条消息选择是否保留,默认不保留。
|
||||
- 保留时指定时长,默认 24 小时,最长 30 天(可配置)。从发送时刻起算,定时等待的时间不算进去。
|
||||
- 超时仍未收下:结果为已过期,正文删除。
|
||||
- 已经推给在线端、正在等确认的消息,这一轮等待(最长一个确认超时)里不会因为保留时间到了而作废;这一轮结束仍未确认且已过保留期限,按已过期结束,否则再推。
|
||||
|
||||
验收:
|
||||
|
||||
- 保留 1 小时,对方 30 分钟后上线,能收到。
|
||||
- 对方 2 小时后才上线,收不到,发送方得到已过期。
|
||||
- 指定明天 8 点发送、保留 1 小时:在明天 8 点之前一直处于等待发送;8 点才开始算 1 小时。
|
||||
|
||||
### F10 抖动宽限
|
||||
|
||||
- 不保留,且发送时刻对方不在线:若对方在宽限内刚断线(默认 60 秒),先等到宽限结束;期间重连则照常推送,宽限结束仍不在则丢弃。
|
||||
- 从未上线或断线已超过宽限:不保留的消息立即丢弃。
|
||||
- 正在推送时连接断开:无论是否保留,至少再等一个宽限。保留消息的截止时间若早于「现在 + 宽限」,延长到「现在 + 宽限」。
|
||||
- 服务器重启时,所有未完成的投递按对方刚断线处理:至少再等一个宽限,端在宽限内重连就能收到(D23)。
|
||||
|
||||
验收:
|
||||
|
||||
- 不保留。对方断网 30 秒内恢复,消息送到。
|
||||
- 不保留。对方断网超过 2 分钟,消息丢弃,发送方收到已丢弃。
|
||||
- 不保留。服务器重启后端在 30 秒内重连,重启前没收下的消息仍能送到。
|
||||
|
||||
### F11 定时发送
|
||||
|
||||
- 发送方指定未来的发送时刻,以服务器时钟为准。SDK 用握手返回的服务器时间校正本机偏差。
|
||||
- 提交成功后发送方可以下线,到点由服务器投递,然后再走 F09、F10。
|
||||
- 最远可定到 365 天后(可配置)。指定时间已过则立即发送。
|
||||
- 服务器停机期间到点的定时消息,启动后立即发送。
|
||||
- 定时与「延迟秒数」不要同时使用。同时使用则提交失败。指定了发送时刻时,不再叠加端的默认延迟。
|
||||
|
||||
验收:提交一条 2 分钟后发送的消息,发送方立刻断开;2 分钟后接收方在线则收到,不在线则按是否保留处理。
|
||||
|
||||
### F12 发送延迟
|
||||
|
||||
- 端可以固定默认延迟。每条消息也可以单独指定延迟秒数,指定 0 表示这条立即发送。都没指定则立即发送。
|
||||
- 延迟由服务器时钟计算:发送时刻 = 服务器当前时间 + 延迟。
|
||||
- 在发送时刻之前消息还在服务器上,撤回一定成功。这就是反悔窗口。
|
||||
|
||||
验收:默认延迟 10 秒。发送后 3 秒撤回,接收方永远收不到。超过 10 秒且对方在线,消息已经进入投递。
|
||||
|
||||
### F13 撤回
|
||||
|
||||
- 只有发送方能撤回。管理员不能代撤。
|
||||
- 对象是已提交、接收方尚未收下、且尚未结束(过期、丢弃、拒绝)的消息。
|
||||
- 还没到发送时刻:一定成功,之后不再发送。
|
||||
- 已在离线保留中、尚未推送:一定成功。
|
||||
- 已经推给在线端但对方还没确认:撤回和确认谁先被服务器记下来谁生效。撤回先到,则对方之后的确认会得知已撤回,SDK 发出撤回事件;应用如果已经处理了这条,由应用自己决定怎么撤销(例如隐藏)。确认先到则撤回失败(或群里该成员失败)。
|
||||
- 已经收下、已过期、已丢弃、已拒绝:不能撤回。
|
||||
- 群消息:还没收下的成员全部撤回;已经收下的成员保持已收下。至少撤回一个且没有成员已收下,结果为「全部撤回」;有撤回也有已收下,为「部分撤回」;一个都没撤回,为「失败」。已经过期、丢弃、拒绝的成员不影响结果。
|
||||
- 撤回的结果在撤回请求的返回里给出,不再为撤回单独发回执(D20)。
|
||||
- 撤回不收回已经形成的回复授权(F15 第 2 种授权,D22)。
|
||||
|
||||
验收:
|
||||
|
||||
- 延迟窗口内撤回,接收方无回调。
|
||||
- 对方离线且在保留中,撤回后上线也收不到。
|
||||
- 群里一人已确认、一人未推送:结果为部分撤回,未推送的成员收不到,已确认的成员仍保留本地副本。
|
||||
|
||||
### F14 回执
|
||||
|
||||
- 每条消息默认要回执,可以按条关闭。
|
||||
- 每个接收端一条最终回执:已收下、已过期、已丢弃、已拒绝。
|
||||
- 发送方当时不在线:回执保留,默认最多 7 天,上线后补送。回执可以重复到达,SDK 按回执号去重。
|
||||
- 关闭回执的消息不占这份队列。管理后台仍能按 F18 查记录。
|
||||
|
||||
验收:接收方确认后发送方收到已收下。发送方离线期间对方确认,发送方重连后补收到回执。
|
||||
|
||||
### F15 对话密码
|
||||
|
||||
- 不设置:任何端都能向它单聊。
|
||||
- 设置后,向它单聊必须有有效授权。授权只有两种:
|
||||
1. 发送时或单独解锁时输对当前对话密码。
|
||||
2. 对方曾经成功提交过发给我的单聊。群消息不算。
|
||||
- 授权只看提交那一刻。提交成功之后对方才改密码,这条已提交的消息照常投递。改密码只让之后的新发送重新验证。
|
||||
- 对方改密码后,旧授权全部失效,包括「它先给我发过消息」带来的回复权。
|
||||
- 把它拉进群时,这一次请求里必须带上它当前的对话密码,已有单聊授权也不能省略。管理员在后台拉人例外,不需要密码。
|
||||
- 进群之后,群消息直接送达,不再逐条要密码。
|
||||
- 对话密码连续猜错会临时锁定这一对端。默认与登录锁定相同:5 分钟 10 次。另外按被猜的端计总数:1 小时内被猜错 50 次,暂停验证它的对话密码 1 小时,已有授权照常可用;它改对话密码时计数清零(D24)。这是为了防止有人注册很多账号轮流猜,4 位的对话密码经不起这样猜。
|
||||
- 不希望被大量回复的发送方(例如给很多端发通知的后台端),可以改用群发:群消息不产生回复授权。
|
||||
|
||||
验收:
|
||||
|
||||
- B 设了密码。A 不带密码发送失败;带对一次后,第二条不再带密码也成功。
|
||||
- B 改密码后,A 的下一条失败,直到重新输对新密码。
|
||||
- B 先给 A 发单聊,A 立刻可以回复且不用密码。B 改密码后,A 再回复失败。
|
||||
- A 已能给 B 单聊,把 B 拉进群时仍要带对话密码;密码错误则 B 不进群。
|
||||
- B 改密码时,A 此前已提交、尚在延迟中的消息到点仍会送达。
|
||||
- 多个账号轮流猜 B 的对话密码,达到总数上限后,正确密码也暂时无法解锁;已有授权的端照常发给 B。
|
||||
|
||||
### F16 群
|
||||
|
||||
- 已登录的端可以建群,建群者是群主。管理员也可以建群并指定群主,群主同时是成员。
|
||||
- 编号规则同端编号(小写字母、数字、`_`、`.`、`-`),留空则生成,形如 `g_` 加 8 位。名称最多 64 字。
|
||||
- 群主可以改名、加人、踢人、转让群主、解散。成员可以自己退出。群主不能直接退出,要先转让;只剩群主一人时可以解散。
|
||||
- 加人时对设了对话密码的端适用 F15。已停用的端不能加入。一次请求里可以带多个成员,校验失败的成员不加入,其余加入,结果里列出失败原因。
|
||||
- 踢出或退出:尚未推送的投递作废,原因 `left_group`;已经推送、尚未确认的,向该端发作废通知。
|
||||
- 解散:全体未完成投递作废;发往该群、还没到发送时刻的消息也立即作废,原因 `group_dissolved`。群编号之后可以被重新使用,新群收不到旧群的任何消息。
|
||||
- 群主被删除:群主转给最早加入的其他成员;没有其他成员则解散。
|
||||
- 成员数默认上限 1000,可配置。
|
||||
|
||||
验收:
|
||||
|
||||
- 非群主加人失败。群主把设密端拉入时密码错误,该端不在成员里,群本身创建成功。
|
||||
- 成员退出后收不到之后的消息,也收不到退出前已提交但还没推送的消息。
|
||||
- 解散群后立刻用同一编号建新群,旧群里还没到点的定时消息不会发给新群。
|
||||
|
||||
### F17 管理后台
|
||||
|
||||
网页后台,界面中文。功能:
|
||||
|
||||
- 登录、修改管理员自己的密码、退出。
|
||||
- 概览:端数量(其中自助注册的数量)、在线数、群数量、待投递数、版本。
|
||||
- 端:查询(可按来源筛选:后台开通、自助注册)、开通、批量开通、编辑、启停、删除、重置登录密码、设置或清除对话密码、踢下线、解除登录锁定。列表显示是否在线、最近上下线时间、来源;支持多选后批量停用、删除,方便清理异常注册。
|
||||
- 注册:开启或关闭自助注册;查看、手填或生成注册安全码。
|
||||
- 群:查询、创建、改名、成员增减、转让、解散。
|
||||
- 投递记录:按发送方、接收方、群、状态、时间筛选。只显示记录,不显示正文。点开可看每个接收端的结果、原因、推送次数、时间。
|
||||
- API 令牌:管理员可以创建多个令牌(填名称),令牌只在创建时显示一次;可以停用、启用、删除,列表显示最近使用时间。接入方自己的后台带令牌调用同一套管理接口,用程序完成开通、停用、重置密码等操作。令牌不能改管理员密码,也不能管理令牌(D27)。
|
||||
- 每个改变状态的操作都记日志:谁做的(管理员或哪个令牌)、做了什么、对象是谁。
|
||||
- 运行参数本页只读,改参数通过配置文件。管理员密码、注册开关、注册安全码和 API 令牌在后台修改。
|
||||
|
||||
验收:
|
||||
|
||||
- 用后台完成开通、改密、开启注册并设置安全码、建群、查看一条未完成投递。正文在页面、接口和浏览器网络响应里都不出现。
|
||||
- 创建一个 API 令牌,用它通过管理接口开通一个端并重置密码;用它改管理员密码被拒绝;停用令牌后立即不能再用。
|
||||
|
||||
### F18 正文删除与记录
|
||||
|
||||
- 一条消息的全部投递都进入最终状态,或在发送前被撤回、作废:立即删除正文。
|
||||
- 记录默认保留 7 天,可配置。设为 0 则完成后连记录一起删除,后台只能看到尚未完成的消息。
|
||||
- 防重标记另存「发送方 + 消息号 + 请求指纹」,不含正文。默认保留 24 小时,消息记录还在时一直保留。这是为了弱网重试不产生第二条,不是历史记录。
|
||||
- 日志里不写正文、登录密码、对话密码、注册安全码。
|
||||
- 备份文件里包含备份当时还没送完的正文,要按敏感数据保管。
|
||||
|
||||
验收:接收方确认后,数据库和后台都读不到正文。保留天数设为 0 时,完成后后台列表不再出现这条。24 小时内重试同一消息号仍不重复投递。
|
||||
|
||||
### F19 SDK
|
||||
|
||||
第一批:Go、Java/Android、JavaScript/TypeScript(浏览器和 Node.js)、Python。
|
||||
|
||||
四种 SDK 行为一致:
|
||||
|
||||
- 注册(管理员开启注册时可用,需要注册安全码,不需要先登录)。
|
||||
- 登录与会话:首次用密码登录,把拿到的会话令牌交给应用保存;之后重连用令牌;令牌失效时通知应用重新登录;退出登录时作废令牌。
|
||||
- 连接、自动重连、心跳。被踢下线、密码错误、会话已失效、编号停用或删除时停止重连;服务器暂时不可用时继续重连。
|
||||
- 发送(单聊、群、延迟、定时、是否保留、保留时长、是否要回执、附带对话密码)。
|
||||
- 撤回、查询本条状态、解锁对话密码。
|
||||
- 收消息、收回执、收撤回或作废、去重、自动或手动确认。
|
||||
- 在线查询、目录、上下线订阅。
|
||||
- 建群、改名、加人、踢人、退出、转让、解散、我的群列表。
|
||||
- 修改自己的名称、默认延迟、登录密码(需要旧密码)、对话密码。
|
||||
- 发送方暂时连不上服务器时,发送进入内存队列,重连后按原消息号再交;已经发出但没等到结果的也一样。进程退出则队列丢失。除发送以外的请求在离线时直接失败。
|
||||
- 本机时间与服务器偏差由 SDK 校正后再计算定时发送。
|
||||
|
||||
验收:每种语言都通过 DEVELOPMENT.md 里的同一份接入清单。清单覆盖注册、登录、收发、去重、重连、离线队列、撤回、定时、群、对话密码、改密、被踢、超限。
|
||||
|
||||
### F20 无 SDK 接入
|
||||
|
||||
不提供 C SDK。设备用 MQTT 5 按 DEVELOPMENT.md 的帧格式接入,至少能:登录、收消息、确认、发送、声明自己能接收的最大字节数。能发 HTTP 请求的设备也可以调用注册接口;不能的由管理员开通。设备可以每次都用密码登录(每次都算新登录、会换令牌,只有这一台设备时没有影响),也可以保存会话令牌用来重连。
|
||||
|
||||
验收:用一个不依赖四套 SDK 的 MQTT 客户端走通登录、发送、接收、确认。
|
||||
|
||||
### F21 端口
|
||||
|
||||
- 端只用一个固定端口连服务器(默认 7443)。这个端口同时提供:MQTT over WebSocket(路径 `/mqtt`,子协议 `mqtt`)、MQTT over TCP(给跑不动 WebSocket 的设备)、注册接口。TLS 和明文在同一端口上自动识别。
|
||||
- 管理后台默认也在这个端口。可以配置成单独端口,例如只监听内网或本机地址,不对公网暴露;配置后,端接入端口不再提供后台。
|
||||
- 内置 MQTT 不单独占端口。本期不需要 Redis 或其他中间件。
|
||||
- 配置了证书则默认只接受 TLS。没有证书时允许明文,并在启动日志里明确警告。是否额外允许明文可配置。
|
||||
- 证书文件更新后自动生效,不用重启。程序本身不申请证书;生产环境由服务器上的 1Panel 申请和自动续签,并推送到本地目录给程序读取(见 DEVELOPMENT.md 第 11.3 节)。
|
||||
|
||||
验收:
|
||||
|
||||
- 默认配置只开一个端口:浏览器能打开后台,SDK 能用 WebSocket 注册和收发,一个裸 MQTT TCP 客户端能登录。
|
||||
- 配置单独的后台端口后:后台只能从后台端口打开,端接入端口上访问后台返回 404,端的注册和收发不受影响。
|
||||
|
||||
### F22 部署与运维
|
||||
|
||||
- 一个 Go 程序,一个可执行文件,内置 MQTT 和网页。不另外部署数据库、消息队列或缓存。
|
||||
- 同时提供 Docker 镜像(amd64、arm64)和 docker-compose 示例,装有 1Panel 的服务器可以直接用它的容器编排部署。
|
||||
- 数据在一个目录里的 SQLite 文件。
|
||||
- 首次使用先运行初始化命令生成管理员密码(只在终端显示一次,不写日志),再启动服务。
|
||||
- 提供备份命令。升级时自动迁移数据库;迁移前自动把库复制一份。
|
||||
- 提供健康检查接口,以及 Prometheus 格式的监控指标(在线数、待投递数、投递耗时等,不含正文和编号明细)。指标只在后台端口上开放;后台和端共用端口时,要带配置的令牌才能访问。
|
||||
|
||||
验收:
|
||||
|
||||
- 空目录运行初始化命令后启动,可登录后台。二进制和 Docker 镜像(两个架构)都能这样启动。
|
||||
- 备份文件能在另一目录启动并看到原来的端。旧版本数据经过一次升级后端和未完成消息都在。
|
||||
- 替换证书文件后,不重启服务,新连接在 1 小时内用上新证书。
|
||||
- Prometheus 能抓到指标;共用端口时不带令牌抓不到。
|
||||
|
||||
### F23 端自助注册
|
||||
|
||||
管理员可以允许端自己注册,接入方就能在自己的 App 里做注册、登录、改密码。
|
||||
|
||||
- 默认关闭。管理员在后台开启,并设置注册安全码(8–64 字符,可以手填或让系统生成)。关闭时任何注册都失败。
|
||||
- 注册必须带当前的注册安全码,错误则失败。
|
||||
- 管理员随时可以更换安全码或关闭注册。已注册的端不受影响,照常登录收发;之后的注册必须用新安全码,旧码无法注册。
|
||||
- 注册时填写:编号(可留空,由服务器生成)、登录密码(可留空,由服务器生成并只返回一次)、名称(可选)、对话密码(可选)。规则同 F01。编号已被占用则失败。
|
||||
- 注册成功即可登录,不需要管理员审核。后台把这类端标记为「自助注册」,管理员可以像其他端一样停用、删除、重置密码。
|
||||
- 注册在端接入端口上完成,不需要先登录。同一来源 IP 连续输错安全码会临时锁定:默认 5 分钟 10 次,锁定 5 分钟。
|
||||
- 注册之后的改名称、改默认延迟、改登录密码(需要旧密码)、改对话密码,都由端登录后通过 SDK 完成(F19)。
|
||||
- 开放注册后,注册者和其他端一样能看到目录(全部端的编号、名称和在线状态),也能给没设对话密码的端发消息。圈子规则不变(D26)。需要防陌生人的端应设置对话密码。
|
||||
- 安全码内置在 App 里时,拿到安装包的人就能取出来。它挡的是没有 App 的人,不能证明注册者身份;泄露后换码即可,已注册的端不受影响。
|
||||
- 服务对公网开放注册时应配置证书,否则安全码和密码会以明文经过网络。
|
||||
|
||||
验收:
|
||||
|
||||
- 注册关闭时,带正确安全码也注册失败。
|
||||
- 开启后,错误安全码失败,正确安全码成功,注册出的端能立即登录。
|
||||
- 管理员更换安全码后,旧码注册失败、新码成功;更换前已注册的端照常登录收发。
|
||||
- 同一 IP 连续输错安全码达到上限后,锁定期内带正确安全码也被拒绝。
|
||||
- 编号已存在时注册失败,原有端不受影响。
|
||||
|
||||
## 7. 消息怎么走
|
||||
|
||||
```mermaid
|
||||
stateDiagram-v2
|
||||
[*] --> 等待发送: 提交成功
|
||||
等待发送 --> 已撤回: 发送时刻前撤回
|
||||
等待发送 --> 已拒绝: 到点前或到点时发现对方已停用或删除、群已解散、发送者已退群或被停用
|
||||
等待发送 --> 投递中: 到发送时刻
|
||||
投递中 --> 已收下: 接收端确认
|
||||
投递中 --> 已撤回: 确认前撤回成功
|
||||
投递中 --> 已过期: 保留期限到,或确认超时时已过保留期限
|
||||
投递中 --> 已丢弃: 不保留且宽限结束仍离线,或推送后确认超时
|
||||
投递中 --> 已拒绝: 退群、停用、删除、超过对方接收上限等
|
||||
已收下 --> [*]
|
||||
已撤回 --> [*]
|
||||
已过期 --> [*]
|
||||
已丢弃 --> [*]
|
||||
已拒绝 --> [*]
|
||||
```
|
||||
|
||||
群消息是同一张图的多份投递。全部投递都结束后删除正文。
|
||||
|
||||
| 结果 | 何时 | 发送方能否撤回 |
|
||||
|---|---|---|
|
||||
| 等待发送 | 没到发送时刻 | 能,一定成功 |
|
||||
| 投递中,还没推送 | 离线保留、宽限中,或在排队等推送 | 能,一定成功 |
|
||||
| 投递中,已推送 | 在线但还没确认 | 能发起,和确认抢先 |
|
||||
| 已收下 | 端已确认 | 不能 |
|
||||
| 已过期 / 已丢弃 / 已拒绝 | 已经结束 | 不能 |
|
||||
|
||||
## 8. 非功能需求
|
||||
|
||||
| 项 | 要求 |
|
||||
|---|---|
|
||||
| 规模 | 单机 1000 个端同时在线,端总数按 1 万设计。内部连接上限按 2000 留余量 |
|
||||
| 容量 | 记录量约等于每天消息数乘以保留天数。按每天 100 万条、保留 7 天设计,后台带筛选的查询在 1 秒内返回 |
|
||||
| 吞吐 | 验收环境能持续每秒 200 条单聊提交;一条 1000 人群消息能在 5 秒内完成推送排队 |
|
||||
| 延迟 | 双方在线、消息小于 1 KiB 时,从提交成功到对方回调,机房内 P95 小于 300 毫秒 |
|
||||
| 可靠 | 已返回提交成功的消息,进程崩溃后仍在。断电最多丢失最后一次尚未落盘的写入;默认使用最严格的 SQLite 同步 |
|
||||
| 弱网 | 20% 丢包、2 秒延迟、随机断开下,保留期内消息最终全部送达,SDK 进程不重启时应用层无重复 |
|
||||
| 安全 | 密码单向哈希,会话令牌和管理 API 令牌只存哈希;登录、对话密码、注册安全码、管理员登录和令牌都防暴力尝试;后台 Cookie 不可被脚本读取;日志无正文、无密码、无注册安全码、无令牌;端只能订阅自己的下行 |
|
||||
| 时间 | 服务器时钟为准。定时消息在时钟被人为大改时按新时钟触发,这一点写入运维说明 |
|
||||
| 兼容 | MQTT 5 为主。MQTT 3.1.1 仅保证能连接和收发 QoS 1,帧格式仍是同一套 JSON;3.1.1 设备被顶号时看不到原因 |
|
||||
|
||||
## 9. 写进本文的默认
|
||||
|
||||
下面是写文档时定下的默认规则。「已确认」是负责人已经认可的;「待确认」的在交给开发前还可以改,改的话同步改本文和 DEVELOPMENT.md 对应小节。D14 起是 0.2 新增,D26 起是 0.3 新增,D28 起是 0.4 新增。
|
||||
|
||||
| 编号 | 默认 | 状态 |
|
||||
|---|---|---|
|
||||
| D1 | 改对话密码不影响已经提交成功的消息 | 已确认 2026-09-30 |
|
||||
| D2 | 拉人进群必须在当次请求里带对话密码;已有单聊授权不能代替。管理员后台例外 | 已确认 2026-09-30 |
|
||||
| D3 | 回执默认开启,发送方离线时回执最多留 7 天 | 已确认 2026-09-30 |
|
||||
| D4 | 不保留的消息,对方断线未超过 60 秒时先等重连 | 已确认 2026-09-30 |
|
||||
| D5 | 投递记录默认留 7 天且不含正文;防重标记另留 24 小时 | 已确认 2026-09-30 |
|
||||
| D6 | 离线保留默认 24 小时,最长 30 天;端默认延迟 0;定时最远 365 天 | 已确认 2026-09-30 |
|
||||
| D7 | 允许给自己发消息 | 已确认 2026-09-30 |
|
||||
| D8 | 接收端可声明最大接收字节,超限的投递直接拒绝 | 已确认 2026-09-30 |
|
||||
| D9 | 停用或删除端时,尚未送到的消息作废 | 已确认 2026-09-30 |
|
||||
| D10 | 群主被删除时,群主转给最早加入的成员 | 已确认 2026-09-30 |
|
||||
| D11 | 正文用 UTF-8 或 Base64,自定义字段最多 4 KiB | 已确认 2026-09-30 |
|
||||
| D12 | 一个管理员账号;后台不能代发、代撤回 | 已确认 2026-09-30 |
|
||||
| D13 | 被踢下线的 SDK 停止自动重连 | 已确认 2026-09-30 |
|
||||
| D14 | 自助注册默认关闭。注册安全码 8–64 字符,明文存库、可在后台查看(要分发给接入方;负责人确认不考虑数据库泄露的风险),不写日志 | 已确认 2026-09-30 |
|
||||
| D15 | 注册时编号可以自选也可以留空生成;登录密码留空则服务器生成并只返回一次;注册不需要审核 | 已确认 2026-09-30 |
|
||||
| D16 | 不做忘记密码自助找回和端自己注销,都由管理员处理 | 已确认 2026-09-30 |
|
||||
| D17 | 端编号和群编号只允许小写字母、数字、`_`、`.`、`-`;消息号区分大小写 | 已确认 2026-09-30 |
|
||||
| D18 | 登录密码失败按「编号 + 来源 IP」锁定(5 分钟 10 次),另按编号计总数暂停密码登录(1 小时 50 次);会话令牌重连不受锁定影响;注册安全码按来源 IP 锁定 | 按 2026-09-30 反馈修改,待确认 |
|
||||
| D19 | 不保留的消息推给在线端后,确认超时(5 分钟)仍未确认就按已丢弃结束,不再重推;保留的消息在保留期内继续重推 | 已确认 2026-09-30 |
|
||||
| D20 | 撤回不单独发回执,结果看撤回请求的返回 | 已确认 2026-09-30 |
|
||||
| D21 | 停用或删除端时,它发出、还没推送的消息一并作废 | 已确认 2026-09-30 |
|
||||
| D22 | 撤回不收回已经形成的回复授权 | 已确认 2026-09-30 |
|
||||
| D23 | 服务器重启时,所有未完成投递至少再等一个宽限,包括保留期在停机期间已过的 | 已确认 2026-09-30 |
|
||||
| D24 | 对话密码另按被猜的端限总数:1 小时错 50 次后暂停新的验证 1 小时,已有授权不受影响 | 已确认 2026-09-30 |
|
||||
| D25 | 每个端未完成的发出消息最多 10000 条,排队待收的投递最多 10000 条;都可配置,设为 0 表示不设上限 | 已确认 2026-09-30 |
|
||||
| D26 | 开放自助注册后,目录仍对所有端可见,谁都能列出全部端 | 已确认 2026-09-30 |
|
||||
| D27 | 管理 API 令牌不过期,停用或删除后立即失效;权限等同管理员,但不能改管理员密码、不能管理令牌;令牌只在创建时显示一次 | 待确认 |
|
||||
| D28 | 每次用密码登录都换新的会话令牌,旧令牌立即作废,旧设备自动退出 | 已确认 2026-09-30(负责人提出) |
|
||||
| D29 | 用令牌重连不换令牌;令牌 30 天没用自动失效(可配置,0 表示不失效);登录密码不能以 `nst_` 开头;端可以主动退出登录、作废令牌 | 待确认 |
|
||||
|
||||
## 10. 验收总表
|
||||
|
||||
开发完成时逐条给出结果:通过、失败或未测。未测要写原因。
|
||||
|
||||
| 编号 | 一句话 |
|
||||
|---|---|
|
||||
| F01 | 批量开通整批校验、停用、删除群主转让、删除后同编号重开不串数据 |
|
||||
| F02 | 新设备登录后旧设备自动退出(在线被踢、离线的令牌失效)、换 IP 用令牌重连、两种密码锁定、重置密码后被踢、服务器故障不误报密码错误 |
|
||||
| F03 | 断开后状态及时变离线,全表可列出 |
|
||||
| F04 | 只通知订阅了的端 |
|
||||
| F05 | 崩溃不丢已提交消息,消息号去重和冲突,密码门生效,配额生效 |
|
||||
| F06 | 群成员收到同一份,入群前不补,发送者不收到自己的 |
|
||||
| F07 | 256 KiB 通过,超出拒绝,接收上限生效 |
|
||||
| F08 | 弱网最终送达且应用层不重复,重启后续传 |
|
||||
| F09 | 保留时间从发送时刻起算,超时过期 |
|
||||
| F10 | 短断线送到,长断线丢弃,服务器重启后宽限内重连送到 |
|
||||
| F11 | 发送方离线后到点仍发送 |
|
||||
| F12 | 延迟窗口内撤回对方收不到 |
|
||||
| F13 | 未推送必撤成功;群部分确认得到部分撤回 |
|
||||
| F14 | 回执能补送给当时离线的发送方 |
|
||||
| F15 | 输一次记住、改密失效、回复免密、进群仍要密码、防多账号轮流猜 |
|
||||
| F16 | 群主权限、退出后不再收到、解散后同编号新群不收旧消息 |
|
||||
| F17 | 后台管端、管注册、管群、查记录,响应里没有正文;API 令牌可用且不能越权 |
|
||||
| F18 | 送达后正文消失;记录天数 0 时连记录消失;防重仍在 |
|
||||
| F19 | 四种 SDK 通过同一清单 |
|
||||
| F20 | 裸 MQTT 能登录、收、确认、发 |
|
||||
| F21 | 默认一个端口提供后台、WebSocket、TCP、注册;后台可分到单独端口 |
|
||||
| F22 | 初始化后单文件或 Docker 启动、备份恢复、升级迁移、证书自动重载、指标可抓取 |
|
||||
| F23 | 注册开关、安全码校验、换码不影响已注册、输错锁定 |
|
||||
|
||||
## 11. 修订记录
|
||||
|
||||
| 版本 | 日期 | 说明 |
|
||||
|---|---|---|
|
||||
| 0.1 | 2026-09-30 | 初稿 |
|
||||
| 0.2 | 2026-09-30 | 端口改为「端只用一个固定端口,后台可用单独端口」(F21)。新增端自助注册(F23),从「本期不做」中移除。按审查补充和修正:编号只允许小写(F01、F16);批量开通整批校验(F01);停用或删除端时作废它发出的消息,删除后编号可复用(F01);登录锁定按编号加 IP,并区分服务器故障(F02);消息号按请求内容判冲突,防重标记与记录并存(F05、F18);请求频率上限写入需求(F05);接收上限按整条数据计算(F07);不保留消息的确认超时(F08、F09);服务器重启后的宽限和补发(F10、F11);撤回结果的判定和不发回执(F13、F14);解散群时作废定时消息(F16);后台批量停用、删除和注册设置(F17);首次启动先初始化(F22);单位统一为 KiB;重试先认防重再校验(F05);每个端未完成消息和排队投递的上限(F05);对话密码另按被猜的端限总数(F15);后台端列表显示在线状态(F17);注册安全码和明文传输的提醒(F23);手机 App 在后台收不到提醒的说明(5.2);新增默认 D14–D25 |
|
||||
| 0.3 | 2026-09-30 | 负责人确认第 9 节 D1–D26(D27 待确认):开放注册后目录仍对所有端可见(D26),配额可设为 0 表示不设上限(D25)。新增管理 API 令牌和管理操作日志(F17)。F22 增加 Docker 镜像和 Prometheus 监控指标。F21 写明证书文件自动重载、生产环境用 1Panel 申请和续签。技术栈写入 DEVELOPMENT.md 第 2 节:Go + 标准库 net/http、SQLite + 手写 SQL、不用 Redis、Vue 3 + TypeScript + Naive UI 打包嵌入程序 |
|
||||
| 0.4 | 2026-09-30 | 登录改为会话令牌(F02):首次用密码登录后发令牌,重连用令牌、和 IP 无关;每次用密码登录都换新令牌,旧设备自动退出(D28);令牌闲置 30 天失效,可以主动退出登录(D29)。密码锁定改为按编号加 IP、按编号总数两种,只拦密码登录,不拦令牌重连(D18);后台可以解除锁定(F01、F17);登录密码不能以 `nst_` 开头。新增 docs/TASKS.md 开发任务拆分 |
|
||||
Reference in New Issue
Block a user