ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

好用的skill 1.安装 npx skills add https://github.com/mattpocock/skills --skill grill-me 2.五子棋为例子AGENTS.md

2026/8/16 21:38:23 拓冰建站 浏览量
好用的skill 1.安装 npx skills add https://github.com/mattpocock/skills --skill grill-me 2.五子棋为例子AGENTS.md 1.grill-me安装方式只询问然后写PLAN的一个skill比superpower轻量级很多npx skillslatest add mattpocock/skills2.AGENTS.md# 五子棋平台实施计划 状态等待审核 本文件仅定义实施方案审核通过前不创建工程骨架、不编写业务代码。 参考基线E:\03_github\antares\doc\architecture-design.md 当前仓库状态wzz_client、wzz_proto、wzz_server、wzz_excel 均为空目录需要从零初始化。 ## 1. 已确认的产品规则 ### 1.1 账号与会话 - 使用“用户名 密码”注册和登录不设置独立昵称界面直接展示用户名。 - 用户名按去除首尾空格并转小写后的值做唯一性判断保留原始大小写用于展示。 - 密码只保存 Argon2id 哈希禁止保存或记录明文。 - 同一账号只允许一个有效在线会话新会话登录成功后旧连接收到顶号通知并关闭。 - 登录成功后签发可撤销的随机会话令牌浏览器断线时用令牌自动恢复会话无需重复传输密码。 - 一个玩家同一时间只能处于一个房间或一个匹配队列中。 ### 1.2 棋局规则 - 棋盘为 15 × 15。 - 黑方先手。 - 横、竖、两个斜线方向连续五颗或以上即获胜。 - 不实现禁手规则。 - 棋盘填满且无人获胜时为平局。 - 在线状态下每步不限时。 - 支持主动认输对局中主动离开等同认输。 - 首局随机分配黑白“再来一局”时双方交换黑白。 ### 1.3 断线规则 - 连接断开不立即判负PlayerActor 保留玩家与进行中房间的绑定。 - 仅一方离线时进入 5 分钟重连宽限期超时后离线方判负。 - 双方同时离线时暂停单方判负计时进入 30 分钟保留期到期后棋局作废且不计分。 - 双方离线期间若只有一方恢复为仍离线的一方重新开始 5 分钟宽限期。 - 新会话顶掉旧会话属于原子换绑不触发断线判负计时。 - RoomActor 必须持久化离线时间与截止时间进程重启或分片迁移后恢复计时器。 ### 1.4 积分与匹配 - 初始积分为 1000。 - 只有自动匹配创建的排位房计算积分。 - 手动创建的房间属于友谊赛不加减积分避免通过指定对手对刷。 - 排位赛胜方加 5 分负方扣 3 分平局双方不变。 - 积分最低为 0当剩余不足 3 分时失败后直接归零。 - 0 分玩家不能进入排位匹配但仍可创建或加入友谊房、观战和聊天。 - 认输和单方断线超时按正常失败结算双方断线超时作废且不结算。 - 匹配按入队时间优先寻找积分最接近的对手初始分差不超过 100每等待 10 秒扩大 100最终不限制分差。 - 匹配成功后自动建房并直接开局不再增加准备确认步骤。 ### 1.5 手动房、观战和聊天 - 首版只提供公开房不实现密码房和私密邀请。 - 支持创建、分页查看房间列表、加入座位、准备、取消准备、离开、认输、再来一局。 - 手动房双方都准备后开始首局。 - 创建者为初始房主等待状态下房主离开时转移给另一名在座玩家无玩家时关闭房间。 - 支持中途加入观战并立即收到完整房间与棋盘快照。 - 每个房间最多 2 名对局玩家和 100 名观众。 - 房间聊天对玩家和观众开放只保留最近 100 条不提供跨日历史。 - 已结束房间在 10 分钟内无人发起再来一局时关闭该时长由 Luban 游戏配置控制。 ## 2. 技术基线 | 领域 | 选型 | |---|---| | JVM | JDK 21 | | 语言 | Kotlin 2.3实施时锁定具体 2.3.x 补丁版本 | | 应用框架 | Asteria 0.6.9 | | Actor 集群 | Apache Pekko 1.2.1、Cluster Sharding、Cluster Singleton、Management/Bootstrap | | 注册与配置中心 | Nacos 3.1 | | 持久化 | MongoDB 7.0 Replica Set、majority write concern | | 客户端协议 | proto3二进制 WebSocket服务端使用 Google Protobuf 4Vue 端使用 protobuf.js | | 客户端 | Vue 3、JavaScript、Vite、Pinia、Vue Router、protobuf.js | | 游戏配置 | Luban客户端 javascript-json服务端 java-json数据均为 JSON | | 构建 | Gradle 9 Kotlin DSL、KSP前端使用 pnpm 并提交锁文件 | | 本地部署 | Docker Compose多 JVM 进程独立运行 | | 测试 | Kotlin Test/JUnit 5、Testcontainers、Vitest、Playwright | Nacos 3.1 用于 - 非敏感运行时配置与动态监听 - JVM 节点注册和发现 - Pekko Cluster Bootstrap 接触点发现 - Gate 对外服务实例注册。 MongoDB 密码、Nacos 凭据和会话签名材料等 Secret 只通过环境变量或挂载文件注入不以明文发布到 Nacos。 业务 ID 使用 UUIDv7。项目不引入 Asteria 的 ZooKeeper Worker ID 模块也不在 Nacos 上模拟 ZooKeeper 顺序节点。 配置职责必须分开 - Nacos 保存端口、节点角色、Mongo 连接参数、集群发现和日志级别等运行时配置。 - Luban 保存棋盘、积分、匹配窗口、断线宽限、房间容量等前后端共享的游戏规则和数值。 - 服务端永远是游戏配置的权威执行方客户端生成的同源配置只用于界面展示和交互提示。 ## 3. 总体架构 客户端请求链路 Vue Client │ WSS Protobuf ▼ Gate / ChannelActor ├── PlayerActor 分片账号会话、积分快照、当前房间 ├── LobbyDirectoryActor 单例公开房目录 ├── MatchmakerActor 单例排位队列与配对 └── RoomActor 分片棋盘、座位、观众、聊天、对局状态 │ ▼ SettlementActor │ ▼ MongoDB 事务 基础设施关系 所有 JVM 进程 ──注册/发现/配置监听── Nacos 3.1 Player/Room/Global ──权威数据与恢复── MongoDB Replica Set 浏览器 ──二进制 WebSocket── Gate 运维探针 ──HTTP── 各进程健康端口 ### 3.1 独立进程与扩容边界 | 进程角色 | 核心职责 | 扩容方式 | |---|---|---| | Gate | WebSocket、ChannelActor、鉴权前状态机、协议解码、限流和路由 | 无状态水平扩容 | | Player | PlayerActor Cluster Sharding、会话换绑、玩家状态 | 按分片水平扩容 | | Room | RoomActor Cluster Sharding、棋局与房间权威状态 | 按分片水平扩容 | | Global | LobbyDirectoryActor、MatchmakerActor Cluster Singleton、SettlementActor 分片 | 至少两个实例单例自动故障转移 | 本地 Docker Compose 至少启动 1 个 Gate、1 个 Player、1 个 Room、2 个 Global以及 Nacos 3.1 和 MongoDB Replica Set。每个角色是独立 JVM不使用 Antares 的同 JVM Stardust 模式作为最终运行形态。 ### 3.2 Actor 权威边界 | Actor | 实体键 | 权威状态 | |---|---|---| | ChannelActor | connectionId | 连接、鉴权阶段、请求序号、回包、订阅关系 | | PlayerActor | playerId | 当前会话代次、当前房间/匹配状态、积分版本、在线状态 | | RoomActor | roomId | 房主、座位、准备状态、棋盘、轮次、观众、最近聊天和重连截止时间 | | LobbyDirectoryActor | Cluster Singleton | 可见房间的只读索引可从 MongoDB 重建 | | MatchmakerActor | Cluster Singleton | 排位票据、等待时间、积分窗口和配对流程 | | SettlementActor | settlementId | 单局幂等结算状态、重试与完成确认 | 原则 - 所有 Pekko Actor 类型、架构图节点和文档引用统一使用 Actor 后缀进程角色、Gradle 模块、Repository 和普通 Service 不使用该后缀。 - Gate 不保存权威业务数据。 - 单玩家写入只在 PlayerActor 邮箱内串行。 - 单房间写入只在 RoomActor 邮箱内串行。 - 跨玩家积分结算使用 MongoDB 事务和唯一结算 ID不依赖“消息恰好只发送一次”。 - 所有异步数据库结果必须回到 Actor 邮箱后再改变内存状态。 - Lobby 房间目录允许最终一致但棋盘、胜负和积分不允许仅靠广播结果决定。 ## 4. Antares 复用方式与 Nacos 改造 保留 Antares 的以下模式 - Asteria 模块化节点启动 - Player/Room Cluster Sharding - ChannelActor 会话状态机 - 构建期 Protobuf 协议注册、消息 Dispatcher 和 Gate 路由 - Actor 加载、Active、Draining、Passivate 生命周期 - Mongo 内存态加载和停机排空 - Cluster Singleton 协调全局业务 - 请求 ID、超时、重试和幂等的跨 Actor 约束。 不照搬以下内容 - 不使用 ZooKeeper、Curator 和 ZooKeeper Worker ID - 不使用原生 TCP、LZ4 和自定义 AES Pipeline - 不拆独立 Rust 战斗服五子棋权威逻辑直接位于 RoomActor - 首版不实现 GM、热补丁、动态游戏时间和 Kubernetes - 不使用 Antares 当前不完整的 Battle 结算链路。 ### 4.1 Nacos 适配层 新增独立 infrastructure-nacos 模块实现并测试 1. NacosConfigStore 适配 Asteria ConfigStore 的读取、写入、监听、版本和 CAS 语义将 ConfigPath 映射为 Nacos namespace、group、dataId。层级查询需要显式索引不能依赖 Nacos 模糊搜索。 2. NacosRuntimeConfigModule 继续复用 Asteria RuntimeConfigRepository 和配置编解码只替换底层 Store。 3. NacosServiceRegistrar 注册节点地址、Pekko Management 地址、角色、版本和健康元数据并在优雅停机时注销。 4. NacosPekkoDiscovery 实现 Pekko Discovery 查询为 Cluster Bootstrap 返回健康接触点Nacos 只负责发现Pekko Cluster 本身仍负责成员关系和故障检测。 5. NacosGameClusterApplicationFactory 根据 Nacos 配置组装 ActorSystem、角色、Remoting、Management、Sharding 和 Singleton。 6. 配置初始化工具 幂等发布本地开发配置区分 dev/test/prod namespace不得覆盖版本更新后的远端配置。 Nacos 数据规划 | 类型 | 规划 | |---|---| | Namespace | wzz-dev、wzz-test、wzz-prod | | Config Group | WZZ_RUNTIME | | Bootstrap Service | wzz-cluster-bootstrap | | Gate Service | wzz-gate | | 元数据 | role、nodeId、appVersion、remotingPort、managementPort、startedAt | ### 4.2 第一阶段技术门槛 Nacos 适配和 WebSocket 传输是本项目相对 Antares 的最大改动。正式展开业务前必须先通过一个最小技术闭环 - 两个独立 JVM 通过 Nacos 发现并加入同一 Pekko Cluster - Nacos 配置可读取、监听、CAS 更新并正确处理重连 - 浏览器或测试客户端通过 WebSocket 发送一个 Protobuf EchoReq - Gate 使用生成式路由把消息发送到另一进程的分片 Actor 并收到 EchoResp - 任一节点重启后可重新注册Cluster 无重复节点和脑裂 - 工程中不存在 ZooKeeper/Curator 运行时依赖。 若 Asteria 0.6.9 的扩展接口不足优先在本仓库实现薄适配模块只有确认无法保持兼容时才提出升级或维护 Asteria fork并在编码前再次申请审核。 ## 5. Luban 配置工程 ### 5.1 参考实现与独立性 - Vue 端参考 E:\03_github\luban_examples-main\Projects\Javascript_NodeJs_json使用 javascript-json 代码目标和 json 数据目标。 - Kotlin 服务端参考 E:\03_github\luban_examples-main\Projects\java_json生成 Java 配置类并由 Kotlin 直接调用使用 java-json 代码目标和 json 数据目标。 - 参考目录只用于核对参数和加载方式运行时及生成时不得依赖 E:\03_github\luban_examples-main。 - wzz_excel 内置固定版本的 Luban 工具、模板和 Windows x64 .NET 8 本地运行时在未安装系统 dotnet 的干净 Windows 环境中也能执行。 - 记录 Luban 来源版本或提交、工具 SHA-256 和许可证升级工具必须单独评审生成差异。 ### 5.2 wzz_excel 目录 计划结构 wzz_excel/ gen.bat README.md luban.conf Datas/ __tables__.xlsx __beans__.xlsx __enums__.xlsx game/ game_config.xlsx Defines/ builtin.xml Tools/ Luban/ dotnet/ VERSION.txt scripts/ generate.ps1 verify-output.ps1 .generated-tmp/ - 所有 Excel 源文件、Luban schema 和生成入口都放在 wzz_excel 内。 - gen.bat 必须使用自身目录作为基准不依赖当前工作目录从资源管理器双击和从命令行执行结果一致。 - .generated-tmp 仅用于生成暂存并加入忽略规则不作为前后端加载目录。 - README 写明表结构、字段分组、生成目的地、工具版本和常见错误。 ### 5.3 共享游戏配置 首版至少建立一张全局游戏配置表包含 | 字段 | 初始值 | 使用方 | |---|---:|---| | boardSize | 15 | 客户端、服务端 | | winLength | 5 | 客户端、服务端 | | initialRating | 1000 | 客户端、服务端 | | winRatingDelta | 5 | 客户端、服务端 | | loseRatingDelta | 3 | 客户端、服务端 | | matchMinRating | 1 | 客户端、服务端 | | matchInitialGap | 100 | 客户端、服务端 | | matchGapStep | 100 | 客户端、服务端 | | matchExpandIntervalSeconds | 10 | 客户端、服务端 | | singleDisconnectGraceSeconds | 300 | 客户端、服务端 | | bothDisconnectAbortSeconds | 1800 | 客户端、服务端 | | finishedRoomRetentionSeconds | 600 | 服务端 | | maxSpectators | 100 | 客户端、服务端 | | roomChatHistoryLimit | 100 | 客户端、服务端 | Luban 的 client/server 分组控制字段输出范围。任何影响胜负、积分或超时的配置即使输出给客户端也必须由服务端重新校验。 ### 5.4 一键生成流程 双击 wzz_excel\gen.bat 后按以下顺序执行 1. 检查本地 Luban、.NET 8 运行时、luban.conf、Excel 源文件及两个目标工程是否存在。 2. 清理本次专用的 .generated-tmp 子目录不直接删除前后端现有生成目录。 3. 执行客户端生成targetclient、codejavascript-json、datajson。 4. 执行服务端生成targetserver、codejava-json、datajson。 5. 校验两次命令退出码、JSON 可解析性、必需表、代码文件和配置关键值。 6. 以相同 Excel 输入计算并写入 config-manifest.json包含 schemaVersion、Luban 工具版本、目标完整哈希和双方共享字段哈希不写入会破坏确定性的生成时间。 7. 客户端与服务端均验证成功后才以带备份回滚的事务式同步替换目标目录任一步失败都恢复并保留整套旧产物返回非零退出码。 8. 输出生成文件数量、目标路径和成功/失败摘要双击运行时保留窗口以便查看结果CI 可传入 --no-pause。 固定输出位置 | 产物 | 目标目录 | |---|---| | JavaScript 配置代码 | wzz_client/src/generated/config/code | | 客户端 JSON | wzz_client/src/generated/config/data | | Java 配置代码 | wzz_server/config/src/generated/java | | 服务端 JSON | wzz_server/config/src/main/resources/game-config | | 两端配置清单 | 各自 JSON 目录内的 config-manifest.json | 生成目录由 gen.bat 独占管理业务代码不得手工编辑生成物。生成物提交到版本库CI 在临时目录重新生成并检查是否存在未提交差异。 ### 5.5 前后端加载 - Vue 使用 Luban 生成的 ES module schema.js 和 JSON在应用启动阶段加载完整配置构造 Tables 后再挂载页面。 - Vue 虽使用 JavaScript 工程仍启用 jsconfig 和编辑器类型检查Luban 生成代码不手改。 - 服务端新增 config Gradle 模块把 src/generated/java 纳入 Java SourceSet把 game-config JSON 打包为资源。 - Kotlin 通过薄封装 GameTables 访问 Luban 生成的 Java Tables禁止业务层散落文件路径和 Gson 解析代码。 - 每个 JVM 角色启动时加载完整 Snapshot执行字段范围和跨字段校验失败则 readinessfalse 并拒绝加入业务服务。 - 客户端与服务端连接握手时交换 config-manifest 中按双方共享字段计算的 sharedConfigHash版本不一致时提示刷新客户端服务端仍按自身配置裁定。客户端和服务端各自完整产物哈希允许因分组字段不同而不同。 - 首版配置随构建发布不实现运行时热更新后续若需要热更另行设计 Nacos 发布、版本切换和 Actor 追赶流程。 ### 5.6 Excel 与生成验收 - Excel 表符合 Luban 模板行、类型、分组和唯一键约束字段说明完整。 - 配置工作簿需检查关键单元格类型、公式错误和可读性并至少完成一次视觉渲染确认。 - game_config 的约束至少包括boardSize 和 winLength 为正且 winLength 不大于 boardSize积分变化非负时间和容量为正。 - 连续执行两次 gen.bat 必须得到字节级一致的代码、JSON 和 manifest。 - 从其他目录调用 gen.bat、路径包含空格、目标目录不存在、Excel 非法和单侧生成失败都必须有自动化测试。 - wzz_client 可加载生成的 JavaScript JSONwzz_server 可编译生成的 Java并加载同一份配置值。 ## 6. 协议与网络设计 ### 6.1 wzz_proto 目录 计划结构 wzz_proto/ buf.yaml buf.lock proto/ wzz/client/v1/common.proto wzz/client/v1/auth.proto wzz/client/v1/player.proto wzz/client/v1/lobby.proto wzz/client/v1/match.proto wzz/client/v1/room.proto wzz/internal/v1/player_rpc.proto wzz/internal/v1/room_rpc.proto wzz/internal/v1/global_rpc.proto - client 协议供 Vue 与 Gate 使用。 - internal 协议只供 JVM Actor/RPC 使用。 - 消息 ID 分段并生成注册表禁止手写重复 ID。 - CI 执行 Protobuf lint、breaking change 检查和生成结果一致性检查。 - Vue 端协议实现固定使用 [protobuf.js](https://github.com/protobufjs/protobuf.js.git)依赖包与 CLI 版本通过 pnpm lockfile 锁定。 - Vue 构建前通过 protobuf.js 的 pbjs 生成 ES module 静态模块不在浏览器运行时动态解析 .proto 文件。 - Vue 生成物输出到 wzz_client/src/generated/protowzz_server 的 Java/Kotlin 生成物输出到 build/generated两种语言的生成物都不放入 wzz_proto。 - Protobuf uint64 字段在 Vue 端使用 Long 或十进制字符串表示禁止转换为可能丢失精度的 JavaScript number。 ### 6.2 WebSocket 数据包 - 只接受二进制帧文本帧直接拒绝。 - WebSocket 自带消息边界不重复实现 Antares 的 TCP 长度帧。 - 帧内使用 Packet Protobuf包含协议版本、protocolId、clientSeq、requestId、payload 和 flags。 - requestId 用于端到端幂等与日志关联clientSeq 用于检测重复和乱序请求。 - 首版不启用 LZ4单帧解码后最大 64 KiB房间快照也必须受该限制。 - 使用 WSS/TLS 保护传输不实现 Antares 的自定义 AES。 - 未鉴权连接只允许注册、登录、恢复会话、心跳。 - 已鉴权路由中的 playerId 一律来自服务端 Session不相信客户端提交的 playerId。 ### 6.3 客户端协议清单 - CommonHello、Heartbeat、Error、ServerNotice。 - AuthRegister、Login、ResumeSession、Logout、Kicked。 - PlayerProfile、ScoreChanged、CurrentRoom。 - LobbyEnterLobby、RoomList、RoomSummary、LobbyChanged。 - MatchStartMatch、CancelMatch、MatchStatus、Matched。 - RoomCreate、JoinSeat、JoinSpectator、Ready、Leave、Resign、PlaceStone、Snapshot、StateChanged、GameEnded、Rematch、Chat。 所有修改状态的请求都携带 requestId服务端缓存或持久化最近结果使客户端超时重发不会重复落子、重复建房或重复结算。 ## 7. MongoDB 数据与一致性 ### 7.1 集合 | 集合 | 关键字段与索引 | |---|---| | account | playerIdusernameNormalized 唯一索引passwordHashcreatedAtlastLoginAt | | session | tokenHash 唯一索引playerId 唯一索引expiresAt TTLsessionEpoch | | player_profile | playerId 唯一ratingratingVersionactiveRoomId统计数据 | | room | roomId 唯一modestatusplayersboardturnroundversiondeadlinesrecentChats | | match_ticket | ticketId 唯一playerId 唯一ratingqueuedAtstatusTTL | | game_result | settlementId 唯一roomId round 唯一结果前后积分结算状态 | ### 7.2 房间持久化 - RoomActor 激活时从 room 文档恢复完整状态。 - 棋盘最多 225 手首版在房间文档中保存紧凑棋盘和顺序 moveLog。 - 每次合法落子、开始、认输、判负和结束均以 room version 做乐观并发更新。 - 权威状态写入 majority 成功后才向客户端确认避免节点硬故障后客户端已见落子却无法恢复。 - 观众连接引用不持久化观众重连后重新订阅并获取 Snapshot。 - RoomActor handoff/passivate 前等待在途写入完成。 ### 7.3 幂等积分结算 1. RoomActor 确认终局并生成 settlementId roomId round。 2. SettlementActor 以 settlementId 查询或创建结算。 3. 在同一个 MongoDB 事务中插入 game_result并更新两名玩家的积分与 ratingVersion。 4. 唯一索引保证重复请求只产生一次结算。 5. 提交后向两个 PlayerActor 发送包含绝对 afterRating 和 ratingVersion 的通知。 6. PlayerActor 按版本应用重复或旧版本通知直接忽略。 7. RoomActor 收到结算完成后进入 Finished并向客户端广播最终积分。 8. 进程在事务提交后、Actor 通知前崩溃时由 SettlementActor 重试并补发通知。 友谊赛仍保存 game_result但 ratedfalse不更新积分。 ## 8. 核心状态机 ### 8.1 连接状态 Connected ├── Registering ├── Authenticating └── Resuming │ ▼ Authorized ├── 正常路由 ├── 新会话换绑 └── Closed - 登录成功前不创建业务订阅。 - 登录/恢复成功后 PlayerActor 增加 sessionEpoch并关闭旧 ChannelActor。 - 掉线后 PlayerActor 通知当前 RoomActor恢复后重新绑定、取消对应超时并推送最新 Snapshot。 ### 8.2 房间状态 Waiting ──双方准备/匹配建房── Playing │ ├── Finished └── Empty - Closed ├── Aborted └── Settling - Finished - Waiting管理房主、座位、准备和观众。 - PlayingRoomActor 校验座位、轮次、坐标、空位和终局。 - Settling拒绝新落子允许查询快照等待幂等积分结算。 - Finished允许观战、聊天和发起再来一局。 - Aborted双方断线超时不计分。 - Closed从房间目录移除并允许 Actor 钝化。 ### 8.3 匹配流程 1. PlayerActor 校验积分大于 0、未在房间且未排队。 2. 写入唯一 match_ticket再交给 MatchmakerActor。 3. MatchmakerActor 按等待时间和动态积分窗口选对手。 4. 分别向两个 PlayerActor 申请 reservation避免匹配与手动入房竞态。 5. 创建排位 RoomActor随机黑白并直接进入 Playing。 6. 成功后完成票据并通知双方失败则释放 reservation 并恢复有效票据。 7. MatchmakerActor 故障转移后从 MongoDB 重建等待队列。 ## 9. 客户端计划 ### 9.1 页面 - 注册/登录页。 - 大厅页当前用户名和积分、匹配按钮、公开房分页列表、创建房间。 - 匹配状态浮层等待时长、当前允许分差、取消按钮。 - 房间页15 × 15 棋盘、双方信息、准备/认输/离开/再来一局、观众数和聊天。 - 断线恢复遮罩重连进度、恢复成功后的快照同步、会话失效后返回登录。 ### 9.2 客户端状态 - authStore账号、会话令牌、顶号和退出。 - socketStore连接、心跳、指数退避重连、requestId、请求超时。 - lobbyStore房间列表、匹配状态。 - roomStore房间快照、增量事件、棋盘、聊天和观战状态。 客户端只做预测性展示不自行裁定落子合法性、胜负或积分。收到增量事件版本不连续时立即请求完整 Snapshot。 ### 9.3 棋盘交互 - 使用 Canvas 或 SVG 绘制棋盘和棋子选择后以实际性能与可访问性测试确定。 - 显示最后一步、当前行棋方、黑白身份和终局连线。 - 落子请求未确认前锁定重复点击服务端拒绝时回滚等待态。 - 观众没有落子控件。 ## 10. wzz_server 工程规划 ### 10.1 Gradle 多模块 计划采用 Gradle 多模块 wzz_server/ build-logic/ common/ protocol/ config/ infrastructure-nacos/ infrastructure-mongo/ gate/ player/ lobby/ match/ room/ global/ tools/ deploy/ docker-compose.yml Dockerfile - common领域值对象、错误码、时间、请求 ID 和运行时公共能力。 - protocol从 wzz_proto 生成 JVM Protobuf、协议注册表和内部 RPC。 - config接收 wzz_excel 生成的 Java 代码和 JSON提供 Kotlin GameTables 与启动校验。 - infrastructure-nacos配置、注册发现和 Pekko Bootstrap 适配。 - infrastructure-mongo客户端、索引、事务和 Repository。 - gate/player/room对应可执行角色和 Actor。 - lobby/match领域库由 global 进程安装。 - global安装 lobby/match 领域模块并承载 LobbyDirectoryActor、MatchmakerActor 和 SettlementActor。 - toolsNacos 配置初始化、索引初始化和协议检查。 wzz_server 通过相对路径只读引用 ../wzz_proto/proto不复制协议源文件。 ### 10.2 Gradle Wrapper 腾讯云镜像 - wzz_server 必须提交 gradlew、gradlew.bat 和 gradle/wrapper 下的 Wrapper 文件所有开发、CI 和部署构建只通过 Wrapper 启动。 - Gradle 9 在阶段 0 锁定具体补丁版本后把下方 x.x.x 替换为该版本禁止保留动态版本或回退到 services.gradle.org。 - gradle-wrapper.properties 必须使用腾讯云发行包镜像和 all.zip distributionBaseGRADLE_USER_HOME distributionPathwrapper/dists distributionUrlhttps\://mirrors.cloud.tencent.com/gradle/gradle-x.x.x-all.zip networkTimeout10000 validateDistributionUrltrue zipStoreBaseGRADLE_USER_HOME zipStorePathwrapper/dists - 锁定版本后补充 distributionSha256Sum并使用官方同版本发行包 SHA-256 校验腾讯云镜像内容。 - CI 检查 URL、all.zip、10 秒超时、URL 校验和 SHA-256Gradle Wrapper 升级后若这些属性被覆盖构建直接失败。 ## 11. 分阶段实施顺序 ### 阶段 0工程与技术验证 - 初始化四个工程、版本目录和统一格式化规则。 - 锁定 Gradle 9 具体版本并配置、校验腾讯云 Gradle Wrapper 镜像。 - 初始化 wzz_excel 独立 Luban 工程并打通 gen.bat 前后端双目标生成。 - 接通 Asteria、Pekko、KSP、Protobuf、Luban 配置加载和最小测试。 - 完成 Nacos 适配与跨进程 Echo WebSocket 闭环。 - 输出架构验证记录和已知限制。 验收第 4.2 节所有技术门槛通过后才能进入业务阶段。 ### 阶段 1协议、账号和会话 - 定义通用包、错误码、注册、登录、恢复、心跳和顶号协议。 - 实现账户索引、Argon2id、会话令牌、登录限流和 PlayerActor 换绑。 - 完成 Vue 注册登录、Socket 管理和自动重连。 验收并发注册同名账号只有一个成功后登录必定顶掉旧连接重连恢复同一 PlayerActor 状态。 ### 阶段 2手动房与基础大厅 - 实现 LobbyDirectoryActor、RoomActor、房间目录和手动房状态机。 - 实现创建、列表、入座、准备、离开和房主转移。 - 完成大厅和房间基础页面。 验收多个 Gate 下房间列表一致玩家不能同时占用两个座位空房正确关闭。 ### 阶段 3五子棋核心 - 实现纯 Kotlin、无 Actor 依赖的棋盘领域模型。 - 实现落子校验、四方向胜负、平局、认输和持久化。 - 接入 RoomActor 广播与客户端棋盘交互。 验收边界、长连、交叉连线、重复落子、越界、非当前玩家等测试全部通过节点重启后棋盘不丢步。 ### 阶段 4匹配与积分结算 - 实现 MatchmakerActor、动态分差、取消、reservation 和故障恢复。 - 实现排位房自动开局。 - 实现 SettlementActor、MongoDB 事务、幂等积分和 0 分限制。 验收同一局重复结算不会重复加减分手动房永不改变积分0 分无法匹配Global 单例切换后队列可恢复。 ### 阶段 5断线、观战、聊天和再来一局 - 实现单方/双方断线计时与恢复。 - 实现观众快照、订阅恢复、人数上限。 - 实现最近 100 条房间聊天和消息长度/频率限制。 - 实现 Finished 保留期和双方再来一局换边。 验收Room 节点在宽限期中重启仍按原截止语义处理顶号不误判断线第 101 条聊天淘汰最旧消息。 ### 阶段 6部署、可观测性和完整验收 - 完成独立角色镜像、Docker Compose、启动顺序和健康探针。 - 增加结构化日志、角色/消息/耗时标签、Prometheus 指标。 - 增加优雅停机Gate 拒绝新连接Player/Room 排空并 flush。 - 完成端到端、故障注入、协议兼容和基础压测。 - 编写开发启动、配置、部署、数据恢复和故障排查文档。 验收全新环境可用一条文档化命令启动完整用户旅程通过进程滚动重启不造成重复结算或已确认棋步丢失。 ## 12. 测试矩阵 ### 12.1 单元测试 - 四方向五连及五连以上、边界、平局和非法落子。 - 房间所有状态迁移和权限校验。 - 匹配窗口扩展、排队公平性和取消竞态。 - 积分归零、平局、排位/友谊模式隔离。 - 用户名规范化、密码校验和协议错误码。 ### 12.2 适配与持久化测试 - Nacos ConfigStore 的读写、监听、CAS、断线重连和 namespace 隔离。 - Luban client/server 分组、双目标生成、配置校验、清单哈希和失败不覆盖旧产物。 - Pekko Discovery 的节点上下线、重复注册和缓存过期。 - Mongo 索引、事务回滚、幂等结算和 Replica Set 主节点切换。 - Room 乐观版本冲突和 Actor 重载。 ### 12.3 多进程集成测试 - Gate 到 Player、Global、Room 的生成式路由。 - 两个 Gate 下的顶号、断线和恢复。 - Player/Room 分片迁移与 handoff。 - MatchmakerActor Cluster Singleton 故障转移和队列重建。 - 结算提交后通知前强杀进程恢复后仍只结算一次。 ### 12.4 浏览器端到端测试 - 注册、登录、进入大厅、创建/加入/准备、完整下完一局。 - 自动匹配、获胜积分 5、失败 -3、平局不变。 - 观战中途加入、聊天、再来一局换边。 - WebSocket 断开、恢复棋局、会话过期和顶号。 ### 12.5 安全与容量 - 非法 protocolId、超大帧、畸形 Protobuf、未鉴权路由和重放 requestId。 - 注册/登录/聊天/落子的连接级和账号级限流。 - 日志不出现密码、令牌和完整凭据。 - 压测 Gate 长连接、RoomActor 活跃数、观战广播和匹配队列。 ## 13. 可观测性 必须至少提供 - WebSocket 当前连接数、鉴权连接数、重连数和顶号数 - 协议请求成功/失败/耗时标签限制为固定角色和消息类型 - 活跃 PlayerActor、RoomActor、排队人数和匹配等待时间 - 对局开始/结束/作废、断线判负和结算重试 - Mongo 事务耗时/失败、Nacos 连接状态、Pekko Cluster 成员和分片迁移 - requestId、playerId、roomId、settlementId 的结构化日志关联。 健康接口只提供基础探针 - alive进程存活。 - ready已加入 Pekko ClusterNacos 注册完成必需依赖可用角色模块启动完成。 ## 14. 明确不在首版范围内 - 人机 AI、机器人补位 - 五子棋禁手、不同棋盘尺寸和每步计时 - 密码房、好友邀请、好友系统 - 大厅公共聊天、私聊、排行榜 - 邮箱/手机验证码、找回密码、第三方登录 - GM 管理后台、热补丁和脚本系统 - 独立战斗服务器 - Kubernetes 生产清单和多地域容灾。 这些能力必须在首版验收后另立计划不在实现过程中顺手扩展。 ## 15. 最终交付验收 最终必须同时满足 1. wzz_client、wzz_proto、wzz_server 和 wzz_excel 可独立运行或构建并共享同一份协议与同源游戏配置。 2. JDK 21、Kotlin 2.3、Asteria、Pekko、Nacos 3.1 和 MongoDB 版本全部锁定且可复现Gradle Wrapper 只能从指定腾讯云镜像下载并通过 SHA-256 校验。 3. Gate、Player、Room、Global 为独立 JVM 进程并能通过 Nacos 组成集群。 4. 注册、登录、顶号、断线恢复和退出完整可用。 5. 大厅、匹配、手动房、准备、五子棋、积分、观战、聊天和再来一局完整可用。 6. 排位积分与友谊赛严格隔离结算幂等且通过 MongoDB 事务闭环。 7. 已确认落子在 Room 节点故障和分片迁移后可恢复。 8. 所有关键状态机、事务、集群故障和浏览器主流程有自动化测试。 9. Docker Compose 能启动完整多进程开发环境并有清晰的运行与排障文档。 10. wzz_excel 双击 gen.bat 可在不依赖外部示例仓库和系统 dotnet 的情况下把 JavaScript/Java 代码及 JSON 原子生成到前后端。 11. 不包含 ZooKeeper/Curator 运行时依赖不存在明文密码或令牌日志。 ## 16. 审核后执行约束 - 只有本 PLAN.md 获得明确批准后才开始编码。 - 编码按阶段提交每一阶段先通过其验收条件再进入下一阶段。 - 若阶段 0 发现 Asteria 0.6.9 无法以兼容方式接入 Nacos 3.1 或 WebSocket暂停业务开发提交证据和替代方案重新审核。 - 实施中若需要改变已确认的积分、断线、匹配或房间规则先更新本计划并再次获得批准。