363 lines
11 KiB
Markdown
363 lines
11 KiB
Markdown
# 公网部署设计文档
|
||
|
||
**日期:** 2026-01-20
|
||
**状态:** 已确认,待实现
|
||
|
||
---
|
||
|
||
## 概述
|
||
|
||
为 Vitals 健康管理应用添加公网访问能力,包括用户认证、邀请码注册、管理后台,并通过 Docker 容器部署到云服务器。
|
||
|
||
---
|
||
|
||
## 需求总结
|
||
|
||
- **访问方式**:公网访问,通过 IP 地址(无域名)
|
||
- **认证方式**:用户名密码登录,JWT Token 认证
|
||
- **注册方式**:邀请码注册,邀请码由管理员生成
|
||
- **权限模型**:普通用户 + 管理员
|
||
- **部署方式**:Docker 容器
|
||
|
||
---
|
||
|
||
## 角色权限
|
||
|
||
| 功能 | 普通用户 | 管理员 |
|
||
|------|---------|--------|
|
||
| 查看/编辑自己的数据 | ✅ | ✅ |
|
||
| 查看/编辑所有用户数据 | ❌ | ✅ |
|
||
| 管理用户(禁用/删除) | ❌ | ✅ |
|
||
| 生成邀请码 | ❌ | ✅ |
|
||
|
||
---
|
||
|
||
## 数据模型
|
||
|
||
### 用户表改动 (users)
|
||
|
||
新增字段:
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| password_hash | TEXT | 密码哈希(bcrypt) |
|
||
| email | TEXT | 邮箱(可选) |
|
||
| is_admin | BOOLEAN | 是否管理员,默认 false |
|
||
| is_disabled | BOOLEAN | 是否禁用,默认 false |
|
||
|
||
### 新增邀请码表 (invites)
|
||
|
||
| 字段 | 类型 | 说明 |
|
||
|------|------|------|
|
||
| id | INTEGER | 主键,自增 |
|
||
| code | TEXT | 邀请码(8位随机字符串) |
|
||
| created_by | INTEGER | 创建者 user_id |
|
||
| used_by | INTEGER | 使用者 user_id(null 表示未使用) |
|
||
| created_at | DATETIME | 创建时间 |
|
||
| expires_at | DATETIME | 过期时间(可选) |
|
||
|
||
---
|
||
|
||
## 认证方案
|
||
|
||
### JWT Token
|
||
|
||
- 登录成功后返回 token,存储在浏览器 localStorage
|
||
- 每次请求在 Header 中携带 `Authorization: Bearer <token>`
|
||
- Token 有效期 7 天
|
||
- Token 内容:`{ user_id, username, is_admin, exp }`
|
||
|
||
### 密码存储
|
||
|
||
- 使用 bcrypt 哈希
|
||
- 不存储明文密码
|
||
|
||
---
|
||
|
||
## 页面设计
|
||
|
||
### 登录页 `/login`
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ Vitals 登录 │
|
||
├─────────────────────────────────────┤
|
||
│ 用户名 │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ └─────────────────────────────┘ │
|
||
│ │
|
||
│ 密码 │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ └─────────────────────────────┘ │
|
||
│ │
|
||
│ [ 登录 ] │
|
||
│ │
|
||
│ 没有账号?立即注册 │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
### 注册页 `/register`
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ Vitals 注册 │
|
||
├─────────────────────────────────────┤
|
||
│ 邀请码 * │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ └─────────────────────────────┘ │
|
||
│ │
|
||
│ 用户名 * │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ └─────────────────────────────┘ │
|
||
│ │
|
||
│ 密码 * │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ └─────────────────────────────┘ │
|
||
│ │
|
||
│ 确认密码 * │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ │ │
|
||
│ └─────────────────────────────┘ │
|
||
│ │
|
||
│ [ 注册 ] │
|
||
│ │
|
||
│ 已有账号?立即登录 │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
### 管理后台 `/admin`(仅管理员可见)
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ 导航栏(首页/运动/.../管理) │
|
||
├─────────────────────────────────────┤
|
||
│ 管理后台 │
|
||
├─────────────────────────────────────┤
|
||
│ 用户管理 │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ 用户名 │ 状态 │ 创建时间 │ 操作│ │
|
||
│ │ rocky │ 正常 │ 01-20 │禁用│ │
|
||
│ │ test │ 禁用 │ 01-19 │启用│ │
|
||
│ └─────────────────────────────┘ │
|
||
├─────────────────────────────────────┤
|
||
│ 邀请码管理 [ 生成邀请码 ] │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ 邀请码 │ 状态 │ 使用者 │ │
|
||
│ │ ABC12345 │ 已用 │ rocky │ │
|
||
│ │ XYZ98765 │ 未用 │ - │ │
|
||
│ └─────────────────────────────┘ │
|
||
├─────────────────────────────────────┤
|
||
│ 数据浏览 │
|
||
│ 用户筛选:[ 全部用户 ▼ ] │
|
||
│ 数据类型:[ 全部类型 ▼ ] │
|
||
│ ┌─────────────────────────────┐ │
|
||
│ │ 数据列表... │ │
|
||
│ └─────────────────────────────┘ │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## API 设计
|
||
|
||
### 新增认证端点
|
||
|
||
| 端点 | 方法 | 说明 |
|
||
|------|------|------|
|
||
| `/api/auth/login` | POST | 登录,返回 JWT |
|
||
| `/api/auth/register` | POST | 注册(需邀请码) |
|
||
| `/api/auth/me` | GET | 获取当前用户信息 |
|
||
|
||
### 新增管理端点
|
||
|
||
| 端点 | 方法 | 说明 |
|
||
|------|------|------|
|
||
| `/api/admin/users` | GET | 用户列表 |
|
||
| `/api/admin/users/{id}` | DELETE | 删除用户 |
|
||
| `/api/admin/users/{id}/disable` | POST | 禁用用户 |
|
||
| `/api/admin/users/{id}/enable` | POST | 启用用户 |
|
||
| `/api/admin/invites` | GET | 邀请码列表 |
|
||
| `/api/admin/invites` | POST | 生成邀请码 |
|
||
| `/api/admin/data` | GET | 查看所有数据(支持筛选) |
|
||
|
||
### 现有 API 改动
|
||
|
||
- 所有 `/api/*` 端点添加 JWT 认证中间件
|
||
- 未登录返回 `401 Unauthorized`
|
||
- 数据自动按当前用户 `user_id` 过滤
|
||
- 排除列表:`/api/auth/login`、`/api/auth/register`
|
||
|
||
---
|
||
|
||
## 访问流程
|
||
|
||
```
|
||
用户访问任意页面
|
||
↓
|
||
检查 localStorage 是否有 Token
|
||
↓
|
||
无 Token → 跳转 /login
|
||
↓
|
||
有 Token → 验证 Token 有效性
|
||
↓
|
||
Token 无效/过期 → 跳转 /login
|
||
Token 有效 → 正常显示页面
|
||
```
|
||
|
||
---
|
||
|
||
## Docker 部署
|
||
|
||
### 文件结构
|
||
|
||
```
|
||
vitals/
|
||
├── Dockerfile
|
||
├── docker-compose.yml
|
||
├── .env.example
|
||
└── data/
|
||
└── vitals.db
|
||
```
|
||
|
||
### Dockerfile
|
||
|
||
```dockerfile
|
||
FROM python:3.11-slim
|
||
|
||
WORKDIR /app
|
||
|
||
COPY pyproject.toml .
|
||
COPY src/ src/
|
||
|
||
RUN pip install --no-cache-dir -e .
|
||
|
||
EXPOSE 8080
|
||
|
||
CMD ["python", "-m", "vitals.web.app", "--host", "0.0.0.0"]
|
||
```
|
||
|
||
### docker-compose.yml
|
||
|
||
```yaml
|
||
version: '3.8'
|
||
|
||
services:
|
||
vitals:
|
||
build: .
|
||
ports:
|
||
- "8080:8080"
|
||
volumes:
|
||
- ./data:/app/data
|
||
environment:
|
||
- ADMIN_USERNAME=${ADMIN_USERNAME}
|
||
- ADMIN_PASSWORD=${ADMIN_PASSWORD}
|
||
- DASHSCOPE_API_KEY=${DASHSCOPE_API_KEY}
|
||
- JWT_SECRET=${JWT_SECRET}
|
||
restart: unless-stopped
|
||
```
|
||
|
||
### .env.example
|
||
|
||
```env
|
||
# 管理员账户(首次启动时创建)
|
||
ADMIN_USERNAME=admin
|
||
ADMIN_PASSWORD=change_me_please
|
||
|
||
# JWT 密钥(请使用随机字符串)
|
||
JWT_SECRET=your_random_secret_key_here
|
||
|
||
# AI 食物识别(可选)
|
||
DASHSCOPE_API_KEY=your_key_here
|
||
```
|
||
|
||
### 部署步骤
|
||
|
||
```bash
|
||
# 1. 上传代码到服务器
|
||
scp -r vitals/ user@server:/path/to/
|
||
|
||
# 2. SSH 到服务器
|
||
ssh user@server
|
||
|
||
# 3. 进入项目目录
|
||
cd /path/to/vitals
|
||
|
||
# 4. 复制并编辑环境变量
|
||
cp .env.example .env
|
||
vim .env
|
||
|
||
# 5. 启动容器
|
||
docker-compose up -d
|
||
|
||
# 6. 查看日志
|
||
docker-compose logs -f
|
||
```
|
||
|
||
访问:`http://服务器IP:8080`
|
||
|
||
---
|
||
|
||
## 实现步骤
|
||
|
||
1. **数据库改动**
|
||
- users 表添加 `password_hash`、`is_admin`、`is_disabled` 字段
|
||
- 新增 `invites` 表
|
||
|
||
2. **认证模块**
|
||
- 实现 JWT 生成/验证(PyJWT)
|
||
- 实现密码哈希(bcrypt)
|
||
- 添加认证中间件
|
||
|
||
3. **认证 API**
|
||
- 实现 `/api/auth/login`
|
||
- 实现 `/api/auth/register`
|
||
- 实现 `/api/auth/me`
|
||
|
||
4. **管理 API**
|
||
- 实现 `/api/admin/*` 端点
|
||
- 添加管理员权限检查
|
||
|
||
5. **前端页面**
|
||
- 登录页 `/login`
|
||
- 注册页 `/register`
|
||
- 管理后台 `/admin`
|
||
- 修改现有页面添加 Token 检查
|
||
|
||
6. **Docker 配置**
|
||
- 创建 Dockerfile
|
||
- 创建 docker-compose.yml
|
||
- 创建 .env.example
|
||
|
||
7. **首次启动逻辑**
|
||
- 检查环境变量创建管理员账户
|
||
|
||
8. **测试**
|
||
- 本地 Docker 测试
|
||
- 部署到服务器验证
|
||
|
||
---
|
||
|
||
## 技术选型
|
||
|
||
| 组件 | 选择 |
|
||
|------|------|
|
||
| 认证 | JWT (PyJWT) |
|
||
| 密码哈希 | bcrypt |
|
||
| 容器 | Docker + docker-compose |
|
||
| Web 服务器 | Uvicorn(内置) |
|
||
|
||
---
|
||
|
||
## 安全考虑
|
||
|
||
- 密码使用 bcrypt 哈希存储
|
||
- JWT 设置合理过期时间(7 天)
|
||
- 邀请码一次性使用
|
||
- 管理员操作需二次确认
|
||
- 建议后续添加 HTTPS(通过 nginx 反向代理 + Let's Encrypt)
|