From 80dc45f528ca0cb1729adff49445d563b8edc99c Mon Sep 17 00:00:00 2001 From: congsh Date: Thu, 18 Jun 2026 13:53:38 +0800 Subject: [PATCH] fix(join-group): redirect unauthenticated users to login + docs update - JoinGroupPage: redirect to login when user is not authenticated - CLAUDE.md: add env details, path alias, and coding constraints Co-Authored-By: Claude Opus 4.8 (1M context) --- CLAUDE.md | 18 ++++++++++++------ frontend/src/views/JoinGroupPage.vue | 10 +++++++++- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 79797ce..96fb1e4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,7 +9,7 @@ Game Group V2 — 游戏组队管理平台。用户创建/加入群组,组队 ## 开发命令 ```bash -# 构建前端 +# 构建前端(先 vue-tsc 类型检查,再 vite build。类型错误会阻断构建) # 注意:npm run build 默认加载 .env.dev 的变量。Docker 构建时通过 ARG 注入空 VITE_PB_URL,由 nginx 代理处理 # 如需本地测试 UAT 构建设置,使用:cd frontend && npm run build -- --mode uat cd frontend && npm run build @@ -63,7 +63,7 @@ docker logs -f gamegroup-frontend-uat # UAT 前端 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 反向代理处理。 +前端 `.env` 文件:`frontend/.env.dev` 和 `frontend/.env.uat`。每个 env 包含四个变量:`VITE_PB_URL`(PocketBase 地址)、`VITE_PORT`(dev server 端口)、`VITE_LIVEKIT_URL`(LiveKit WebSocket 地址)、`VITE_VOICE_TOKEN_URL`(Voice Token 服务地址)。Docker 构建时 `VITE_PB_URL` 被覆盖为空,由 nginx 反向代理处理。 ## 架构 @@ -78,11 +78,12 @@ pocketbase.ts (PB 客户端初始化) ``` - **`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', () => {...})`) +- **`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`, `events.ts`) +- **`stores/`** — Pinia stores,组合式 API 风格(`defineStore('name', () => {...})`)。共 11 个 store(user/group/team/event/poll/ledger/asset/memory/notification/bulletin),`index.ts` 仅导出前 3 个,其余直接从文件导入 - **`composables/useRealtime.ts`** — 统一管理 PocketBase 实时订阅,组件卸载时自动清理 - **`composables/useVoiceRoom.ts`** — LiveKit 语音房间封装,处理连接/断开/麦克风/扬声器控制 - **`types/index.ts`** — 所有接口集中定义 + `displayName()` 工具函数 + 状态映射常量(如 `UserStatusMap`、`TeamStatusMap`) +- **路径别名**: `@/` 映射到 `src/`,在 `vite.config.ts` 和 `tsconfig.json` 中配置 ### 认证流程 @@ -92,7 +93,7 @@ pocketbase.ts (PB 客户端初始化) ### 路由结构 -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 为独立路由。 +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 为独立路由。JoinGroup (`/join/group/:groupId`) 和 JoinTeam (`/join/team/:sessionId`) 为无需认证的独立页面,用于外部邀请链接。 ### Vite 代理 vs Nginx @@ -148,5 +149,10 @@ HTTP 环境下 `navigator.mediaDevices` 受限,已在 `useVoiceRoom.ts` 中给 - 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 自动取消请求 + +## 编码约束 + +- **TypeScript 严格模式**: `strict: true` + `noUnusedLocals` + `noUnusedParameters`,未使用的变量/参数会导致构建失败 +- **无测试框架**: 项目当前没有测试文件和测试配置,不要尝试运行测试 +- **无 Linter 配置**: 没有 ESLint/Prettier 配置文件 diff --git a/frontend/src/views/JoinGroupPage.vue b/frontend/src/views/JoinGroupPage.vue index 854ed68..2cfdf61 100644 --- a/frontend/src/views/JoinGroupPage.vue +++ b/frontend/src/views/JoinGroupPage.vue @@ -19,7 +19,7 @@ const error = ref('') const groupId = route.params.groupId as string -onMounted(async () => { +async function loadGroup() { try { group.value = await getGroup(groupId) } catch { @@ -27,6 +27,14 @@ onMounted(async () => { } finally { loading.value = false } +} + +onMounted(async () => { + if (!isAuthenticated()) { + router.replace({ name: 'Login', query: { redirect: route.fullPath } }) + return + } + await loadGroup() }) function goToLogin() {