1
0
Files
nex/openspec/specs/database-migration/spec.md

174 lines
5.6 KiB
Markdown
Raw 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.
# Database Migration
## Purpose
使用 goose 管理数据库迁移,支持自动执行、回滚和版本化管理。
### Requirement: 使用 goose 迁移工具
系统 SHALL 使用 goose 管理数据库迁移。
#### Scenario: goose 安装
- **WHEN** 开发环境设置
- **THEN** SHALL 安装 goose CLI 工具
- **THEN** SHALL 支持通过 CLI 执行迁移
#### Scenario: 迁移文件格式
- **WHEN** 创建迁移文件
- **THEN** SHALL 使用 SQL 格式(.sql 文件)
- **THEN** SHALL 包含 -- +goose Up 和 -- +goose Down 注释
- **THEN** SHALL 支持事务性迁移
### Requirement: 创建初始迁移
系统 SHALL 创建初始 schema 迁移。
#### Scenario: 初始迁移文件
- **WHEN** 创建初始迁移
- **THEN** SHALL 创建单个初始迁移文件(如 `20260421000001_initial_schema.sql`
- **THEN** SHALL 包含 providers、models、usage_stats 表的创建语句
- **THEN** SHALL 包含外键约束
- **THEN** SHALL 包含索引创建语句
#### Scenario: Up 迁移
- **WHEN** 执行 up 迁移
- **THEN** SHALL 创建所有表
- **THEN** SHALL 创建索引
- **THEN** SHALL 创建外键约束
#### Scenario: Down 迁移
- **WHEN** 执行 down 迁移
- **THEN** SHALL 删除所有表和索引
- **THEN** SHALL 按正确顺序删除(避免外键约束错误)
#### Scenario: 按数据库方言拆分迁移目录
- **WHEN** 组织迁移文件
- **THEN** SHALL 将 SQLite 方言迁移文件存储在 `migrations/sqlite/` 目录
- **THEN** SHALL 将 MySQL 方言迁移文件存储在 `migrations/mysql/` 目录
- **THEN** SHALL 两个目录维护独立的版本号序列
- **THEN** SHALL 两个目录的迁移文件内容在逻辑上一致(相同的表结构和约束),但使用各自方言的 DDL
### Requirement: models 表 schema 变更
系统 SHALL 在初始迁移脚本中直接创建新的 models 表结构(服务未上线,无需考虑数据迁移,迁移脚本已合并为单个初始迁移文件)。
#### Scenario: 初始迁移 models 表结构
- **WHEN** 执行迁移
- **THEN** SHALL CREATE models 表包含字段idTEXT PRIMARY KEY存储 UUID 字符串、provider_idTEXT NOT NULL、model_nameTEXT NOT NULL、enabledINTEGER DEFAULT 1、created_atDATETIME
- **THEN** SHALL 存在 UNIQUE(provider_id, model_name) 约束
- **THEN** SHALL 存在 FOREIGN KEY (provider_id) REFERENCES providers(id) ON DELETE CASCADE
### Requirement: 迁移命令集成
迁移 SHALL 集成到 Makefile。
#### Scenario: 迁移 up 命令
- **WHEN** 执行 `make backend-migrate-up`
- **THEN** SHALL 执行所有待执行的迁移
- **THEN** SHALL 使用 `DB_DRIVER` 变量选择方言目录(默认 `sqlite3`
- **THEN** SHALL 使用 `DB_DSN` 变量作为数据库连接串
- **THEN** SHALL 显示迁移进度
#### Scenario: 迁移 down 命令
- **WHEN** 执行 `make backend-migrate-down`
- **THEN** SHALL 回滚最后一个迁移
- **THEN** SHALL 使用 `DB_DRIVER``DB_DSN` 变量
- **THEN** SHALL 显示回滚进度
#### Scenario: 迁移状态命令
- **WHEN** 执行 `make backend-migrate-status`
- **THEN** SHALL 显示当前迁移状态
- **THEN** SHALL 显示已执行和待执行的迁移
#### Scenario: 创建迁移命令
- **WHEN** 执行 `make backend-migrate-create`
- **THEN** SHALL 同时在 `migrations/sqlite/``migrations/mysql/` 两个目录创建新的迁移文件模板
- **THEN** SHALL 使用递增的版本号
#### Scenario: MySQL 迁移命令使用
- **WHEN** 使用 MySQL 驱动执行迁移
- **THEN** SHALL 设置 `DB_DRIVER=mysql`
- **THEN** SHALL 设置 `DB_DSN` 为 MySQL 连接串(如 `user:pass@tcp(localhost:3306)/nex`
### Requirement: 应用启动时迁移
应用 SHALL 在启动时执行迁移。
#### Scenario: 自动迁移
- **WHEN** 应用启动
- **THEN** SHALL 根据 `database.driver` 配置选择对应的迁移目录和 goose dialect
- **THEN** SHALL 在 `driver=sqlite` 时使用 `migrations/sqlite/` 目录goose dialect 为 `sqlite3`
- **THEN** SHALL 在 `driver=mysql` 时使用 `migrations/mysql/` 目录goose dialect 为 `mysql`
- **THEN** SHALL 自动执行待执行的迁移
- **THEN** SHALL 在迁移失败时拒绝启动
- **THEN** SHALL 记录迁移日志
#### Scenario: 迁移版本检查
- **WHEN** 应用启动
- **THEN** SHALL 检查数据库迁移版本
- **THEN** SHALL 在版本不匹配时执行迁移
### Requirement: 连接池配置
系统 SHALL 配置数据库连接池。
#### Scenario: 连接池参数
- **WHEN** 初始化数据库连接
- **THEN** SHALL 设置 MaxIdleConns默认 10
- **THEN** SHALL 设置 MaxOpenConns默认 100
- **THEN** SHALL 设置 ConnMaxLifetime默认 1h
#### Scenario: 连接池监控
- **WHEN** 应用运行
- **THEN** SHALL 定期记录连接池状态(可选)
- **THEN** SHALL 监控连接池使用情况
### Requirement: 迁移回滚支持
系统 SHALL 支持迁移回滚。
#### Scenario: 回滚到指定版本
- **WHEN** 执行 `goose down-to <version>`
- **THEN** SHALL 回滚到指定版本
- **THEN** SHALL 按顺序执行 down 迁移
#### Scenario: 完全回滚
- **WHEN** 执行 `goose reset`
- **THEN** SHALL 回滚所有迁移
- **THEN** SHALL 清空数据库
### Requirement: 迁移文件管理
迁移文件 SHALL 版本化管理。
#### Scenario: 迁移文件命名
- **WHEN** 创建迁移文件
- **THEN** SHALL 使用格式 `<version>_<name>.sql`
- **THEN** SHALL 版本号递增
- **THEN** SHALL 名称使用 snake_case
#### Scenario: 迁移文件存储
- **WHEN** 创建迁移文件
- **THEN** SHALL 按 SQL 方言存储在对应子目录(`migrations/sqlite/``migrations/mysql/`
- **THEN** SHALL 提交到版本控制系统