# 初始化数据库迁移系统 **日期**: 2026-01-27 **类型**: 数据库迁移 **影响范围**: 全新环境部署 ## 概述 创建完整的初始化数据库迁移脚本,支持全新环境一键创建所有表结构。 ## 背景 之前的基线迁移(baseline)只是标记现有数据库状态,不包含实际的建表逻辑。这导致全新环境部署时无法自动创建表结构。 ## 变更内容 ### 1. 删除旧基线迁移 删除文件: - `server/alembic/versions/20260127_1412_dc0e4f0a740c_baseline_标记现有数据库状态.py` ### 2. 生成完整初始化迁移 新文件: - `server/alembic/versions/20260127_1931_3a3a2a1417de_initial_schema_初始化所有表结构.py` - **迁移版本**: `3a3a2a1417de` 包含所有表的完整建表逻辑: - ✅ 用户系统(users, user_sessions) - ✅ 文件夹系统(folders, folder_members) - ✅ 项目系统(projects, project_members, project_shares, project_versions) - ✅ AI 服务(ai_models, ai_jobs, ai_quotas, ai_usage_logs) - ✅ 积分系统(credit_transactions, credit_consumption_logs, credit_gifts, credit_packages, credit_pricing) - ✅ 充值系统(recharge_orders, payment_callbacks) - ✅ 短信服务(sms_verification_codes) ### 3. 自动创建 UUID v7 函数 迁移脚本在 `upgrade()` 函数开头自动创建 UUID v7 函数: ```python def upgrade() -> None: """升级数据库""" # 1. 创建 UUID v7 函数(必须在创建表之前) op.execute(""" CREATE OR REPLACE FUNCTION gen_uuid_v7() RETURNS uuid AS $$ DECLARE unix_ts_ms BIGINT; uuid_bytes BYTEA; BEGIN unix_ts_ms = (EXTRACT(EPOCH FROM CLOCK_TIMESTAMP()) * 1000)::BIGINT; uuid_bytes = SUBSTRING(INT8SEND(unix_ts_ms) FROM 3 FOR 6) || gen_random_bytes(10); RETURN ENCODE( SET_BYTE(SET_BYTE(uuid_bytes, 6, (GET_BYTE(uuid_bytes, 6) & 15) | 112), 8, (GET_BYTE(uuid_bytes, 8) & 63) | 128), 'hex' )::UUID; END; $$ LANGUAGE plpgsql VOLATILE; """) # 2. 创建所有表结构 # ... ``` 在 `downgrade()` 函数结尾自动删除: ```python def downgrade() -> None: """回滚数据库""" # 删除所有表... # 3. 删除 UUID v7 函数 op.execute("DROP FUNCTION IF EXISTS gen_uuid_v7()") ``` ### 4. 修复枚举值问题 修复了 `server/app/models/recharge/order.py` 中的索引定义: - **问题**: 索引条件中使用了枚举对象 `PaymentStatus.PENDING` - **修复**: 改为整数值 `1`(PENDING 的枚举值) - **原因**: Alembic autogenerate 无法将枚举对象渲染为 SQL 字面值 ```python # 修复前 Index('idx_recharge_orders_payment_status_pending', 'payment_status', postgresql_where=Column('payment_status') == PaymentStatus.PENDING) # 修复后 Index('idx_recharge_orders_payment_status_pending', 'payment_status', postgresql_where=Column('payment_status') == 1) # 1 = PENDING ``` ### 4. 修复枚举值问题 - ✅ 禁止外键约束(应用层验证) - ✅ 枚举类型使用 SMALLINT - ✅ UUID v7 主键 - ✅ 时间戳字段(created_at, updated_at, deleted_at) - ✅ 索引优化 ## 部署指南 ### 全新环境部署 ```bash # 1. 启动容器(自动执行迁移) ./start_docker.sh --clean --build ``` ⚠️ **注意**: - 脚本会自动检测首次部署并执行数据库迁移 - 迁移脚本会自动创建 UUID v7 函数和所有表 - 迁移成功后会创建标记文件 `.migration_initialized` 详见:[首次部署自动执行数据库迁移](./2026-01-27-auto-migration-on-first-deploy.md) ### 现有环境更新 如果你的数据库已经有表结构: ```bash # 标记为已应用最新迁移(不执行建表) docker exec jointo-server-app alembic stamp head # 验证 docker exec jointo-server-app alembic current ``` ## 验证结果 ### 检查迁移状态 ```bash $ docker exec jointo-server-app alembic current 3a3a2a1417de (head) ``` ### 检查表结构 ```bash $ docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\dt" List of relations Schema | Name | Type | Owner --------+-------------------------+-------+---------- public | ai_jobs | table | jointoAI public | ai_models | table | jointoAI public | ai_quotas | table | jointoAI public | ai_usage_logs | table | jointoAI public | alembic_version | table | jointoAI public | credit_consumption_logs | table | jointoAI public | credit_gifts | table | jointoAI public | credit_packages | table | jointoAI public | credit_pricing | table | jointoAI public | credit_transactions | table | jointoAI public | folder_members | table | jointoAI public | folders | table | jointoAI public | payment_callbacks | table | jointoAI public | project_members | table | jointoAI public | project_shares | table | jointoAI public | project_versions | table | jointoAI public | projects | table | jointoAI public | recharge_orders | table | jointoAI public | sms_verification_codes | table | jointoAI public | user_sessions | table | jointoAI public | users | table | jointoAI (21 rows) ``` ## 优势 ### 1. 全新环境支持 - ✅ 一键创建所有表结构 - ✅ 无需手动执行 SQL - ✅ 自动应用索引和约束 ### 2. 版本化管理 - ✅ 完整的迁移历史 - ✅ 支持 upgrade 和 downgrade - ✅ 自动依赖管理 ### 3. 团队协作 - ✅ 统一的数据库结构 - ✅ 可重复的部署流程 - ✅ 易于代码审查 ## 注意事项 ### 1. 现有环境 如果你的数据库已经有表结构,**不要执行 `alembic upgrade`**,而是使用 `alembic stamp head` 标记为已应用。 ### 2. 数据备份 在生产环境执行迁移前,务必备份数据库: ```bash docker exec jointo-server-postgres pg_dump -U jointoAI jointo > backup_$(date +%Y%m%d_%H%M%S).sql ``` ### 3. 迁移测试 在开发环境测试迁移的 upgrade 和 downgrade: ```bash # 测试升级 docker exec jointo-server-app alembic upgrade head # 测试回滚 docker exec jointo-server-app alembic downgrade base # 重新升级 docker exec jointo-server-app alembic upgrade head ``` ## 相关文档 - [Alembic 迁移指南](../guides/alembic-migration-guide.md) - [Alembic 迁移系统实施](./2026-01-27-alembic-migration-system.md) - [数据库设计规范](../../.claude/skills/jointo-tech-stack/references/database.md) ## 问题排查 ### 问题 1:表已存在 **症状**:执行 `alembic upgrade` 时报错 "relation already exists" **解决**:使用 `alembic stamp head` 标记为已应用 ### 问题 2:迁移版本不一致 **症状**:`alembic current` 显示旧版本或无版本 **解决**: ```bash # 查看当前版本 docker exec jointo-server-app alembic current # 标记为最新版本 docker exec jointo-server-app alembic stamp head ``` ### 问题 3:容器未运行 **症状**:命令执行失败 **解决**: ```bash # 启动容器 docker compose up -d # 检查容器状态 docker ps | grep jointo-server ``` ## 总结 完成了从标记式基线迁移到完整初始化迁移的转换,现在支持: - ✅ 全新环境一键部署 - ✅ 现有环境平滑升级 - ✅ 完整的版本化管理 - ✅ 符合 Jointo 技术栈规范