Files
huajishe-tts/docs/texas/11-implementation-plan.md
e2hang 04d0af515c feat: 登录系统落地 + 踢人修正 + 单房间约束 + 权限收口
问题8 登录系统:
- node:sqlite 账号存储(scrypt 哈希 + HMAC 签名 token),preset admin 改为 e2hang/evan1115
- /api/auth/register|login|me,me 返回 room 供重联
- 网关拦截 create/join 需登录(401),列表保持开放

踢人逻辑修正(问题2 延伸):
- kickMove 真正释放座位(folded=false, name=null)而非锁死
- war/mill 去掉永久封禁语义

管理员越权:管理员 token 可删任意房间、踢任意房间内的人

单房间约束(用户新需求):
- 同一用户同时只能在一个房间,create/join 他房返回 409
- 踢人后若房间仅剩踢人者则自动解散并释放其记录(修复 2 人局踢光对手后被困 409)
- 陈旧房间记录兜底清理

UI 清理:移除"改名"按钮与"你的名字"输入框;删除房间按钮仅房主/管理员可见

docs: 新增 12-auth-kick-single-room.md 汇总本会话全部需求/根因/修复/边界测试

Co-Authored-By: Claude (CodeBuddy) <noreply@codebuddy.ai>
2026-08-25 14:13:59 +08:00

5.1 KiB
Raw Permalink Blame History

11 - 实施计划(依次修改)

按用户要求“依次计入 docs/texas 用 md然后制定计划依次修改”。本文件为执行顺序与每步交付物。 所有改动以不破坏现有单测/类型检查为前提,每步附最小验证。

阶段 0基础设施server 房间管理 + 登录后端)

影响全局,先做。对应问题 2、问题 8 后端。

  • 2.1 房间内存在线表 + 心跳路由 (packages/server/src/rooms.ts 已实现:presence Map + POST /api/rooms/:id/heartbeat + 10min 自动关房 sweep)。
  • 2.2 删除房间路由 POST /api/rooms/:id/delete(仅房主),db.wipe + 清 presence。
  • 2.3 踢人路由 POST /api/rooms/:id/kick仅房主body {target}):清 metadata + 调游戏内 kick moveengine 层已单测验证 seated=false
  • 2.4 固化房主 engine host() 改读 G.hostIdsetup 写入 '0')。
  • 8 后端 /api/auth/register|login|mepackages/server/src/auth-db.ts + auth.tsnode:sqlite 持久化scrypt 哈希 + 随机盐HMAC-sha256 签名 token预设 admin 账号从 env/常量 seedindex.ts 网关拦截"创建/加入房间"未带 token 的请求返回 401列表/查询接口保持开放。

阶段 1通用 UI 接房间管理 + 登录前端

  • 2.5 客户端 LobbyRoomList:房主显示“删除房间”“踢人”按钮;挂载后定时 heartbeat3min房间被删 → onRoomGone 清状态 + 提示。lobby-client 已加 roomsInit/heartbeat/delete/kick
  • 8 前端 App.tsxLoginBar(登录/注册切换错误回显token 存 localStoragetts-like.token/tts-like.username);进房时把 token 注入 createMatch/joinMatchAuthorization 头;登录名作默认 playerName(可手动改昵称,改后不再被登录名覆盖);未登录时列表区提示"创建/加入房间需先登录"。lobby-client 已加 register/login/me 方法。
  • 单房间约束(用户新需求) rooms.ts 新增中间件mountApiPrefix 之前注册):拦截 create/join/leave,同一登录用户同时只能在一个房间——已在别房则 create/join 返回 409(中文提示先离开);create/join 成功登记 userRoom/roomPlayersleave/kick/delete 成功清除对应记录。/api/auth/me 现返回 room,供客户端重联时权威确认所在房间;客户端 configlocalStorage 持久化,刷新即自动重连原房间。LobbyRoomListerrMsg 把 409 文案友好展示。

阶段 2改名刷新问题 1

  • 1.1 engine 新增 renameMove(沿用 playerID 信任模型),注册 rename move。
  • 1.2 ui HoldemBoard 加 effectplayerName 变化且已入座 → onMove('rename', [playerName])
  • 验证:改名后牌桌两处同步刷新(座位名 + 结果区)。

阶段 3游戏循环问题 3、4、5

  • 3.1 engine 通用 各游戏加 kick moveseatedHoldem 加 rebuy / leaveRoom / resetRoom房主moves单测覆盖
  • 3.2 ui Holdem筹码≤0 显示“补码/退出”;房主 waiting 显示“重置房间”War/Mill 加“再来一局”rematch move
  • 4.1 engine 修 roundComplete list.length===1 分支加 acted 判定(单测回归)。
  • 4.2 engine 加固 buildPots 空层结转 orphanCarry 并入下一层,避免退错人(归属权)。
  • 4.3 单测 holdem.test.ts 扩至 40 例(含 roundComplete、buildPots、kick/rebuy/leave/reset
  • 5.1 验证测试 下注顺序单测证明preflop=UTG、postflop=SB、每次加注重置轮询结论原代码正确

阶段 4展示细节问题 6、9、10

  • 6.1 engine resolveHand 摊牌亮所有未弃玩家牌(含 all-in 双方HoldemBoard 在 G.myHand 为 null已清时回落 revealedHands[me],结算后保留自己牌可见。
  • 6.2 ui 座位展示 revealedHands含自己结算区展示赢家。
  • 9.1 ui+engine 滑块 step=5、number 归一 5 的倍数;raiseMove 拒绝非 5 倍数(全下除外,单测覆盖)。
  • 10.1 ui 座位显示 本手总下 {totalBetThisHand}

依赖与风险

  • 阶段 0 的“踢人改 G”依赖 Master dispatchboardgame.io Server() 未直接暴露 master 需确认能否经 db + 自建 Master 实例触发 move若不可行降级为“仅清 metadata + 游戏内 passive 检测 (该座位长时间无动作则自动 seated=false”。
  • 问题 5 大概率为“无需改逻辑,仅文档澄清 + 加测试证据”;若测试暴露 endTurn({next})ActivePlayers.ALL 下异常,则升级为逻辑修复。

不建议现在做(避免过度工程)

  • 账号落盘持久化(先用内存,与现有 InMemory 房间一致)。→ 已改为 SQLite 落盘node:sqlite 内置,无原生编译;房间 metadata 仍为 InMemory重启即清空账号跨重启保留
  • 自动轮回的定时器自动开(用显式“再来一局”按钮,避免无人时误开)。
  • OAuth / 第三方登录。