- Each environment now runs its own PB + LiveKit + Voice Token + frontend - UAT LiveKit: 7890, Voice Token: 7893 (separate from Dev 7880/7883) - Remove docker-compose.backend.yml, merge into dev compose - Delete duplicate bulletin migration files that caused PB crash on startup - Update CLAUDE.md, nginx configs, and .env files accordingly Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
9.1 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
项目概述
Game Group V2 — 游戏组队管理平台。用户创建/加入群组,组队开黑,管理游戏库、投票、积分竞猜、账本和资产。
开发命令
# 构建前端
# 注意: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 (
pocketbasenpm 包),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 登录。输入不含
@时查询userscollection 的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) 支持语音房间。语音流程:
- 用户点击语音按钮 → 路由跳转到
VoiceRoom.vue useVoiceRoom.connect(sessionId)调用api/voice.ts的fetchVoiceTokenfetchVoiceToken向后端/voice-api/voice-token/:sessionId请求 token- Voice Token 服务验证用户 PB token → 查询
team_sessions确认成员身份 → 签发 LiveKit JWT - 前端用 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 可切换),窗口大小 1280x800electron/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 注意事项
userscollection 的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 自动取消请求