外观
Nexo — 2026-09-13 迭代需求文档
范围:承接 2026-08-30 迭代,将用户主数据与认证体系合并收敛为单一应用(
nexo-account,统一账号与认证中心)。遵循奥卡姆剃刀与真原子化设计原则,彻底剔除“拆而不分”的分布式单体硬伤、跨库分布式事务与 Outbox 队列、全量数据推送、假权限与管理员判定等过度设计,专注落地统一账号与认证中心、轻量管理员开户(24h 设密链接 / 内部随机初始密码)、管理员用户管理控制台(Web UI)、IM 按需拉取与停用轻量通知断连、三态生命周期(待激活/正常/停用,单表单一事实源)与极简重新启用模型。 验收标准见第 10 节,本文档定义"做什么"与"为什么";"怎么做"以同目录技术方案(design.md)为准。
1. 背景与目标
在既往迭代中:
- 2026-08-16 单聊跑通:IM 地基建立,但用户账号直接耦合在
nexo-im-api内部; - 2026-08-23 认证中心与桌面壳:成功将令牌签发与会话管理剥离为
nexo-auth,但各业务系统(IM、桌面壳)仍缺乏统一人员档案与维护入口; - 2026-08-30 多端能力补齐:完成端侧密码加密与多端会话同步,但 IM 内部仍保留了历史旧注册接口与 5 分钟全量轮询。
Nexo 的形态是统一数字工作台,除 IM 外,后续还将挂载任务平台、发布平台等独立应用。各子系统绝不能各自维护一套用户表,更不能反向依赖 IM 检索人员。
在此前探索中,曾设想将系统物理拆分为独立的 nexo-user(用户主数据)与 nexo-auth(凭据认证)两个微服务。但在单机 Docker Compose 且缺乏分布式事务基础设施(2PC/Saga/Outbox)的现实下,强行拆分暴露出致命的**“伪原子化”硬伤**:
- 服务拆而不分:建号、激活、停用在两个服务间强耦合,任何一方网络抖动都会导致系统处于半入库脏数据状态;
- 数据事实源分裂:账号状态
status在两张表双写,缺乏跨库事务,必然导致状态脑裂; - 操作缺乏 ACID 保证:多步跨网络调用无法原子回滚;
- 胶水代码冗余:为两个服务编写大量内部 RPC 与双向 HMAC 校验代码,严重增加维护负担。
因此,本迭代核心目标是:遵循第一性原理彻底收敛,将用户主数据与认证体系合并为单一服务 nexo-account,实现单库单事务真原子化,落地轻量开户与管理控制台,完成 IM 登录注册剥离与按需拉取闭环。
本期确立 10 项真原子化架构原则:
- 单服务单库真原子收敛:统一为
nexo-account(端口3001),维护单数据库nexo_account,消灭所有跨服务分布式事务与双写胶水代码; - 状态单一事实源:
status(PENDING/ACTIVE/DISABLED)全局仅在users表维护一份,彻底消除脑裂分叉; - 全生命周期单事务原子化:建号、激活、停用、超时处理 100% 在本地单数据库事务内完成;
- 取消跨服务全量推送:IM 不再接收全量资料推送,仅在产生数据关联(如开启会话、查看成员、检索人员)时按需拉取并短时缓存;
- 账号停用仅推送状态通知:停用时仅向下游 IM 发送
{ userId, status: 'DISABLED', disabledAt },0 个人资料传输,IM 收到后毫秒掐断长连接; - 权限平台未上线前不进行鉴权:不写假管理员白名单(无
ADMIN_USERNAMES,无requireAdmin),只要携带合法 Bearer JWT 即可调用管理接口; - 物理分表实现 Zero-Knowledge:
users(档案)与credentials(密码哈希)物理分表,系统内部随机生成初始密码,员工打开 24h 链接自主改密; - 建号即创建用户,超时未激活单条 SQL 停用:开户落库
PENDING状态,24 小时未激活单条原子 SQL 自动转为DISABLED; - 彻底清除 HR 词汇:彻底去除“岗位”、“工号”、“职位”、“在职”、“离职”、“复职”,状态仅保留
PENDING(待激活)、ACTIVE(正常)、DISABLED(停用); - 移除无外部通道支撑的死字段:彻底移除
email(无 SMTP)与phone(无 SMS),仅保留核心档案。
2. 承接与已知欠账(承接 2026-08-30 验收)
| 欠账项 | 处理 | 排期 | Owner |
|---|---|---|---|
IM 依然残留旧有的本地 /register 与旧密码校验端点 | 本期交付(彻底注销路由,历史代码四项归零) | 2026-09-13 | 待认领 |
IM 内部 user_profiles 采用 5 分钟轮询与 24h 定时刷新 | 本期交付(移除轮询器,改造为产生关联时按需拉取 + 5分钟短时缓存) | 2026-09-13 | 待认领 |
| 账号停用后在线长连接无法毫秒级掐断 | 本期交付(停用轻量状态通知 + WebSocket 4001 毫秒强制断连) | 2026-09-13 | 待认领 |
| 密码零接触安全规范(Zero-Knowledge 原则) | 本期交付(物理分表隔离密码;内部随机初始密码 + 24h 激活链接由员工自主设密) | 2026-09-13 | 待认领 |
3. 功能需求
3.1 单应用架构与真原子数据模型
FR-1 统一账号与认证中心 nexo-account(单应用单库架构)
- 将人员主数据与认证逻辑统一收敛在
nexo-account单一服务中(端口3001); - 采用 Node.js (Hono) + PostgreSQL 16 架构,统一维护
nexo_account单一数据库; - 库内维护
users(用户档案)、credentials(凭据分表)与account_tickets(单次激活/重置凭据表); - 彻底消灭微服务间分布式事务、出件箱(Outbox)表及异步轮询补偿 Worker。
FR-2 极简单一用户模型(单一事实源,7 核心字段)
- 单表收敛:
users表维护全局唯一的员工档案与生命周期状态:id(UUID,主键)username(登录名,唯一且不可变)real_name(真实姓名,必填)nickname(昵称,选填)avatar_url(头像地址,选填)status(状态:PENDING/ACTIVE/DISABLED,全局唯一状态事实源)created_at、updated_at(时间戳)
- 字段极简红线:严禁引入
email、phone、version、工号、职位、岗位等冗余字段; - 状态三态收敛:
PENDING(待激活):建号后的初始状态,等待员工设置新密码;ACTIVE(正常):已完成设密激活,可正常登录与通讯;DISABLED(停用):账号被禁用,长连接被掐断,禁止登录与 API 访问。
FR-3 密码物理分表安全隔离(Zero-Knowledge 原则)
- 单独维护
credentials表存储密码哈希(user_id PK FK, password_hash, updated_at); - 业务查询用户档案(如姓名、昵称、头像)绝不涉及密码表,从物理表层面隔离敏感凭据;
credentials表不设冗余status字段,避免双写与脑裂。
FR-4 账号停用与重新启用
- 管理员在控制台停用账号时,系统在本地单事务内将
users.status = 'DISABLED',同时吊销其全部活跃 Session; - 事务提交后,向 IM 发送轻量通知
{ userId, status: 'DISABLED', disabledAt }(disabledAt为认证中心时钟的停用时刻,ISO 8601 UTC),IM 毫秒强掐客户端长连接; - 重新启用时,管理员在控制台点击【重新启用】,单事务将
users.status重置为ACTIVE; - 全流程无“在职/离职/复职”等 HR 术语,统一使用“待激活”、“正常”、“停用”。
3.2 轻量开户体系
FR-5 原生原子开户建号与 24h 激活设密(Zero-Knowledge 原则)
- 管理员主动录入:
- 管理员在 Web 控制台录入新成员基础信息:用户名(
username)、真实姓名(real_name),昵称(nickname)选填; - 免外部审批流,以控制台录入为主凭据;
- 管理员在 Web 控制台录入新成员基础信息:用户名(
- 原生单事务写入:
- 系统内部通过 CSPRNG 随机生成 32 位初始密码并计算 scrypt 哈希;
- 系统生成 32 字节高熵随机激活码并计算 SHA-256 哈希(24h 有效期);
- 在单个本地 PostgreSQL 事务内同时写入:
users(状态为PENDING)credentials(存入随机初始密码哈希)account_tickets(存入 24h 激活凭据)
- 任意一步失败全量原子回滚,杜绝半入库脏数据;
- 控制台返回专属激活链接(
https://<auth-domain>/activate?code=xxx),支持一键复制私发员工; - 管理员全程不生成、不查看、不输入任何明文密码;
- 员工自主激活与改密:
- 员工打开激活链接,系统核验 Ticket 有效后渲染改密页面(展示其用户名);
- 员工输入新密码并提交,系统在单个本地事务内:
- 单次核销 Ticket(记录
used_at防止重放); - 更新
credentials.password_hash为新密码哈希; - 更新
users.status = 'ACTIVE'。
- 单次核销 Ticket(记录
- 设密成功后直接引导至登录页;
- 超时自动停用:
- 若自建号起超过 24 小时员工未完成激活,单条 SQL 自动转为
DISABLED; - 控制台提供【重新生成激活链接】操作,点击后单事务重置状态为
PENDING并生成新链接。
- 若自建号起超过 24 小时员工未完成激活,单条 SQL 自动转为
3.3 管理控制台 Web UI
FR-6 用户管理控制台界面与用户列表
- 管理控制台提供「用户管理」中心界面:
- 人员数据表格:展示列包含:【姓名】、【用户名】、【昵称】、【状态】、【创建时间】、【操作】;
- 统一用户列表视图:直观展示企业全体成员(待激活、正常、停用);
- 提供关键字模糊搜索(支持姓名、用户名、昵称检索),提供状态下拉筛选(待激活、正常、停用);
- 操作列动作:资料编辑、重新生成激活链接(或重置密码链接)、停用账号、重新启用。
FR-7 批量导入与 Dry-Run 预检
- 支持标准 CSV 模板下载与批量导入;模板仅需两列:
username、real_name(nickname选填); - 两阶段导入(Dry-Run):
- 预检校验:文件上传后先进行格式合规性检查(必填项、用户名唯一性、文件内重复校验),返回校验报告,对错误行红字高亮;
- 确认入库:校验通过后一键提交,采用单数据库事务完成全量写入,整批生成初始凭据与激活链接;
- 一键导出:批量创建成功后,支持一键下载导出包含全员激活链接的 CSV 文件供分发;
- 出现未捕获异常整批全量回滚,不产生半入库脏数据。
FR-8 停用账号与防误触安全弹窗
- 在人员操作列点击「停用账号」时,弹出高风险确认模态框;
- 防误触安全设计:
- 高危警示区:红字提示「停用后将即刻掐断该用户所有客户端长连接,并在全网吊销其 Token 与登录凭证」;
- 强制全名二次核验:必须在输入框中完整、准确输入该用户的真实姓名全称,确认按钮方可点亮;
- 确认提交后,单事务更新状态为
DISABLED并吊销 Session,向 IM 触发停用通知。
FR-9 凭据重置与激活链接管理
- 管理员在操作列可对指定员工发起凭证重置:
- 若账号处于
PENDING(待激活),提供【重新生成激活链接】功能,作废旧链接并生成新 24h 链接; - 若账号处于
ACTIVE(正常),提供【发起密码重置】功能,生成 60 分钟短效设密链接;
- 若账号处于
- 链接支持一键快速复制至剪贴板,便于管理员私发交付。
3.4 下游业务联动与鉴权放行
FR-10 IM 按需拉取与停用切断
nexo-im-api彻底废弃旧有 5 分钟全量轮询与 24 小时刷新机制;- 按需拉取与短时缓存:
- 当发生数据关联时(如开启会话、查看群成员、通讯录检索),IM 服务在内存中维护轻量 LRU 缓存(TTL 5分钟);
- 若本地缓存未命中,调用
nexo-account的内部查询接口GET /internal/users?ids=...(HMAC 认证)批量获取基础公开资料并写入缓存;
- 停用状态轻量通知:
- 账号停用时,
nexo-account仅向 IM 发送轻量通知:POST /internal/users/{userId}/disabled,Payload 为{ userId, status: 'DISABLED', disabledAt }(disabledAt必填,为认证中心时钟的停用时刻,ISO 8601 UTC,供 IM 做只前进不后退的幂等判定),不传输姓名、头像等冗余资料; - IM 收到通知后立即清理本地缓存,并在 150ms 内执行
closeUser(userId, 4001, '账号已停用')强掐该用户全部在线 WebSocket 连接,客户端收到 4001 码后退回登录页并禁用重连。
- 账号停用时,
FR-11 管理端点免鉴权放行(合法 JWT 放行)
- 在外部独立权限平台(#58)上线之前,严禁引入任何硬编码管理员名单或伪鉴权逻辑(无
ADMIN_USERNAMES,无requireAdmin); - 管理 REST 接口只要校验请求头携带合法有效 Bearer JWT 即可放行;
- 鉴权与数据范围判定未来 100% 由外部独立权限平台接管,保持系统架构纯洁。
4. 历史债务清理与缺陷修复
| # | 涉及系统 | 现状与缺陷 | 正确行为 |
|---|---|---|---|
| DEBT-1 | nexo-im-api | 仍保留本地 /register 与带密码的旧登录路由 | 彻底删除本地注册路由与控制器,移除旧密码表字段 |
| DEBT-2 | nexo-im-api | 通讯录依赖 5 分钟全量轮询与 24 小时定时刷新 | 移除定时轮询器,改为发生数据关联时按需拉取并本地短时缓存 |
| BUG-1 | nexo-im-api | 账号停用后未被及时踢掉 WebSocket,仍能收发消息 | 收到停用通知后 150ms 内强制关闭全端连接(closeUser(4001)) |
| BUG-2 | nexo-account | 跨服务拆分导致开户与改密缺乏原子性,存在半状态 | 收敛为单库单服务,本地 ACID 事务保障天然原子 |
| BUG-3 | nexo-account | 既有账号体系缺乏账号停用状态支持 | 扩充 status 字段,三态化表达账号全生命周期 |
5. 核心技术方案对齐
以下五项在技术方案(design.md)中已完成极简设计与收敛:
- 单服务单库真原子架构方案 ——
nexo-account单库本地单事务(ACID)搞定建号、激活、停用,彻底根除分布式伪原子陷阱; - 内部随机初始密码与 24h 激活链接协议 —— 单次 Ticket 核销机制,单事务原子改密与状态激活;
- IM 按需拉取与停用切断 —— 本地 5 分钟 LRU 缓存 +
POST /internal/users/{id}/disabled轻量状态通知 + 150mscloseUser(4001)强掐; - 访问令牌短效收口与 Session 吊销广播 —— Access Token 有效期缩短至 180 秒,Session 吊销广播至资源服务本地内存黑名单;
- 免伪鉴权放行原则 —— 权限平台就绪前不写假权限代码,合法 Bearer JWT 即放行。
6. 待评审收口
| # | 待定项 | 倾向 | 不定会怎样 |
|---|---|---|---|
| 1 | 是否同意收敛为单一服务 nexo-account | 倾向完全同意 | 彻底消灭伪原子化与跨库事务,实现原生 ACID 强一致 |
| 2 | 是否同意取消向 IM 全量推送,改为按需拉取 | 倾向完全同意 | 消除无意义的广播开销,仅停用时通知状态 |
| 3 | 是否同意权限平台上线前不进行鉴权 | 倾向完全同意 | 杜绝硬编码假管理员白名单,保持系统架构纯洁 |
| 4 | 24h 激活链接有效时长 | 倾向设定为 24 小时 | 超时自动停用,后台支持重新生成激活链接 |
| 5 | 批量导入单次支持的最大行数 | 倾向限制为 500 行 | 单机单事务控制在毫秒级完成 |
| 6 | 访问令牌(Access Token)有效时长 | 倾向设定为 180 秒(3 分钟) | 构筑无状态吊销兜底上限 |
| 7 | 激活链接分发方式 | 倾向控制台复制直达链接私发 | 当前无企业 SMTP 邮件中继,手工分发最务实可靠 |
7. 候补(登记,本期不做)
- 画像标签系统与规则引擎:本期不建标签表、不打标签,未来根据业务明确诉求再行规划;
- 外部开放注册审批流:外部审批平台与开放门户就绪后再行规划接入;
- 细粒度 RBAC 角色授权:等待权限平台(#58)就绪后统一接入。
8. 明确不做(Out of Scope)
- 多服务物理强行拆分与跨库分布式事务 —— 5 人团队坚决不做伪微服务,避免半状态灾难;
- 重型消息队列中间件与出件箱 —— 单机 Docker 环境坚决不上 Kafka/RocketMQ,采用单事务写入 + 轻量内部调用;
- 角色定义、组织部门树与管理员白名单 —— 属于权限平台管辖范围,当前不写假代码;
- 邮箱(SMTP)与短信(SMS)通道 —— 无通道支撑,绝不保留
email/phone摆设字段; - 移动端 Native 界面适配 —— 本期管理控制台聚焦于 PC Web 桌面分辨率。
9. 非功能需求
- 事务原子性:建号、激活、停用操作 ACID 原子性保证 100%,零半状态;
- 按需拉取响应时效:IM 批量拉取公开资料响应耗时 P99 ≤ 50ms;
- 停用阻断时效:管理员办理停用确认后,在线 WebSocket 连接强制掐断延迟 ≤ 150ms;接口级 401 阻断 ≤ 1ms;
- 批量导入吞吐:500 人批量开户 Dry-Run 校验时间 ≤ 1s,正式入库事务耗时 ≤ 1s;
- 安全性原则:
- Zero-Knowledge:密码物理分表隔离,管理员零接触明文密码,初始密码内部随机生成,员工自主设密;
- Fail-Closed:非法或伪造 Token 严格返回 401,已停用账号禁止签发 Token。
10. 验收标准
验收标准覆盖以下 8 条端到端主路径:
- 管理员单人建号与生成激活链接:录入新成员用户名与姓名,系统单事务原子写入档案、随机凭据与 24h 激活链接,复制链接私发;
- 员工自助设密激活链路:访问激活链接直达
/activate页面,输入新密码并提交,单事务原子核销 Ticket、更新密码与置状态为ACTIVE; - 超时未激活自动停用:超过 24 小时未激活的账号单条 SQL 自动转为
DISABLED;管理员可在后台点击【重新生成激活链接】单事务恢复PENDING并生成新链接; - IM 产生关联时按需拉取资料:IM 客户端开启聊天或检索用户时,按需从
nexo-account查询资料并缓存在本地,不依赖全量推送; - 防误触停用账号:在控制台办理停用,未完全输入真实姓名全称时确认按钮禁用;输入全称确认后,单事务停用并吊销 Session;
- 账号停用即时断连:办理停用确认瞬间,该用户的 IM 桌面端收到 4001 码并退回登录页,后续 API 请求被 401 拦截;
- 重新启用账号无冲突:为已停用账号点击【重新启用】,状态恢复为
ACTIVE,登录与使用即刻恢复正常; - 批量导入与导出链接:上传包含重复用户名的 CSV 表格,Dry-Run 准确在界面标红报错行;修正后成功单事务批量创建并一键导出全员激活链接 CSV。
11. 风险与降级
| 风险 | 降级预案 |
|---|---|
| 激活链接超过 24h 未使用 | 账号自动变为 DISABLED 状态,管理员可在控制台针对该用户点击「重新生成激活链接」重新复制分发 |
| 停用误触风险 | 必须输入员工真实姓名全称,后端全等校验阻断误操作 |
| 批量导入遇到未知格式导致解析异常 | 前端限制文件大小(≤ 2MB)并限定 CSV;后端单事务原子回滚,不产生半入库脏数据 |
| Token TTL 缩短带来的续期频率 | SDK 刷新阈值设为 60s,5 个用户平均每分钟仅产生 2~3 次轻量点查请求,无性能压力 |
12. 约束与说明
- 遵循
YYYY-MM-DD验收会日期命名规范(2026-09-13); - 代码修改严禁直接推送到
dev或main分支,统一在特性分支进行并通过 PR 合并; - 排期节奏:
- 09-08(周二):PRD 定稿与技术方案评审;
- 09-08 ~ 09-09(周二至周三):
nexo-account表结构扩充、单事务建号、24h 激活链接与/activate设密页、管理 REST API; - 09-09 ~ 09-10(周三至周四):停用通知与 IM
closeUser(4001)掐线、IM 废除轮询接入按需拉取、控制台 Web UI; - 09-11(周五):桌面壳
nexo-app侧边栏挂载、全链路冒烟联调(建号 → 激活 → 登录 → IM 通讯 → 停用断连); - 09-12(周六):预跑 TC 验收用例与冒烟测试,产出离线核验证据;
- 09-13(周日):召开验收会闭环交付。
13. 名词解释
| 术语 | 含义说明 |
|---|---|
统一账号与认证中心 (nexo-account) | 系统的企业人员档案、安全凭据与认证基础设施权威源 |
| 真原子化 (True Atomicity) | 核心生命周期流转(建号、激活、停用、超时)全部基于本地单数据库事务(ACID)完成,零跨网络半状态 |
| 单一事实源 (Single Source of Truth) | status 仅在 users 表维护全局唯一字段,凭据表不再冗余状态,杜绝脑裂 |
待激活 (PENDING) | 账号已创建并生成激活码,员工尚未设置新密码的初始状态;超过 24 小时未激活自动转为停用 |
正常 (ACTIVE) | 账号已成功设置密码,可正常登录系统与收发消息 |
停用 (DISABLED) | 账号处于禁用状态,长连接被强制切断,禁止登录与 API 访问 |
| 按需拉取 (On-Demand Fetch) | IM 服务仅在发生数据关联(如开启聊天、检索通讯录)时才向账号中心查询人员公开档案并短时缓存 |
closeUser | IM 连接管理器的方法,接收到停用状态通知后毫秒掐断指定用户全部在线连接并返回 4001 码 |
| Zero-Knowledge 设密 | 管理员零接触明文密码,系统内部随机生成初始密码并通过有时效单次链接由员工自主设密 |