library-picturebook-activity/docs/project/02-architecture.md

287 lines
13 KiB
Markdown
Raw Permalink Normal View History

# 系统架构设计
## 1. 整体架构
```
┌─────────────────────────────────────────────────────────────┐
│ 用户访问层 │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────────────┐ │
│ │ 公众端(H5) │ │ 管理后台(Web) │ │ 微信内置浏览器(H5) │ │
│ │ /p/... │ │ /:tenant/... │ │ /p/... │ │
│ └──────┬──────┘ └──────┬───────┘ └─────────┬──────────┘ │
└─────────┼────────────────┼────────────────────┼─────────────┘
│ │ │
┌─────────▼────────────────▼────────────────────▼─────────────┐
│ Vue3 前端应用 │
│ ┌─────────────────┐ ┌──────────────────────────────────┐ │
│ │ 公众端模块 │ │ 管理端模块 │ │
│ │ - 活动大厅 │ │ - 机构管理端(图书馆/学校/... │ │
│ │ - 活动详情 │ │ - 评审端 │ │
│ │ - 报名/提交作品 │ │ - 平台管理端(超管) │ │
│ │ - 个人中心 │ │ - 现有功能保持不变 │ │
│ │ - 子女管理 │ │ │ │
│ └─────────────────┘ └──────────────────────────────────┘ │
└────────────────────────────┬─────────────────────────────────┘
│ HTTP API
┌────────────────────────────▼─────────────────────────────────┐
│ NestJS 后端 │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
│ │ Auth模块 │ │ 用户模块 │ │ 活动模块 │ │ 公众API模块 │ │
│ │(多种登录) │ │(子女管理) │ │(现有改造) │ │ (公众端专用) │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────────────┘ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────────────┐ │
│ │ 租户模块 │ │ 评审模块 │ │ 作品模块 │ │ 其他现有模块 │ │
│ │(类型扩展) │ │(现有) │ │(现有改造) │ │ (保持不变) │ │
│ └──────────┘ └──────────┘ └──────────┘ └────────────────┘ │
└────────────────────────────┬─────────────────────────────────┘
│ Prisma ORM
┌────────────────────────────▼─────────────────────────────────┐
│ MySQL 数据库 │
│ users / children / tenants / contests / registrations / ... │
└──────────────────────────────────────────────────────────────┘
```
---
## 2. 租户模型设计
### 2.1 租户类型
| 类型标识 | 名称 | 说明 | 举例 |
|---------|------|------|------|
| `platform` | 平台租户 | 系统运营方,全局唯一 | 乐绘世界 |
| `library` | 图书馆 | 公共图书馆机构 | 广东省立中山图书馆 |
| `kindergarten` | 幼儿园 | 幼儿教育机构 | XX幼儿园 |
| `school` | 学校 | 中小学校 | XX小学 |
| `institution` | 社会机构 | 美术培训、文化机构等 | XX美术中心 |
| `other` | 其他 | 未分类的机构 | - |
### 2.2 租户与用户的关系
```
租户(机构)
├── 拥有机构用户:管理员、工作人员、评委
│ └── 通过 tenant_id 关联
公众用户
├── 不隶属任何租户
├── 通过自主注册创建
├── 可以查看所有"公开"活动并报名
身份重叠场景(二期实现)
├── 一个手机号 = 一个账号
├── 同一账号可以同时拥有:公众用户身份 + 机构用户身份
└── 通过"身份切换"在不同工作台之间切换
```
### 2.3 活动可见范围
```
活动创建时设置 visibility 字段:
├── public — 公开(所有注册用户可见,广东省图本次使用)
├── designated — 指定机构(选择哪些租户可见,现有逻辑)
└── internal — 仅内部(仅本机构内部可见)
```
---
## 3. 用户体系设计
### 3.1 核心原则:一号多身份
**一个手机号/账号 = 一个用户**,用户可以拥有多个身份角色。
一期先实现账号密码登录,二期补充手机号和微信登录。一期阶段公众用户通过"用户名+密码"自主注册。
### 3.2 用户来源
| 来源 | 标识 | 说明 |
|------|------|------|
| 管理员创建 | `admin_created` | 现有方式,管理员在后台创建用户 |
| 自主注册 | `self_registered` | 新增,用户通过公众端注册页面自行注册 |
### 3.3 用户参与模型
```
注册用户User
├── 可以以"自己"的身份报名活动(所有用户默认能力)
├── 可以添加子女,以"子女"的身份代为报名(可选能力)
├── 我自己报名的活动participant_type = 'self'
│ └── 适用场景:有手机号的青少年自己注册参与
└── 我为子女报名的活动participant_type = 'child'
├── child_id 指向具体哪个子女
└── 适用场景:家长为年幼子女代报名
```
### 3.4 报名流程
```
用户点击"报名活动"
├── 检查是否已登录 → 未登录则跳转登录/注册页
├── 已登录 → 检查是否有关联子女
├── 无子女 → 直接以自己身份报名
│ → 填写报名补充信息 → 提交
└── 有子女 → 弹出"选择参与者"
┌─────────────────────────┐
│ 请选择参与者: │
│ ○ 我自己 │
│ ○ 子女小明8岁
│ ○ 子女小红5岁
添加新的子女 │
└─────────────────────────┘
→ 选择后填写报名信息 → 提交
```
---
## 4. 前端架构
### 4.1 路由设计
```
前端路由结构:
├── /p/ # 公众端H5 + Web 响应式)
│ ├── /p/login # 公众端登录
│ ├── /p/register # 公众端注册
│ ├── /p/activities # 活动大厅(活动列表)
│ ├── /p/activities/:id # 活动详情
│ ├── /p/activities/:id/register # 报名页面
│ ├── /p/activities/:id/submit # 提交作品
│ ├── /p/mine # 个人中心
│ ├── /p/mine/children # 子女管理
│ ├── /p/mine/registrations # 我的报名
│ └── /p/mine/works # 我的作品
├── /:tenantCode/ # 管理端(现有,保持不变)
│ ├── /:tenantCode/login # 机构登录
│ ├── /:tenantCode/contests # 活动管理
│ ├── /:tenantCode/system # 系统管理
│ └── ...
└── / # 根路径重定向
```
### 4.2 公众端布局
```
┌────────────────────────────────────────┐ Web 端
│ 顶部导航栏 │
│ [Logo 乐绘世界] [活动大厅] [个人中心] │
├────────────────────────────────────────┤
│ │
│ 页面内容区 │
│ │
└────────────────────────────────────────┘
┌──────────────┐ H5 移动端
│ 顶部标题栏 │
├──────────────┤
│ │
│ 页面内容区 │
│ │
├──────────────┤
│ 底部Tab导航 │
│ [首页][我的] │
└──────────────┘
```
### 4.3 响应式适配策略
```
一套 Vue 代码,通过 CSS 媒体查询和 Tailwind 断点适配:
├── sm (< 640px) H5 移动端布局底部 Tab 导航
├── md (640-1024px) → 平板端布局
└── lg (> 1024px) → Web 端布局(顶部导航栏)
```
---
## 5. 后端 API 设计
### 5.1 新增公众端 API 模块
```
/api/public/ # 公众端 API无需租户上下文
├── POST /auth/register # 公众注册
├── POST /auth/login # 公众登录
├── GET /activities # 获取公开活动列表
├── GET /activities/:id # 获取活动详情
├── POST /activities/:id/register # 报名活动
├── POST /activities/:id/submit # 提交作品
├── GET /mine/profile # 获取个人信息
├── PUT /mine/profile # 更新个人信息
├── GET /mine/children # 获取子女列表
├── POST /mine/children # 添加子女
├── PUT /mine/children/:id # 编辑子女
├── DELETE /mine/children/:id # 删除子女
├── GET /mine/registrations # 我的报名列表
└── GET /mine/works # 我的作品列表
```
### 5.2 现有 API 改造
```
活动相关 API 变更:
├── 创建活动:新增 visibility 字段public/designated/internal
├── 获取活动列表:支持按 visibility 过滤
├── 报名接口:新增 participant_type 和 child_id 字段
└── 报名记录查询:支持按 participant_type 筛选
```
---
## 6. 多机构联合举办(二期)
### 6.1 主办-协办模型
```
活动表新增:
├── organizer_tenant_id — 主办机构 ID
└── co_organizer_ids — 协办机构 ID 列表JSON 数组)
权限分配:
├── 主办方:完整管理权限(创建、编辑、审核、发布成果)
└── 协办方:有限权限(查看报名数据、推荐评委、查看成果)
```
### 6.2 活动页面展示
```
活动详情页展示:
├── 主办单位:广东省立中山图书馆
└── 协办单位:北京国家图书馆、上海图书馆
```
---
## 7. 一号多身份(二期)
### 7.1 身份切换机制
```
用户登录后:
├── 默认进入公众端(活动大厅)
├── 如果用户同时是某机构的管理员/工作人员
│ └── 显示"切换到管理端"入口
├── 切换身份 = 切换工作台视角
└── 不需要重新登录JWT token 中包含所有身份信息
```
### 7.2 身份绑定
```
用户身份表user_identities
├── user_id — 用户 ID
├── identity_type — 身份类型public / tenant_admin / judge / staff
├── tenant_id — 关联租户(公众身份为 NULL
├── role_id — 关联角色
└── status — 状态active / inactive
```