docs: update

This commit is contained in:
2026-01-03 19:34:20 +08:00
parent 5cdc8b2144
commit c2493841ec
4 changed files with 838 additions and 750 deletions
+181
View File
@@ -0,0 +1,181 @@
# 架构设计
## 系统概述
CheckIn App V2 采用用户-任务分离架构,一个用户可管理多个打卡任务,全局 Token 刷新,任务级别独立控制。
## 核心架构
### V2 关键改进
- **用户-任务分离**: User 和 CheckInTask 独立管理
- **全局 Token**: 用户级别的 authorization token,一次扫码更新所有任务
- **任务级控制**: 每个任务独立的启用状态和邮箱配置
- **任务模板**: TaskTemplate 系统,快速创建标准化任务
### 数据模型
#### User(用户)
```python
- id: 主键
- jwt_sub: QQ ID唯一
- alias: 用户名
- email: 邮箱
- password_hash: 密码可选
- authorization: QQ Token全局
- jwt_exp: Token 过期时间
- role: admin/user
- is_approved: 审批状态
```
#### CheckInTask(任务)
```python
- id: 主键
- user_id: 所属用户
- name: 任务名称
- payload_config: JSON 配置包含打卡字段
- cron_expression: 定时表达式 "0 20 * * *"
- is_active: 是否启用
```
#### CheckInRecord(记录)
```python
- id: 主键
- task_id: 所属任务
- status: success/failed/already_submitted
- response_text: API 响应
- trigger_type: scheduled/manual/admin
- check_in_time: 打卡时间
```
#### TaskTemplate(模板)
```python
- id: 主键
- name: 模板名称
- field_config: JSON 字段配置
- parent_id: 父模板可选
- is_active: 是否启用
```
## 技术栈
### 后端
- **FastAPI**: Web 框架,自动生成 API 文档
- **SQLAlchemy**: ORM,支持多数据库
- **APScheduler**: 任务调度,动态加载 cron 任务
- **Selenium**: 浏览器自动化,获取 QQ Token 和打卡 payload
- **JWT**: 身份认证
- **SMTP**: 邮件通知
### 前端
- **Vue 3**: Composition API
- **Ant Design Vue**: UI 组件库
- **Pinia**: 状态管理
- **Axios**: HTTP 客户端,拦截器处理 Token
## 认证流程
### QQ 扫码登录
1. 用户输入 alias
2. 后端检查 alias 可用性和频率限制
3. Selenium 启动 headless Chrome,打开接龙登录页
4. 生成 QR code,返回给前端
5. 用户手机 QQ 扫码
6. Selenium 检测登录成功,提取 authorization token 和 jwt
7. 存储用户信息(待审批状态)
8. 管理员审批后用户可登录
### 密码登录
1. 用户设置密码后可使用 alias + password 登录
2. 后端验证密码,返回 JWT token
## 打卡流程
### 手动打卡
1. 用户点击任务的"立即打卡"按钮
2. 后端异步执行打卡任务
3. Selenium 获取最新 x-api-request-payload
4. 使用用户的 authorization token 调用接龙 API
5. 解析响应,存储记录
6. 返回结果
### 定时打卡
1. 系统启动时加载所有启用的任务
2. APScheduler 根据 cron_expression 调度
3. 到达时间后自动执行打卡流程
4. 发送邮件通知到任务配置的邮箱
## 调度任务
### Token 监控
- 间隔: 30 分钟(可配置)
- 功能: 检查 Token 过期时间
- 30 分钟内过期: 发送预警邮件
- 已过期 30 分钟内: 发送过期通知
### 会话清理
- 间隔: 24 小时
- 功能: 删除旧的 Selenium 会话文件
### 用户清理
- 间隔: 1 小时
- 功能: 删除 24 小时未审批的用户
## 权限控制
### 角色
- **admin**: 所有权限
- **user**: 仅操作自己的数据
### 验证机制
- 任务所有权验证: 确保用户只能操作自己的任务
- JWT 认证: 所有 API 需要有效 token
- 审批机制: 新用户需管理员审批
## 目录结构
### 后端分层
```
backend/
├── api/ # 路由层(29 个端点)
├── services/ # 业务逻辑层
├── models/ # 数据模型层
├── schemas/ # 请求响应模型
├── workers/ # Selenium 工作模块
└── scripts/ # 工具脚本
```
### 前端分层
```
frontend/src/
├── api/ # API 调用封装
├── views/ # 页面组件
├── components/ # 可复用组件
├── stores/ # Pinia 状态
├── router/ # 路由配置
└── composables/ # 组合式函数
```
## 扩展性
- 数据库可切换到 PostgreSQL/MySQL
- 调度任务可扩展到 Celery
- 前端可独立部署到 CDN
- 支持 Docker 容器化部署
+220
View File
@@ -0,0 +1,220 @@
# 部署指南
## 环境准备
### 系统要求
- Ubuntu 20.04+ / CentOS 7+ / Windows Server
- Python 3.9+
- Node.js 16+
- Chrome / Chromium
- 2GB+ RAM
### 依赖安装
```bash
# Ubuntu
sudo apt update
sudo apt install -y python3 nodejs npm chromium-browser
# CentOS
sudo yum install -y python3 nodejs npm chromium
```
## 生产部署
### 方式一:传统部署
#### 1. 后端部署
```bash
# 克隆项目
git clone <repository>
cd CheckInApp
# 创建虚拟环境
python3 -m venv venv
source venv/bin/activate
# 安装依赖
pip install -r backend/requirements.txt
# 生产环境额外依赖
pip install gunicorn
# 配置环境变量
cp .env.example .env
vim .env # 修改环境变量
```
#### 2. 前端部署
```bash
cd frontend
# 安装依赖
npm install
# 构建生产版本
npm run build
# 输出在 dist/ 目录
```
**使用 Nginx 托管**:
[示例文件](../nginx.conf.example)
#### 3. 使用 Systemd 管理
[示例文件](../checkin-app.service.example)
### 方式二:Docker 部署(推荐)
TODO(Maybe never)
## 配置优化
### 生产环境变量
[示例文件](../.env.example)
### 数据库迁移到 PostgreSQL
```bash
# 安装 PostgreSQL
sudo apt install postgresql postgresql-contrib
# 创建数据库
sudo -u postgres createdb checkin
sudo -u postgres createuser checkin_user
sudo -u postgres psql -c "ALTER USER checkin_user WITH PASSWORD 'password';"
# 修改 .env
DATABASE_URL=postgresql://checkin_user:password@localhost/checkin
```
## 安全加固
### 1. 防火墙配置
```bash
sudo ufw allow 22/tcp # SSH
sudo ufw allow 80/tcp # HTTP
sudo ufw allow 443/tcp # HTTPS
sudo ufw enable
```
### 2. SSL 证书(Let's Encrypt
```bash
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d your-domain.com
# 自动续期
sudo systemctl enable certbot.timer
```
### 3. 限制访问
- 修改 `.env` 中的 `CORS_ORIGINS` 为实际域名
- 在 Nginx 中配置 rate limiting
- 使用 fail2ban 防止暴力破解
## 监控维护
### 日志管理
```bash
# 查看后端日志
tail -f logs/backend.log
```
### 数据库备份
```bash
# SQLite 备份
cp data/checkin.db data/checkin.db.backup
# PostgreSQL 备份
pg_dump checkin > backup.sql
# 定时备份(crontab
0 2 * * * /path/to/backup.sh
```
### 性能监控
使用工具:
- Prometheus + Grafana
- New Relic
- Sentry(错误追踪)
## 扩展部署
### 负载均衡
```nginx
upstream backend {
server 127.0.0.1:8000;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
}
server {
location /api {
proxy_pass http://backend;
}
}
```
### Redis 缓存
```python
# 安装 redis
pip install redis
# 配置会话存储
REDIS_URL=redis://localhost:6379/0
```
## 故障排查
### 端口占用
```bash
sudo lsof -i :8000
sudo kill -9 <PID>
```
### Selenium 问题
```bash
# 检查 Chrome 版本
chromium --version
chromedriver --version
# 确保版本匹配
```
### 权限问题
```bash
# 确保目录权限正确
sudo chown -R www-data:www-data /path/to/CheckInApp
sudo chmod -R 755 /path/to/CheckInApp
```
## 回滚策略
```bash
# 保存当前版本
git tag -a v2.0.0 -m "Production release"
# 回滚到上一版本
git checkout v1.9.0
docker-compose down
docker-compose up -d --build
```
+398
View File
@@ -0,0 +1,398 @@
# 开发指南
## 开发环境设置
### 后端开发
```bash
# 克隆项目
git clone <repository>
cd CheckInApp
# 创建虚拟环境
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
# 安装依赖
pip install -r backend/requirements.txt
# 安装开发依赖
pip install pytest pytest-asyncio black flake8
python3 run.py
```
### 前端开发
```bash
cd frontend
# 安装依赖
npm install
# 启动开发服务器
npm run dev
# 代码格式化
npm run lint
npm run format
```
## 项目结构
### 后端目录说明
```
backend/
├── main.py # FastAPI 应用入口,CORS、路由注册
├── config.py # Pydantic Settings 配置
├── dependencies.py # 依赖注入(认证、权限)
├── exceptions.py # 自定义异常类
├── models/ # SQLAlchemy 数据模型
│ ├── database.py # 数据库连接、Session
│ ├── user.py
│ ├── check_in_task.py
│ ├── check_in_record.py
│ └── task_template.py
├── schemas/ # Pydantic 请求响应模型
│ ├── user.py
│ ├── task.py
│ ├── auth.py
│ └── response.py # 标准化响应
├── api/ # API 路由(按模块划分)
│ ├── auth.py # 认证相关
│ ├── users.py # 用户管理
│ ├── tasks.py # 任务管理
│ ├── check_in.py # 打卡功能
│ ├── admin.py # 管理员功能
│ └── templates.py # 模板管理
├── services/ # 业务逻辑层
│ ├── auth_service.py
│ ├── user_service.py
│ ├── task_service.py
│ ├── check_in_service.py
│ ├── scheduler_service.py
│ ├── template_service.py
│ └── registration_manager.py
└── workers/ # Selenium 自动化
├── token_refresher.py # QQ 登录
├── check_in_worker.py # 打卡执行
└── email_notifier.py # 邮件发送
```
### 前端目录说明
```
frontend/src/
├── main.js # Vue 应用入口
├── App.vue # 根组件
├── api/ # API 封装
│ ├── client.js # Axios 实例、拦截器
│ └── index.js # API 模块(auth, user, task 等)
├── views/ # 页面组件
│ ├── LoginView.vue
│ ├── DashboardView.vue
│ ├── TasksView.vue
│ ├── RecordsView.vue
│ └── admin/ # 管理员页面
├── components/ # 可复用组件
│ ├── TaskCard.vue
│ ├── RecordTable.vue
│ └── ...
├── stores/ # Pinia 状态管理
│ ├── auth.js # 认证状态
│ ├── user.js # 用户信息
│ └── task.js # 任务列表
├── router/ # Vue Router
│ └── index.js # 路由配置、导航守卫
└── composables/ # 组合式函数
├── useAuth.js
└── useTask.js
```
## 开发流程
### 添加新功能
#### 1. 后端 API 开发
**步骤**:
1.`models/` 定义数据模型
2.`schemas/` 定义请求响应模型
3.`services/` 实现业务逻辑
4.`api/` 创建路由端点
5.`main.py` 注册路由
**示例**: 添加一个新的"任务标签"功能
```python
# models/task_tag.py
class TaskTag(Base):
__tablename__ = "task_tags"
id = Column(Integer, primary_key=True)
task_id = Column(Integer, ForeignKey("check_in_tasks.id"))
tag_name = Column(String(50))
# schemas/tag.py
class TaskTagCreate(BaseModel):
tag_name: str
# services/tag_service.py
def create_tag(db: Session, task_id: int, tag_data: TaskTagCreate):
tag = TaskTag(task_id=task_id, tag_name=tag_data.tag_name)
db.add(tag)
db.commit()
return tag
# api/tags.py
@router.post("/tasks/{task_id}/tags")
def add_tag(task_id: int, tag: TaskTagCreate, db: Session = Depends(get_db)):
return tag_service.create_tag(db, task_id, tag)
# main.py
from api import tags
app.include_router(tags.router, prefix="/api")
```
#### 2. 前端开发
**步骤**:
1.`api/index.js` 添加 API 调用
2.`stores/` 创建或更新状态
3. 创建或更新 Vue 组件
4. 配置路由(如需要)
**示例**: 添加标签管理页面
```javascript
// api/index.js
export const tagApi = {
addTag: (taskId, data) => client.post(`/tasks/${taskId}/tags`, data),
getTags: (taskId) => client.get(`/tasks/${taskId}/tags`)
}
// stores/tag.js
export const useTagStore = defineStore('tag', {
state: () => ({
tags: []
}),
actions: {
async fetchTags(taskId) {
const { data } = await tagApi.getTags(taskId)
this.tags = data
}
}
})
// components/TagManager.vue
<template>
<div>
<a-tag v-for="tag in tags" :key="tag.id">{{ tag.tag_name }}</a-tag>
<a-button @click="addTag">添加标签</a-button>
</div>
</template>
```
### 数据库迁移
```bash
# 修改模型后生成迁移脚本
# 手动创建脚本在 backend/scripts/migrate_*.py
# 执行迁移
python backend/scripts/migrate_xxx.py
```
### 测试
#### 后端测试
```python
# tests/test_task_service.py
import pytest
from backend.services import task_service
def test_create_task():
task = task_service.create_task(db, user_id=1, task_data)
assert task.name == "Test Task"
assert task.is_active == True
# 运行测试
pytest backend/tests/
```
#### 前端测试
```javascript
// tests/TaskCard.spec.js
import { mount } from '@vue/test-utils'
import TaskCard from '@/components/TaskCard.vue'
test('displays task name', () => {
const wrapper = mount(TaskCard, {
props: { task: { name: 'Test Task' } }
})
expect(wrapper.text()).toContain('Test Task')
})
// 运行测试
npm run test
```
## 代码规范
### 后端规范
- 使用 Black 格式化: `black backend/`
- 遵循 PEP 8
- 函数添加类型注解
- API 路由使用 Pydantic 模型验证
- 使用 dependency injection
```python
# 好的示例
async def create_task(
task_data: TaskCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
) -> TaskResponse:
"""创建新任务"""
return task_service.create_task(db, current_user.id, task_data)
```
### 前端规范
- 使用 ESLint + Prettier
- 组件使用 Composition API
- 使用 `<script setup>` 语法
- Props 添加类型验证
- 统一使用 Ant Design Vue 组件
```vue
<!-- 好的示例 -->
<script setup>
import { ref, computed } from 'vue'
const props = defineProps({
task: {
type: Object,
required: true
}
})
const isActive = computed(() => props.task.is_active)
</script>
```
## 调试技巧
### 后端调试
```python
# 使用 logging
import logging
logger = logging.getLogger(__name__)
logger.info(f"Creating task for user {user_id}")
# 使用 pdb
import pdb; pdb.set_trace()
# 查看 SQL 查询
import logging
logging.basicConfig()
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
```
### 前端调试
```javascript
// 使用 Vue Devtools
// Chrome 扩展安装
// console 输出
console.log('Task data:', task.value)
// 调试 API 请求
axios.interceptors.request.use(request => {
console.log('Request:', request)
return request
})
```
## 常见问题
### CORS 错误
`.env` 添加前端地址:
```env
CORS_ORIGINS=http://localhost:3000
```
### 数据库锁定
使用 connection pool:
```python
engine = create_engine(
DATABASE_URL,
pool_pre_ping=True,
pool_size=10
)
```
### Selenium 超时
增加等待时间:
```python
WebDriverWait(driver, 30).until(...)
```
## Git 工作流
```bash
# 创建功能分支
git checkout -b feature/task-tags
# 提交代码
git add .
git commit -m "feat: add task tag functionality"
# 合并到主分支
git checkout main
git merge feature/task-tags
# 推送
git push origin main
```
## 性能优化
### 后端优化
- 使用 SQLAlchemy 的 `joinedload` 避免 N+1 查询
- 添加数据库索引
- 使用异步任务处理耗时操作
- 启用 gzip 压缩
### 前端优化
- 使用虚拟滚动处理大列表
- 路由懒加载
- 图片懒加载
- 使用 `keep-alive` 缓存组件