DOCS · 晨读版
把它跑起来,然后去睡觉。
这里是 University Helper 的完整帮助:从本地起服务、配环境变量,到 Docker 部署和两个平台的功能用法。仓库内的 docs/ 目录始终是最权威的版本。
概览
University Helper 是一个自托管的校园课程自动化平台,基于 FastAPI + React 构建。它替你完成超星学习通的签到与泛雅课程任务、智慧树的课程任务, 并把所有任务状态保存在属于你自己的租户数据库里。
- 多租户隔离 —— 每位用户一座 PostgreSQL 数据库(
tenant_<username>),跨租户数据泄露在物理上不可能。 - 凭据加密 —— 第三方平台账号密码使用 Fernet 对称加密后才写入数据库。
- JWT 认证 —— REST API 全部走
Authorization: Bearer,令牌默认 30 分钟过期。 - 加固部署 —— 非 root 容器、只读根文件系统、nginx 限速与安全响应头。
仓库名为 university-helper;部分源码仍保留历史内部名 easy_learning(容器名、环境变量前缀),正在逐步统一。
快速开始
一条龙引导脚本会创建 .env 并安装 Python / Node 依赖:
$ bash scripts/setup.sh # 创建 .env,安装依赖
$ make start # docker-compose 栈(应用 + postgres)
$ make test # pytest + vitest
只跑后端
$ cd backend
$ cp .env.example .env # 编辑 SECRET_KEY / CORS_ORIGINS / 数据库凭据
$ python -m venv .venv && source .venv/bin/activate
$ pip install -r requirements.txt -r requirements-dev.txt
$ uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
只跑前端
$ cd frontend
$ npm install
$ npm run dev # http://localhost:3000,/api 自动代理到 :8000
数据库
需要 PostgreSQL 15+。database/ 下的 schema 文件会被 docker
entrypoint 自动执行;Alembic 迁移位于
backend/alembic/versions/,用 alembic upgrade head 应用。
环境变量
后端启动前,至少要配置下面这些键(参考根目录 .env.example):
| 变量 | 必填 | 说明 |
|---|---|---|
MAIN_DB_HOST / NAME / USER / PASSWORD | 是 | 主库连接信息。 |
SECRET_KEY | 是 | JWT 签名密钥,长度 ≥ 16 字符(生产建议 ≥ 32)。 |
CORS_ORIGINS | 是 | JSON 数组,例如 ["http://localhost:3000"]。 |
CREDENTIAL_ENCRYPTION_KEY | 生产必填 | Fernet 密钥(urlsafe-base64)。生产环境缺少它应用会拒绝启动;开发环境可省略。 |
POSTGRES_PASSWORD | Docker 部署必填 | 容器内 Postgres 超级用户密码。 |
APP_PORT | 否 | 后端监听端口,默认 8000。 |
ENV | 否 | 设为 production 启用生产模式校验。 |
SHUAKE_COMPAT_SECRET | 否 | ≥ 32 字符时启用 7 天兼容令牌接口 GET /auth/shuake-token。 |
DOCS_ENABLED | 否 | 设为 true 时在 /docs 暴露 Swagger UI。 |
$ python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
.env。首次对外部署前,立即更换数据库密码与 JWT 密钥。Docker 部署
生产部署使用 docker-compose.server.yml + Dockerfile.server,
由宿主机 nginx 负责 TLS 终止与前端静态文件(栈内没有 nginx 容器)。
权威文档见仓库内 docs/DEPLOYMENT.md。
$ git clone https://github.com/sweetcornna/university-helper.git
$ cd university-helper
$ cp .env.example .env # 填 SECRET_KEY · POSTGRES_PASSWORD · CREDENTIAL_ENCRYPTION_KEY · CORS_ORIGINS
$ docker compose -f docker-compose.server.yml -p university-helper up -d --build
首次部署的检查顺序:
- 手动创建并填好
.env(见上节,密钥不进仓库)。 docker compose … up -d --build起栈。- 配置宿主机 nginx:TLS 终止、
root frontend/dist;、/api/反代到http://127.0.0.1:8000。 - 验证:
curl -fsS http://127.0.0.1:8000/health。
scripts/hotfix_publish.sh 单文件热更新(SSH-key 认证优先),不要重复整栈重建。仓库根目录的旧 deploy.* 脚本已归档至 scripts/_legacy/,禁止运行。功能指南 · 超星学习通
登录
在「超星」页面使用手机号 + 密码登录。登录成功后即可拉取课程列表,凭据按需加密保存。
签到
- 普通 / 二维码 / 位置签到均支持;位置签到内置地图检索,搜索地点即可取得坐标。
- 「一键全签」会对当前所有进行中的签到逐一提交(
POST /chaoxing/sign-all)。
泛雅课程任务
在课程页选择要推进的课程后发起任务(POST /course/start,platform: "chaoxing")。
视频与章节测验会按章节顺序自动推进,进度与日志可随时查询,任务支持暂停 / 续跑 / 停止。
功能指南 · 智慧树
登录
- 扫码登录:发起
POST /course/zhihuishu/qr-login后页面会展示二维码,用智慧树 App 扫码确认。 - 密码登录:手机号 + 密码(
POST /course/zhihuishu/password-login)。
课程任务
选好课程后入队(POST /course/zhihuishu/tasks/course)。任务在后台逐节推进视频,
与超星任务共用同一套进度 / 日志 / 暂停 / 续跑 / 停止接口。
API 参考
Base URL:http://localhost:8000/api/v1(本地)。所有接口返回 JSON,错误统一为
{ "code": "ErrorClassName", "message": "…" }。
除公共路由外,所有接口需要 Authorization: Bearer <jwt>。
DOCS_ENABLED=true 后,/docs 有可交互的 Swagger UI,/openapi.json 是原始 spec —— 在线探索请优先用它们。认证
| 方法 | 路径 | 用途 |
|---|---|---|
POST | /auth/register | 注册:创建用户并自动建租户库,返回 JWT。用户名需匹配 ^[a-z0-9]+$;密码 ≥ 8 位且含大小写与数字。 |
POST | /auth/login | 邮箱 + 密码登录,返回与注册相同的结构。 |
GET | /auth/shuake-token | 签发 7 天兼容令牌(需配置 SHUAKE_COMPAT_SECRET)。 |
超星
| 方法 | 路径 | 用途 |
|---|---|---|
POST | /chaoxing/login | 手机号 + 密码登录,预热客户端缓存。 |
GET | /chaoxing/courses | 列出当前账号的课程。 |
POST | /chaoxing/sign | 提交单个进行中的签到。 |
POST | /chaoxing/sign-all | 提交所有进行中的签到。 |
GET | /chaoxing/location/* | 地理编码 / 地点搜索 / 逆地理编码(公共路由,供地图选点)。 |
课程任务(超星泛雅 + 智慧树)
| 方法 | 路径 | 用途 |
|---|---|---|
POST | /course/start | 启动课程任务,platform 取 "chaoxing" 或 "zhihuishu"。 |
GET | /course/status/{task_id} | 轮询任务进度。 |
GET | /course/tasks | 列出当前用户的任务。 |
GET | /course/logs/{task_id} | 读取任务日志行。 |
POST | /course/task/{task_id}/pause · /resume · /stop | 暂停 / 续跑 / 停止任务。 |
POST | /course/zhihuishu/qr-login | 发起智慧树扫码登录,返回会话 id 与二维码 PNG。 |
POST | /course/zhihuishu/password-login | 智慧树手机号 + 密码登录。 |
POST | /course/zhihuishu/tasks/course | 入队智慧树课程任务。 |
轮询 status 与 logs 时请带退避间隔;任务数据以 JSONB 存于你的租户库(course_task_store)。
常见问题
注册时提示用户名或密码不合法?
用户名只允许小写字母与数字(^[a-z0-9]+$);密码至少 8 位,且必须同时包含大写字母、小写字母和数字。
后端起不来,日志说缺环境变量?
检查 MAIN_DB_*、SECRET_KEY(≥ 16 字符)、CORS_ORIGINS 是否齐全。ENV=production 时还必须提供 CREDENTIAL_ENCRYPTION_KEY,否则应用会拒绝启动 —— 这是有意设计。
前端请求 /api 报跨域或 404?
开发模式下 Vite 把 /api 代理到 http://localhost:8000,先确认后端在 8000 端口活着。跨域错误通常是 CORS_ORIGINS 没把前端地址(如 http://localhost:3000)加进去 —— 注意它是 JSON 数组格式。
课程任务的进度去哪里看?
界面上每个任务卡片都有实时进度;接口层面用 GET /course/status/{task_id} 轮询,GET /course/logs/{task_id} 看逐行日志。任务可随时 pause / resume / stop。
Swagger / 接口调试页面在哪里?
设置 DOCS_ENABLED=true 后访问 /docs(Swagger UI),原始 OpenAPI spec 在 /openapi.json。生产环境建议保持关闭。
我的平台账号密码安全吗?
第三方平台凭据在写入数据库前先用 Fernet 对称加密,密钥只存在于服务器环境变量中,不进仓库、不进镜像。另外每位用户的数据存在独立的租户库里,应用层越权也读不到别人的数据。
8000 端口被占了怎么办?
改 .env 里的 APP_PORT,同时记得同步前端代理与 nginx 反代的上游端口。
怎么更新已部署的服务?
整体升级:拉新代码后重新 docker compose -f docker-compose.server.yml up -d --build。单文件热修复:scripts/hotfix_publish.sh backend/app/main.py(需要配置 SERVER_IP 与 SSH key),后端文件会同步进容器并自动重启,依赖层变更会触发整镜像重建。
安全与合规
安全基线
- 后端容器非 root(UID/GID 10001)运行,只读根文件系统,Linux capabilities 全部裁剪。
- nginx 强制
Content-Security-Policy、HSTS、frame-ancestors deny,登录接口限速 5 次/分。 - Postgres 限制最大连接数、开启慢查询日志与 WAL 压缩;备份加密存储。
- 安全漏洞请按 SECURITY.md 流程私下报告。