feat(courseware,docs): 完善课件传输与岛编辑并统一全仓文档

- 增加课件上传、班级可见范围、设备补收与传输进度
- 整合自定义灵动岛编辑器和相关客户端交互
- 同步三端契约、数据库迁移、部署配置与隔离回归
- 按源码统一文档与官网说明,移除过时任务书和审查记录
- 保持产品版本为 1.4.0
This commit is contained in:
LoveChengke committed 2026-10-18 11:53:37 +08:00
1 parent 536379036a
commit c7f215a09c
127 files changed
+4334 -8482

No files matched your search

+31 -118
View File
@@ -1,134 +1,47 @@
---
title: MySQL 切换指南
description: 通过快照和受支持的换库流程切换 SQLite/MySQL,保留迁移历史。
---
# MySQL 切换指南
本项目默认使用 **SQLite(libSQL 内嵌模式)** 跑本地开发,数据模型与访问层已按
MySQL 兼容方式设计,可平滑切换到云端 MySQL / MariaDB 统一存储。
默认数据库为 SQLite,服务端也支持 MySQL/MariaDB。唯一 schema 为 packages/server/prisma/schema.prisma;
Prisma 通过 libSQL 或 MariaDB driver adapter 访问,两种适配器已随运行时依赖内置。
角色、优先级等以 String 加 API 校验存储,不用 Prisma enum 或 @db.*。
## 为什么默认是 SQLite
## 已有数据的切换
- 本地零依赖即可跑通全部功能(无需安装数据库服务)
- `schema.prisma` 刻意只使用跨库通用类型
(`String` / `Int` / `Float` / `Boolean` / `DateTime`,无 `enum`、无 `@db.*` 原生类型)
管理员在“数据库管理 → 一键切换数据库”填写**空目标库**连接串,并完成界面确认。
还须 database:manage;页面和具体接口各自检查权限。
## 设计上的兼容约定
1. 备份并导出当前数据库为 JSON 快照。
2. 测试目标连接,确认目标为空。
3. 改写 schema provider,子进程生成对应 Prisma Client。
4. 打包形态编译生成的 TypeScript 客户端。
5. 子进程基于当前 schema 建表,并用 apply-snapshot 写入快照。
6. 成功后写入 .env 的 DATABASE_PROVIDER/DATABASE_URL;重启服务端连接新库。
| 约定 | 说明 |
| ------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| 不使用 Prisma `enum` | 角色(`ADMIN/TEACHER/STUDENT`)与优先级(`LOW/NORMAL/HIGH/URGENT`)以 `String` 存储,由 zod 在 API 层校验,两种数据库行为完全一致 |
| 主键为 `String @default(cuid())` | 不依赖自增,便于多端离线生成与合并 |
| 时间统一 `DateTime` | 由应用层与驱动适配器负责时区,不使用数据库原生时间函数 |
| 唯一约束仅使用 `@@unique` / `@unique` | SQLite 与 MySQL 语义一致 |
| 级联删除使用 Prisma 的 `onDelete` | 由 Prisma 生成对应外键动作 |
失败时回滚 schema,环境配置仅在成功后写入。快照覆盖的表以 lib/snapshot.ts 为准。
目标已有表时拒绝;回到 SQLite 也应指定新空文件,不能删除正在使用的数据库。
旧源库请保留到验证完成。课件实体不在 JSON 内,换主机时需另复制文件目录,见[课件](../app/courseware.md)。
## 切换到 MySQL
## 源码开发与配置
### 方式一:Web 管理端「数据库管理 → 一键切换」(推荐,v1.0.0 新增)
管理员在 Web 管理端打开 **数据库管理** 页(`/database`,仅 ADMIN 可见),在「一键切换数据库」卡片里:
1. 选目标类型(SQLite ⇄ MySQL)并填**空库**连接串(有表的库会被拒绝,防误覆盖);
2. 输入「确认迁移」→ 点「开始迁移」。
界面会自动依次执行(带步骤进度条):
1. **备份当前数据库**(gzip JSON 快照存 `<数据目录>/backups/`,失败可回滚);
2. 导出当前数据为快照;
3. 测试目标库连接;
4. 检查目标库为空;
5. 改写 `schema.prisma` 的 provider;
6. 子进程 `prisma generate` 生成新方言的 Prisma 客户端;
7. (打包形态)把生成的 `.ts` 客户端编译进 `dist/generated`;
8. 子进程 `prisma db push` 在目标库建表;
9. 子进程 `dist/tools/apply-snapshot.js` 把快照写入目标库;
10. 全部成功后改写 `.env` 的 `DATABASE_PROVIDER` / `DATABASE_URL`。
**完成后必须重启服务端**(安装版运行 `restart.cmd`,开发模式重跑 `pnpm dev:server`)才会连接新库。
中途任一步失败会**回滚 `schema.prisma`**,`.env` 不被改写 —— 现有数据库与配置保持可用。
> 同一页还提供:连接状态检测(版本 / 体积 / 各表行数)、连接测试、手动与**定时备份**、
> 备份恢复、快照导出导入、SQLite 数据库文件下载。备份与导入导出共用同一种 JSON 快照格式,
> 因此**任意备份都能恢复回任意一种受支持的数据库**。
>
> 只支持 SQLite 与 MySQL 两种主库:Redis 等键值库不是 Prisma 支持的主数据库(无法建表/迁移),
> 接口层直接拒绝。
### 方式二:命令行手工切换
#### 1. 修改 provider
```bash
# 自动把 prisma/schema.prisma 的 provider 改成 mysql
node scripts/use-database.mjs mysql
```
#### 2. MySQL 驱动适配器(自 v1.0.0 起已随包内置)
Prisma 7 要求所有数据库都通过 driver adapter 接入,MySQL 对应 `@prisma/adapter-mariadb`
(该适配器基于 `mariadb` 驱动,兼容 MySQL 8)。**它已在 `packages/server/package.json` 的
依赖里**(数据库管理模块的连接测试/迁移需要),因此无需再手动安装:
```bash
# 仅当从旧版本升级、依赖里还没有时才需要
pnpm --filter @classhelper/server add @prisma/adapter-mariadb
```
`packages/server/src/lib/db.ts` 内置分支:当 `DATABASE_PROVIDER=mysql` 时会动态加载该适配器,
服务端代码无需改动。
#### 3. 配置环境变量
编辑 `packages/server/.env`:
scripts/use-database.mjs 只切换 schema provider,不迁移数据、不改 .env、不替代完整换库流程。
如果只准备一个全新的开发环境,可用 pnpm db:switch:mysql,再配置独立空库并生成客户端;
建模和导入仍按受支持流程完成。配置示例:
```dotenv
DATABASE_PROVIDER=mysql
DATABASE_URL="mysql://classhelper:your-password@127.0.0.1:3306/classhelper"
```
> 云端部署时把 `127.0.0.1` 换成云数据库内网/公网地址;
> 生产环境请同时修改 `JWT_SECRET` 与 `CORS_ORIGIN`。
SQLite 迁移目录属于仓库升级历史,不要为了切库删除它,也不要对已有数据运行 db:seed/db:reset。
SQLite SQL 不直接应用到 MySQL;换库流程基于当前 schema 建表,保留原迁移用于 SQLite 升级。
Prisma Client 与实际 provider 必须一致;切换后未重启时旧进程仍连接旧库。
#### 4. 重建迁移并生成客户端
## 部署核验
SQLite 与 MySQL 的 DDL 方言不同,**必须重新生成迁移文件**:
```bash
# 删除 SQLite 迁移历史(迁移文件是方言相关的)
rm -rf packages/server/prisma/migrations
# 重新生成并应用(需要目标库可连接,且账号有建表权限)
pnpm db:migrate
# 初始化演示数据
pnpm db:seed
```
也可以先只生成 SQL 供 DBA 审核:
```bash
pnpm --filter @classhelper/server exec prisma migrate dev --create-only --name init_mysql
```
> 只搬数据、不要演示数据时,用界面的「下载快照 / 导入快照」更省事:
> 旧库导出 JSON → 切库建表 → 新库导入,一份快照也可用 CLI 迁移:
> `node server/dist/tools/apply-snapshot.js --provider mysql --url "mysql://..." --file snapshot.json`
#### 5. 回到 SQLite
```bash
node scripts/use-database.mjs sqlite
# 同步 .env:DATABASE_PROVIDER=sqlite、DATABASE_URL="file:./prisma/dev.db"
rm -rf packages/server/prisma/migrations # 若之前已切换成 MySQL 迁移
pnpm db:migrate
```
> 用界面「一键切换」回 SQLite 时,目标库同样必须是空文件:删除旧 `.db` 或指定一个新路径。
## 生产部署注意事项
1. **连接池**:Prisma 7 的 driver adapter 使用底层驱动(`mariadb`)的连接池设置,
与 Prisma 6 默认值不同(例如默认无连接超时)。建议通过适配器参数显式设置连接上限与时区。
2. **时区**:`Grade.publishedAt`、`Homework.dueAt` 等字段建议在数据库会话中统一为 UTC,
三端展示时再按本地时区格式化(前端使用 `@classhelper/shared` 的 `formatDate`)。
3. **迁移部署**:CI/CD 中使用 `prisma migrate deploy`(对应 `pnpm db:deploy`)而不是 `migrate dev`。
4. **备份**:切换云数据库后,`packages/server/prisma/dev.db` 不再被使用,可从 `.gitignore` 之外移除。
界面「定时备份」把快照写进 `<数据目录>/backups/`(MySQL 模式下即安装根 `data/backups/`),
**服务端进程不运行时不会补跑**;关键环境建议同时用数据库自带的备份策略。
5. **安装包体积**:切换链路需要随包内置 `prisma` CLI 与 `typescript` 编译器(Prisma 7 生成器产出
`.ts`,切换后需在目标机编译进 `dist/generated`),服务端安装包因此约 34MB → 71MB。
确认新库连接、表行数、班级登录、课表和成绩读取;保留切换前快照。
生产凭据放 .env 或部署密钥中,不提交 Git。完整备份和各形态命令见[数据库管理](database.md)。
Linux 正式包应在 Linux 构建,否则 Prisma engine 可能是宿主平台版本,见[Linux 部署](linux-deploy.md)。