spawn 手机版本计划(mobile-app)
状态:已拍板,实施中(2026-10-02 定稿,M0 首批开工)。 实施进度批注于各里程碑行内;变更记录追加在「拍板记录」表。
关联:总体目录规划见根
README.md(apps/mobile-app占位); 后端能力与部署形态见docs/development-guide.zh.md。
0. 现状盘点(2026-10-02)
| 项 | 现状 |
|---|---|
| 移动端规划 | 仅根 README.md 目录树一行占位:apps/mobile-app # iOS/Android 客户端(含小黑盒式数据面板),无独立计划 |
| 移动端代码 | 无(apps/ 下只有 web-client) |
| 可复用后端 | 六个 Go 服务全部 REST + JWT:user-service(注册/登录/推荐)、game-catalog(游戏库/榜单/推荐)、content-service(攻略/评论)、community(帖子/话题/关注/点赞)、api-gateway(聚合 + 反代)、user-service-rpc(内网 gRPC,手机不直连) |
| 前端技术栈 | web-client 为 React 19 + TypeScript + Vite;无 React Native / Flutter 任何依赖 |
| 未落地后端 | README 规划中的 matchmaking / realtime-hub(开黑/实时)尚未实现;data-panel(战绩)已于 2026-10-09 落地第一里程碑(服务 + 网关反代 + web 面板最小面),mobile 面板可直接消费网关 /api/v1/stats/* |
| 接入方式现状 | web-client 直连四服务(apps/web-client/src/api/client.ts 硬编码 localhost:88xx);api-gateway(8800) 端点面窄(login / games/featured / recommendations + community/content 反代)——已过时:BFF 一/二阶段(2026-10-04)后网关已扩 users/games 反代、/home/feed 聚合与分享卡,见第 3 节「网络」行 |
1. 目标平台
| 平台 | 优先级 | 说明 |
|---|---|---|
| Android | P0(首发) | 国内游戏社区主战场;模拟器 + 真机双通道调试,上架国内应用市场 |
| iOS | P1(紧随) | 同代码库出包,差异仅在推送证书与上架流程;无 Apple 开发者账号前以 TestFlight/侧载验证 |
| 鸿蒙(HarmonyOS NEXT) | 暂不 | RN 生态对纯血鸿蒙支持未稳;待社区方案成熟后评估,不进首期排期 |
2. 功能面切分
2.1 上手机(按后端就绪度排序)
| 功能块 | 后端依赖 | 里程碑 |
|---|---|---|
| 注册 / 登录 / JWT 安全存储(SecureStore) | user-service 已就绪 | M1 |
| 游戏库浏览 / 搜索 / 详情 | game-catalog 已就绪 | M1 |
| 榜单(特色/推荐) | game-catalog 已就绪 | M1 |
| 攻略阅读 + 评论(浏览/发表) | content-service 已就绪 | M2 |
| 社区帖子流 / 话题圈子 / 发帖 / 点赞 / 分享计数 | community 已就绪 | M2 |
| 关注关系(话题/用户)+ 关注流 | community 已就绪 | M3 |
| 个人中心(资料/我的帖子/我的点赞) | user-service + community 已就绪 | M3 |
| 本地推送(新帖/热榜提醒,Expo Notifications) | 无后端依赖 | M3 |
| 深链与分享卡片(app links / universal links) | 网关侧路由 | M3 |
2.2 首期不上手机(及原因)
| 功能 | 原因 |
|---|---|
| 小黑盒式战绩数据面板 | data-panel 已于 2026-10-09 落地第一里程碑(后端 + web 面板),mobile 面板作为 M4 增量接网关 /api/v1/stats/* |
| 开黑房 / 语音 / 实时匹配 | realtime-hub 已落地(2026-10-11,含语音信令透传);matchmaking 未落地 |
| 运营后台类功能 | admin-console 域,移动端不做 |
| 支付 / 会员体系 | 后端无此域 |
| 小程序壳 | 独立 apps/mini-program,另行规划 |
2.3 移动端独有交互约定
- 列表一律下拉刷新 + 触底分页(对应各服务 List 接口的 limit/offset);
- 发帖/评论文本框多行自适应,图片选择走系统相册(首期单图,多图随 content-service 图片能力);
- JWT 过期静默跳登录页(与 web-client 401 语义一致)。
3. 技术选型(与主仓技术栈的关系)
| 决策点 | 选型 | 理由 |
|---|---|---|
| 框架 | React Native(Expo 托管工作流) | ① 与 web-client 同为 React + TypeScript:类型、工具函数、团队心智直接复用,README 规划的 packages/shared-utils / packages/data-models(TS 类型契约)天然双端共享;② 后端全为 REST + JWT,无自定义原生协议需求,RN 完全覆盖;③ Expo 托管原生构建(EAS),双平台出包不需要本地维护 Android/iOS 双套原生工程 |
| 备选否决 | Flutter | 技术面优秀但引入 Dart 第二语言体系,与本仓 React 前端零复用,单人/小队规模下双栈维护成本不成比例(如拍板偏好 Flutter,功能面与里程碑不变,仅替换本节) |
| 语言 | TypeScript(strict) | 与 web-client 一致 |
| 状态/数据 | 轻量自行开发 fetch 封装 + React Query(TanStack Query) | 后端接口规整(统一 code/message 信封),无需重客户端;React Query 覆盖缓存/重试/分页 |
| 网络 | 经 api-gateway 统一入口(BFF 第一阶段,2026-10-04 切换):EXPO_PUBLIC_API_URL 覆盖网关域名,开发默认 host:8800(Android 模拟器 10.0.2.2)。网关侧自有聚合 handler(精选/推荐/分享卡/首页聚合)+ 反代(community/content/users/games;2026-10-11 起登录注册也走 users 反代)覆盖 App 全量调用面;曾为手机版先行扩网关会拉长关键路径的顾虑随 BFF 第一阶段落地解除 | |
| 认证 | JWT Bearer + expo-secure-store | 与六服务现有中间件零改动对接 |
| 目录 | apps/mobile-app(README 已占位),pnpm workspace 接入 | 与 monorepo 规划一致 |
| 类型契约 | packages/data-models:先手写 TS 类型 + 一个 make types 校验脚本对照 .api 文件;后端 goctl 无 TS 生成器,不为此引代码生成链 | 避免为类型同步先建一套生成基建 |
4. 里程碑排期
节奏按「1 名全职前端 + 后端按需支持」估算;每期含联调与真机验证, 验收标准写入各期。日历以拍板日为 T0 顺延。
| 期 | 内容 | 验收标准 | 周期 |
|---|---|---|---|
| M0 工程骨架 | Expo 脚手架落 apps/mobile-app、pnpm workspace 接入、TS strict、ESLint 对齐 web-client、导航框架(底部 Tab:游戏/社区/我的)、CI 接入现有 gofmt/build 门禁旁路(lint + tsc) | Android 模拟器跑通空壳 App,三 Tab 可切换,CI 绿 | 1 周 |
| M1 浏览 + 账号 | 登录/注册(含 JWT SecureStore 与 401 跳转)、游戏库列表/搜索/详情、榜单页 | 真机登录 → 浏览 → 搜索 → 详情全链路;token 重启存活 | 2 周 |
| M2 内容 + 社区 | 攻略阅读 + 评论、帖子流/话题/发帖/点赞;下拉刷新 + 触底分页 | 真机完成「看攻略→评论」「看帖→点赞→发帖」全流程 | 2–3 周 |
| M3 关系 + 收尾 | 关注/关注流、个人中心、本地推送、深链分享卡;Android 出 release 包(EAS 或本地 gradle) | Android 可安装包走完全部已上功能;iOS TestFlight 侧载验证 | 2 周 |
| M4(增量,另立项) | data-panel 落地后的战绩面板;api-gateway BFF 化后统一切网关 | — | 进行中:BFF 第一阶段提前于 M4 完成(2026-10-04):网关补 users/games 反代(POST /auth/register、GET /users/:id、GET /games、GET /games/:id,与既有 community/content 反代及自有 handler 共存,集成测试按生产装配全量注册暴露路由冲突),mobile-app base URL 收敛到网关单地址(EXPO_PUBLIC_API_URL 覆盖);走查登记并修复跨切缺陷:反代直转 r.Body 时长度未知走 chunked,go-zero 上游解析 chunked 请求体失败(user-service 直连 chunked curl 亦复现 field is not set)——proxy 改为缓冲定长转发(1 MiB 上限,超限 413,附契约测试);五服务 curl 全链路走查通过(注册/登录/资料、游戏列表/详情/精选、攻略/评论、话题/帖子/点赞/分享、关注流/我的点赞、匿名 401 透传、分享卡),App 全量调用面仅经 :8800;web-client 直连拓扑与网关既有路由不变。第二阶段同日落地:网关 GET /home/feed 列表聚合端点(精选游戏/热帖/话题/攻略四路并发拉取,逐组字段裁剪——正文/图片等大字段不下发、正文仅截断 60 字摘要;单上游故障降级为空组并记 degraded,不做整体 5xx),App 侧消费点同日落地:新增 Tab「发现」((tabs)/discover.tsx)一次请求渲染精选游戏/热帖/话题/攻略四区块,下拉刷新、degraded 降级提示条、空态/错误重试,expo export 产物走查文案与路由均在包内;web-client 不受影响。data-panel 面板仍属 M4 另立。M4 第一里程碑落地(2026-10-09 拍板:data-panel 立项开工;matchmaking/realtime-hub/admin-console/小程序维持不开工,真机回归维持无设备不派):新建 services/data-panel(端口 8896/metrics 9097)——SQLite/MySQL 双驱动 player_stats 表(UNIQUE(user_id, game_id)),战绩摄入为单调增量累加(JWT 保护 POST /api/v1/stats/records,单语句 upsert col=col+delta,负 delta 400,game_title 非空才覆盖,last_played_at 取最大推进,归属恒取令牌 user_id),查询公开(GET /api/v1/stats/users/:id/summary、.../games?limit&offset、.../games/:game_id,win_rate/kd 读侧 4 位小数),空表内嵌种子,TTL+LRU 缓存;api-gateway 增 /api/v1/stats 五路反代(集成测试补 data-panel stub 与全量装配);web-client 增 /stats 战绩页(KPI 卡 + 按游戏明细表,仅经网关单地址);compose/nightly/Prometheus 同步接线(七服务)。web 最小面已上线。mobile 消费点同日落地(M4 增量):client.ts 增战绩 fetcher(fetchStatsSummary / fetchUserGameStats / fetchUserGameStat,经网关单地址),新增底部 Tab「战绩」(KPI 汇总卡 + 按游戏明细卡,未登录给登录入口,下拉刷新/错误重试/空态)与 Stack 动态路由 stats/[gameId](单游戏战绩详情:对战/战斗分区 + 段位分徽标);环境无模拟器,以 tsc + eslint + expo export --platform android 产物走查替代(bundle 内战绩 Tab/详情路由与 KPI/明细/登录引导文案均在包内),真机回归并入下一有设备批次 |
风险与依赖:
- 后端 CORS / 明文 HTTP:手机真机默认禁 http 明文(Android
usesCleartextTraffic),开发期走局域网 IP + 放行配置,生产必须 HTTPS——上架前需备公网域名 + 证书(当前 compose 无 TLS 终结,属部署域新增项); - iOS 开发者账号:无账号则 iOS 仅模拟器/侧载验证,不影响 Android 首发节奏;
- 图片上传:已解除——gateway
POST /upload本地盘存储已于 2026-10-10 落地(6642132),web/mobile 均已接线;生产如需外发 CDN 属新拍板项。
5. 拍板记录
| 日期 | 决议 | 批注 |
|---|---|---|
| 2026-10-02 | 按推荐定稿:Android P0 / iOS P1;功能面按第 2 节切分;React Native(Expo)+ TypeScript;里程碑 M0–M3 共约 7–8 周 | 用户授权免审直接拍板;M0 同日开工。Flutter 备选否决理由维持有效 |
| 2026-10-05 | iOS 与鸿蒙定位改为低优先级填空:只写代码;iOS 验证走 GitHub macOS runner(不占本地不卡进度),鸿蒙无工具链只写码编译过即可;有空闲就做、没空继续其他任务,绝不卡主进度,也不当主线 | 用户修正令,覆盖 10-02「iOS P1 紧随」节奏;M3 的 iOS TestFlight 侧载验证随本口径转为填空项 |
| 2026-10-07 | (按 10-05 填空口径自主执行,非拍板)iOS 补 ios.bundleIdentifier = com.tappi.spawn 与 Android 对齐:此前 iOS 侧无 bundle id,prebuild 每次靠 Expo 推导默认值,身份不稳定波及 spawn:// 深链注册与将来侧载/推送证书;iOS workflow(497d4cd)build 验证 | 主队列清零后的填空项;鸿蒙维持 plan 第 2 节「暂不」(RN 纯血鸿蒙生态未稳)不动 |
| 2026-10-09 | (按 10-05 填空口径自主执行,非拍板)iOS 权限与上架键补齐(6f30ad2):app.json 接入 expo-image-picker 插件并声明相册用途文案(photosPermission——发帖选图走 launchImageLibraryAsync,iOS 无 NSPhotoLibraryUsageDescription 运行时即崩且审核必拒;仅声明实际用到的相册读权限,不凑相机/麦克风),ios.infoPlist 补 ITSAppUsesNonExemptEncryption=false(应用仅标准 HTTPS,省 TestFlight 逐版加密问答)。走查口径:本地 expo config --type prebuild 展开 + expo prebuild -p ios --no-install 静态核 Info.plist(相册文案/加密键/CFBundleURLSchemes=[spawn, com.tappi.spawn] 均在);macOS runner(ios.yml 手动点火)prebuild + pod install + 模拟器免签名编译全绿(15m42s)。顺延账:真机安装与权限弹窗实测、Universal Links(需 Apple 团队 + 域名 AASA 部署,无凭据不写码)、APNs 远程推送凭证(本地通知双平台代码已就位,见 M3 第四切片)、真机回归统一并入下一有设备批次 | 主队列 M4 增量清零后的填空项;iOS 侧可写的实质配置至此已无存量——剩余项全部依赖外部凭据/设备,维持填空口径待条件 |