Files
asd-backend/docs/MIGRATIONS.md

135 lines
4.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 数据库迁移
## 概述
所有数据库结构变更通过 SQL 迁移脚本管理,存储在 `migrations/` 目录,按序号命名。
部署时 `deploy.sh` 自动检测并执行未运行的迁移:
```
upload_dir "迁移文件" migrations → 上传到服务器
run_migrations → 逐条执行未迁移的脚本
```
已执行的迁移记录在数据库 `_migrations` 表中。
## 迁移文件清单
| 序号 | 文件 | 操作 | 说明 |
|------|------|------|------|
| 001 | `001_add_payment_fields.sql` | `ALTER TABLE users ADD COLUMN` | 添加 `is_member`, `is_admin`, `membership_expires_at` 字段 |
| 002a | `002_add_payment_orders.sql` | `CREATE TABLE` | 创建 `payment_orders` 表 |
| 002b | `002_add_user_profile_fields.sql` | `ALTER TABLE users ADD COLUMN` | 添加 `avatar_url`, `nickname` 字段 |
| 003 | `003_set_all_users_paid.sql` | `SELECT 1`(空操作) | **历史遗留**:原将所有用户设为付费,已改为空操作 |
| 004 | `004_add_refresh_tokens.sql` | `CREATE TABLE` | 创建 `refresh_tokens` 表(双 Token 机制) |
| 005 | `005_add_web_login_codes.sql` | `CREATE TABLE` | 创建 `web_login_codes` 表(网页端扫码登录) |
| 006 | `006_add_performance_indexes.sql` | `CREATE INDEX` | 添加性能索引(`user_id`, `date`, `is_favorite` |
| 007 | `007_add_spot_check_count.sql` | `ALTER TABLE` | `weather_data` 添加 `spotcheckcount` 字段 |
| 009 | `009_add_payment_audit_log.sql` | `CREATE TABLE` | 创建 `payment_audit_log` 表(支付审计日志) |
| 010 | `010_rename_paid_fields.sql` | `ALTER TABLE RENAME COLUMN` | `is_paid``is_member`, `paid_expires_at``membership_expires_at` |
| 011 | `011_add_notifications.sql` | `CREATE TABLE` | 创建 `notifications` 表(通知系统) |
> **注意**:序号不连续(无 008是因为跳过了一个已撤销的迁移。新迁移请继续使用下一可用序号如 012
## 迁移说明
### 003 — 历史遗留
此迁移**最初**执行了 `UPDATE users SET is_paid = true`,将所有已有用户设为永久付费会员(用于早期测试)。发现后已改为空操作 `SELECT 1 WHERE 1 = 1`。**已有的被修改的数据需要用脚本手动回退**。
### 009 — 自动建表
此迁移对应的代码中有幂等 `CREATE TABLE IF NOT EXISTS` 逻辑,即使未通过迁移系统执行,代码也会自动建表。迁移文件本身保留以确保正式部署时 `_migrations` 表记录完整。
### 010 — 字段重命名
`is_paid``is_member`(会员身份凭证,即使过期也保留)
`paid_expires_at``membership_expires_at`NULL 表示永久会员)
## 如何创建新迁移
```bash
# 1. 创建迁移文件
touch migrations/012_your_description.sql
# 2. 写入 SQL
vim migrations/012_your_description.sql
# 3. 部署时自动执行
./deploy.sh production # 会自动运行新迁移
./deploy.sh development # 开发环境同理
```
### 迁移编写规范
| 规则 | 说明 |
|------|------|
| **幂等** | 使用 `IF NOT EXISTS` / `IF EXISTS`,可重复执行 |
| **事务** | 关键操作使用 `BEGIN` / `COMMIT` |
| **回滚** | 考虑失败场景,避免不可逆操作 |
| **注释** | 文件头部写清目的、日期、依赖关系 |
示例:
```sql
-- ============================================
-- 迁移: 012_add_example.sql
-- 目的: 创建示例表
-- 日期: 2026-05-26
-- ============================================
CREATE TABLE IF NOT EXISTS example (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
```
## 如何手动执行迁移
在服务器上直接运行:
```bash
ssh root@1panel-server
docker exec -i 1Panel-postgresql-FtMo psql -U milkydata -d milkydata \
< /root/rust/rust_backend/migrations/012_your_migration.sql
# 记录到 _migrations 表
docker exec 1Panel-postgresql-FtMo psql -U milkydata -d milkydata \
-c "INSERT INTO _migrations (name) VALUES ('012_your_migration.sql');"
```
## 迁移测试
部署后 `test_migration_status` 会自动检查:
- `_migrations` 表是否存在
- 已执行的迁移数量
- 最后一次执行的迁移文件名
## 当前执行状态
### 开发库 `milkydata_dev`
```
001_add_payment_fields.sql
002_add_payment_orders.sql
002_add_user_profile_fields.sql
003_set_all_users_paid.sql
004_add_refresh_tokens.sql
005_add_web_login_codes.sql
006_add_performance_indexes.sql
007_add_spot_check_count.sql
009_add_payment_audit_log.sql
010_rename_paid_fields.sql
```
### 生产库 `milkydata`
`_migrations` 表尚未创建。缺失的迁移:
- 004 (refresh_tokens)
- 005 (web_login_codes)
- 009 (payment_audit_log)
- 011 (notifications)