# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## 项目概述 Game Group V2 — 游戏组队管理平台。用户创建/加入群组,组队开黑,管理游戏库、投票、积分竞猜、账本和资产。 ## 开发命令 ```bash # 构建前端 # 注意:npm run build 默认加载 .env.dev 的变量。Docker 构建时通过 ARG 注入空 VITE_PB_URL,由 nginx 代理处理 # 如需本地测试 UAT 构建设置,使用:cd frontend && npm run build -- --mode uat cd frontend && npm run build # 本地 vite dev server(一般不用,用 Docker 部署代替) cd frontend && npm run dev # 部署脚本(根目录) ./deploy-dev.sh # 构建 + 部署 Dev 全套 (PB + LiveKit + 前端, 端口 7033/8090) ./deploy-uat.sh # 构建 + 部署 UAT 全套 (PB + LiveKit + 前端, 端口 7034/8712) ./stop-all.sh # 停止所有服务 # Electron 桌面端 cd electron && npm install cd electron && npm run start # 启动桌面端(默认连接 Dev) cd electron && npm run start:dev # 同上,显式指定 dev 环境 cd electron && npm run start:uat # 连接 UAT 环境 cd electron && npm run build # 打包 Windows 可执行文件 # 查看日志 docker logs -f gamegroup-pb # Dev PocketBase docker logs -f gamegroup-pb-uat # UAT PocketBase docker logs -f gamegroup-livekit-dev # Dev LiveKit docker logs -f gamegroup-livekit-uat # UAT LiveKit docker logs -f gamegroup-voice-token-dev # Dev Voice Token docker logs -f gamegroup-voice-token-uat # UAT Voice Token docker logs -f gamegroup-frontend-dev # Dev 前端 docker logs -f gamegroup-frontend-uat # UAT 前端 ``` **重要**: 不要在本地启动 vite dev server,使用 Docker 部署后通过端口访问测试。Dev 环境在 `http://192.168.1.14:7033`。部署到 UAT 前必须等用户确认。 ## 技术栈 - **后端**: PocketBase 0.22.4 (Docker, `ghcr.io/muchobien/pocketbase`) — 无自定义 JS hooks,业务逻辑全在前端 - **前端**: Vue 3 + TypeScript + Pinia + Element Plus + Tailwind CSS + Vite - **API 通信**: PocketBase JS SDK (`pocketbase` npm 包),localStorage 持久化认证 - **实时通信**: PocketBase realtime subscriptions - **样式**: 自定义 CSS 变量 (`--gg-*` 前缀, `design.css`) + Tailwind + Element Plus,绿色主题 - **语音通话**: LiveKit server v1.10 + `livekit-client` + 独立 Express token 服务 - **桌面端**: Electron 35 + `electron-store` + `electron-builder` ## 环境与端口 | 服务 | Dev | UAT | |------|-----|-----| | 前端 (nginx) | 7033 | 7034 | | PocketBase | 8090 | 8712 | | LiveKit | 7880/7881/7882(udp) | 7890/7891/7892(udp) | | Voice Token | 7883 | 7893 | Docker Compose 文件:`docker-compose.dev.yml`(Dev 全套)、`docker-compose.uat.yml`(UAT 全套),共享 `gamegroup-net` 网络。每个环境独立运行完整的 PB + LiveKit + Voice Token + 前端服务。 前端 `.env` 文件:`frontend/.env.dev`(VITE_PB_URL=8711, PORT=7033)和 `frontend/.env.uat`(VITE_PB_URL=8711, PORT=7034)。注意 Dev/UAT 构建时 VITE_PB_URL 都指向 8711,因为 Docker 构建时会将其覆盖为空,由 nginx 反向代理处理。 ## 架构 ### 前端核心流程 ``` pocketbase.ts (PB 客户端初始化) → router guards (isAuthenticated 检查) → stores (user/group/team/notification/poll/ledger/asset/memory) → api/ (PocketBase CRUD 封装,每个领域一个文件) → components + views ``` - **`api/pocketbase.ts`** — 单例 PocketBase 客户端,导出 `pb`、`getCurrentUser()`、`isAuthenticated()`、`logout()` - **`api/`** — 每个领域一个文件(`users.ts`, `groups.ts`, `sessions.ts`, `invitations.ts`, `games.ts`, `polls.ts`, `bets.ts`, `points.ts`, `ledgers.ts`, `assets.ts`, `memories.ts`, `notifications.ts`, `gameBlacklist.ts`, `playerBlacklist.ts`, `voice.ts`, `bulletins.ts`) - **`stores/`** — Pinia stores,组合式 API 风格(`defineStore('name', () => {...})`) - **`composables/useRealtime.ts`** — 统一管理 PocketBase 实时订阅,组件卸载时自动清理 - **`composables/useVoiceRoom.ts`** — LiveKit 语音房间封装,处理连接/断开/麦克风/扬声器控制 - **`types/index.ts`** — 所有接口集中定义 + `displayName()` 工具函数 + 状态映射常量(如 `UserStatusMap`、`TeamStatusMap`) ### 认证流程 - 注册:用户输入中文昵称存 `name` 字段,`username` 自动生成 ASCII 标识(`'u' + Date.now().toString(36) + random`) - 登录:支持昵称/邮箱/username 登录。输入不含 `@` 时查询 `users` collection 的 `name`/`username` 字段,获取 `username` 后调用 `authWithPassword(username, password)` - 路由守卫:`requiresAuth` 跳转登录页,`requiresGuest` 跳转首页 ### 路由结构 Layout (`/`) 下所有认证页面为子路由:Home, GroupView (`/group/:id`), LedgerView (`/group/:groupId/ledger`), AssetView (`/group/:groupId/assets`), BlacklistView (`/group/:groupId/blacklist`), VoiceRoom (`/group/:groupId/voice/:sessionId`), GamesLibrary, Profile, Settings, Changelog。Login/Register 为独立路由。 ### Vite 代理 vs Nginx 开发环境 Vite 将 `/api` 代理到 PocketBase(去掉 `/api` 前缀)。生产环境 nginx 做同样代理,SSE realtime 连接额外禁用 buffering。Voice Token 服务通过 `/voice-api/` 路径由 nginx 代理到 voice-token 端口(Dev: 7883, UAT: 7893)。 前端 nginx 配置有两份:`nginx.conf`(dev,代理到 8090)和 `nginx.uat.conf`(代理到 8712),Docker 构建时通过 `NGINX_CONF` build arg 选择。静态资源缓存一年,HTML 不缓存。 ### 语音通话架构 组队会话 (`team_sessions`) 支持语音房间。语音流程: 1. 用户点击语音按钮 → 路由跳转到 `VoiceRoom.vue` 2. `useVoiceRoom.connect(sessionId)` 调用 `api/voice.ts` 的 `fetchVoiceToken` 3. `fetchVoiceToken` 向后端 `/voice-api/voice-token/:sessionId` 请求 token 4. Voice Token 服务验证用户 PB token → 查询 `team_sessions` 确认成员身份 → 签发 LiveKit JWT 5. 前端用 token 连接 LiveKit server(Dev: `ws://192.168.1.14:7880`, UAT: `ws://192.168.1.14:7890`) HTTP 环境下 `navigator.mediaDevices` 受限,已在 `useVoiceRoom.ts` 中给出明确的 Chrome flags 引导错误提示。 ### Electron 桌面端 - `electron/main.js` — 主进程,加载远程 URL(dev/uat 可切换),窗口大小 1280x800 - `electron/preload.js` — 预加载脚本(当前为空壳,保留扩展点) - `electron/package.json` — 独立包,依赖 `electron-store`(用于本地配置持久化) - 构建产物为 Windows portable 可执行文件 ### 实时订阅管理 所有 PocketBase 实时订阅统一通过 `useRealtime.ts` composable 管理。组件使用时在 `onMounted` 中调用订阅方法,`onUnmounted` 时自动调用 `unsubscribeAll` 清理。不要直接在组件中创建孤立的 `pb.collection().subscribe()` 而不做清理。 ### 数据模型(PocketBase Collections) - **users** — 认证集合。`username` 是系统字段(不可改,仅 `[a-z0-9_-]`),中文昵称存 `name` 字段。状态:idle/working/in_team/away - **groups** — owner + members 关系,支持审核加入(requireApproval) - **team_sessions** — 临时组队,状态流转:recruiting → playing → finished/dissolved。含 `voiceRoom` 和 `voiceActive` 字段 - **invitations** — 组队邀请,pending/accepted/rejected - **games** — 游戏库,归属 group,含平台、标签、封面 - **game_comments** / **game_favorites** — 评论和收藏 - **join_requests** — 入群申请 - **polls** / **poll_options** / **poll_votes** — 投票(选项投票/点名),含匿名、截止时间 - **bets** / **bet_options** / **bet_entries** — 积分竞猜,含下注范围和结算 - **point_logs** — 积分流水(vote/team/memory/bet 行为) - **memories** — 多媒体记忆(图片/视频/音频/文档),归属 group。nginx 配置 `client_max_body_size 500m` 支持大文件上传 - **ledgers** — 群组账本(收入/支出),按游戏/聚餐/设备/交通分类 - **assets** — 群组资产(游戏账号/主机/设备/配件),含当前持有者 - **game_blacklist** — 游戏黑名单(行为/外挂/坑货/环境差) - **player_blacklist** — 玩家黑名单(标签:挂机/送人头/喷人等) - **notifications** — 站内通知(投票/组队/入群等事件) - **bulletin_posts** / **bulletin_reads** — 群组信息公示板,支持置顶/优先级/已读追踪/过期时间 ### PocketBase 注意事项 - `users` collection 的 `listRule`/`viewRule` 设为空字符串(公开),以支持登录页查询用户 - Auth collection 的 `email` 字段不对未认证请求暴露,登录查找用 `username` 替代 - 数据迁移在 `backend/pb_migrations/`,由管理面板操作自动生成。**不要**为 `username` 等系统字段创建 `addField` 迁移,会导致 `duplicate column` 错误 - PocketBase 管理面板:`admin@example.com` / `admin123456` - 前端 `.env` 文件:`VITE_PB_URL` 配置后端地址,`VITE_PORT` 配置开发端口 - API 调用添加 `$autoCancel: false` 避免 PocketBase SDK 自动取消请求