feat: phase 2 - polls, memories, notifications, stats v0.1.0
- Group polls with option/rollcall modes, edit by creator, auto-settle - Multimedia memories with upload, preview, inline video playback - In-app notifications for poll/team/group events - Points system and group stats dashboard - Group detail tabs with icons (activity/polls/memories/stats) - Fix: nginx file upload size, static cache blocking API, timezone, auto-cancel Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -9,71 +9,80 @@ Game Group V2 — 游戏组队管理平台。用户创建/加入群组,组队
|
||||
## 开发命令
|
||||
|
||||
```bash
|
||||
# 前端开发(默认连接 localhost:8090 的 PocketBase)
|
||||
cd frontend && npm run dev
|
||||
|
||||
# 前端开发环境(连接远程后端 192.168.1.14:8711,端口 7033)
|
||||
cd frontend && npm run dev:dev
|
||||
|
||||
# 前端 UAT 环境(端口 7034)
|
||||
cd frontend && npm run dev:uat
|
||||
|
||||
# 构建前端
|
||||
cd frontend && npm run build
|
||||
|
||||
# 启动后端(PocketBase,端口 8711)
|
||||
cd backend && docker-compose up -d
|
||||
# 本地开发(一般不用,用 Docker 部署代替)
|
||||
cd frontend && npm run dev
|
||||
|
||||
# 部署脚本(根目录)
|
||||
./deploy-backend.sh # 部署后端
|
||||
./deploy-dev.sh # 部署 Dev 前端
|
||||
./deploy-uat.sh # 部署 UAT 前端
|
||||
./deploy-backend.sh # 部署 PocketBase 后端
|
||||
./deploy-dev.sh # 构建 + 部署 Dev 前端 (端口 7033)
|
||||
./deploy-uat.sh # 构建 + 部署 UAT 前端 + 后端 (端口 7034/8712)
|
||||
./stop-all.sh # 停止所有服务
|
||||
```
|
||||
|
||||
**重要**: 不要在本地启动 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 包),cookie 认证
|
||||
- **API 通信**: PocketBase JS SDK (`pocketbase` npm 包),localStorage 持久化认证
|
||||
- **实时通信**: PocketBase realtime subscriptions
|
||||
- **样式**: 自定义 CSS 变量 (`--gg-*` 前缀, `design.css`) + Tailwind + Element Plus,绿色主题
|
||||
|
||||
## 环境与端口
|
||||
|
||||
| 服务 | Dev | UAT |
|
||||
|------|-----|-----|
|
||||
| 前端 (nginx) | 7033 | 7034 |
|
||||
| PocketBase | 8090 | 8712 |
|
||||
|
||||
Docker Compose 文件:`docker-compose.backend.yml`、`docker-compose.dev.yml`、`docker-compose.uat.yml`,共享 `gamegroup-net` 网络。
|
||||
|
||||
## 架构
|
||||
|
||||
### 前端目录结构 (`frontend/src/`)
|
||||
### 前端核心流程
|
||||
|
||||
- **`api/`** — 每个领域一个文件(`users.ts`, `groups.ts`, `sessions.ts`, `invitations.ts`, `games.ts`),封装 PocketBase CRUD 和过滤逻辑。`pocketbase.ts` 初始化客户端并导出认证工具函数
|
||||
- **`stores/`** — Pinia stores(`user`, `group`, `team`, `notification`),组合式 API 风格(`defineStore('name', () => {...})`)
|
||||
```
|
||||
pocketbase.ts (PB 客户端初始化)
|
||||
→ router guards (isAuthenticated 检查)
|
||||
→ stores (user/group/team/notification)
|
||||
→ api/ (PocketBase CRUD 封装)
|
||||
→ components + views
|
||||
```
|
||||
|
||||
- **`api/pocketbase.ts`** — 单例 PocketBase 客户端,导出 `pb`、`getCurrentUser()`、`isAuthenticated()`、`logout()`
|
||||
- **`api/`** — 每个领域一个文件(`users.ts`, `groups.ts`, `sessions.ts`, `invitations.ts`, `games.ts`),封装 CRUD 和过滤逻辑
|
||||
- **`stores/`** — Pinia stores,组合式 API 风格(`defineStore('name', () => {...})`)
|
||||
- **`composables/useRealtime.ts`** — 统一管理 PocketBase 实时订阅,组件卸载时自动清理
|
||||
- **`views/`** — 页面级组件,路由懒加载
|
||||
- **`components/`** — 按领域分子目录:`common/`, `game/`, `group/`, `layout/`, `team/`
|
||||
- **`types/index.ts`** — 所有 TypeScript 接口和类型定义集中在一个文件
|
||||
- **`types/index.ts`** — 所有接口集中定义 + `displayName()` 工具函数
|
||||
|
||||
### 认证流程
|
||||
|
||||
- 注册:用户输入中文昵称存 `name` 字段,`username` 自动生成 ASCII 标识(`'u' + Date.now().toString(36) + random`)
|
||||
- 登录:支持昵称/邮箱/username 登录。输入不含 `@` 时查询 `users` collection 的 `name`/`username` 字段,获取 `username` 后调用 `authWithPassword(username, password)`
|
||||
- 路由守卫:`requiresAuth` 跳转登录页,`requiresGuest` 跳转首页
|
||||
|
||||
### Vite 代理 vs Nginx
|
||||
|
||||
开发环境 Vite 将 `/api` 代理到 PocketBase(去掉 `/api` 前缀)。生产环境 nginx 做同样代理,SSE realtime 连接额外禁用 buffering。
|
||||
|
||||
### 数据模型(PocketBase Collections)
|
||||
|
||||
- **users** — 用户,含状态(idle/working/in_team/away)、工作时间设定、积分
|
||||
- **groups** — 群组,owner + members 关系,支持审核加入(requireApproval)
|
||||
- **team_sessions** — 临时组队,关联 sourceGroup,状态流转:recruiting → playing → finished/dissolved
|
||||
- **invitations** — 组队邀请,from/to 用户,pending/accepted/rejected
|
||||
- **users** — 认证集合。`username` 是系统字段(不可改,仅 `[a-z0-9_-]`),中文昵称存 `name` 字段。状态:idle/working/in_team/away
|
||||
- **groups** — owner + members 关系,支持审核加入(requireApproval)
|
||||
- **team_sessions** — 临时组队,状态流转:recruiting → playing → finished/dissolved
|
||||
- **invitations** — 组队邀请,pending/accepted/rejected
|
||||
- **games** — 游戏库,归属 group,含平台、标签、封面
|
||||
- **game_comments** / **game_favorites** — 游戏评论和收藏
|
||||
- **join_requests** — 入群申请,pending/approved/rejected
|
||||
- **game_comments** / **game_favorites** — 评论和收藏
|
||||
- **join_requests** — 入群申请
|
||||
|
||||
### 关键模式
|
||||
### PocketBase 注意事项
|
||||
|
||||
- **Vite 代理**: 开发时 `/api` 代理到 PocketBase,路径重写去掉 `/api` 前缀(`vite.config.ts`)
|
||||
- **认证流程**: `pocketbase.ts` → cookie 持久化 → 路由守卫检查 `isAuthenticated()` → 未登录跳转 `/login`
|
||||
- **实时订阅**: 通过 `useRealtime` composable 和 `subscribe*` 函数订阅 PocketBase 变更事件,各 store 自行刷新数据
|
||||
- **样式系统**: 自定义 CSS 变量(`design.css`,`--gg-*` 前缀)+ Tailwind + Element Plus,主题色为绿色系
|
||||
|
||||
### 后端
|
||||
|
||||
- PocketBase 数据迁移在 `backend/pb_migrations/`,由管理面板操作自动生成
|
||||
- `backend/pb_hooks/main.js` 为占位文件,当前镜像不支持 JS VM
|
||||
- 所有业务逻辑(如入群审批、组队邀请)在前端 API 层实现
|
||||
|
||||
## 环境配置
|
||||
|
||||
前端通过 `.env` 文件配置:
|
||||
- `VITE_PB_URL` — PocketBase 地址(默认 `window.location.origin`)
|
||||
- `VITE_PORT` — 开发服务器端口
|
||||
- `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` 配置开发端口
|
||||
|
||||
Reference in New Issue
Block a user