You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

6.7 KiB

数据库迁移重置 - 2026-02-03

类型: 重大变更
影响范围: 所有数据库表
执行人: 后端架构团队
状态: 🚧 进行中


变更概述

完全重置数据库迁移,基于最新的数据库设计文档重新创建所有表结构。

变更原因

  1. 规范统一: 统一 UUID v7 生成策略(应用层生成)
  2. 架构优化: 移除所有物理外键约束,应用层保证引用完整性
  3. 文档驱动: 基于 4 个服务的详细数据库设计文档重建
  4. 清理历史: 删除旧的迁移文件,从头开始

执行步骤

已完成

  1. 归档旧迁移文件

    • 移动到 server/alembic/versions/.archive_20260203/
    • 保留 11 个旧迁移文件作为历史记录
  2. 重置数据库

    • 终止所有数据库连接
    • 删除 jointo 数据库
    • 重新创建空数据库
  3. 配置基础设施

    • 创建 update_updated_at_column() 触发器函数
    • 启用 pg_trgm 扩展(全文搜索)
    • 删除错误的 UUID 生成函数(UUID v7 由应用层生成)
  4. 创建迁移文件骨架

    • 20260203_1113_0a70b74cfe69_create_user_service_tables.py
    • 20260203_1113_0384c0e5c609_create_resource_service_tables.py
    • 20260203_1113_9d636684e92f_create_ai_service_tables.py
    • 20260203_1113_1c1773449f65_create_project_service_tables.py

🚧 待完成

  1. 填充迁移文件内容

    根据以下文档填充建表语句:

    • User 服务(10 张表)

      • 参考:docs/requirements/backend/04-services/user/database-init.md
      • 表:users, user_sessions, sms_verification_codes, credit_transactions, credit_consumption_logs, credit_packages, credit_pricing, credit_gifts, recharge_orders, payment_callbacks
    • Resource 服务(2 张表)

      • 参考:docs/requirements/backend/04-services/resource/database-init.md
      • 表:file_checksums, attachments
    • AI 服务(7 张表)

      • 参考:docs/requirements/backend/04-services/ai/database-init.md
      • 表:ai_jobs, ai_models, ai_usage_logs, ai_quotas, ai_conversations, ai_conversation_messages, ai_prompts_system
    • Project 服务(16 张表)

      • 参考:docs/requirements/backend/04-services/project/database-init.md
      • 表:folders, folder_members, projects, project_members, project_shares, project_versions, screenplays, screenplay_versions, screenplay_characters, screenplay_locations, screenplay_props, screenplay_element_tags, storyboards, storyboard_items, storyboard_resources, project_resources
  2. 执行迁移

    docker exec jointo-server-app alembic upgrade head
    
  3. 验证表结构

    docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\dt"
    docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\d users"
    
  4. 更新文档

    • 更新 database-init-overview.md 的版本号
    • 创建本 Changelog

关键规范

UUID v7 生成

正确:应用层生成

from app.utils.id_generator import generate_uuid

class User(SQLModel, table=True):
    user_id: UUID = Field(
        sa_column=Column(
            PG_UUID(as_uuid=True),
            primary_key=True,
            default=generate_uuid  # 应用层生成
        )
    )

错误:数据库函数生成

-- 不要创建数据库 UUID 生成函数
CREATE FUNCTION generate_uuid() ...

时间戳字段

必须使用 TIMESTAMPTZ(ADR 006)

created_at TIMESTAMPTZ NOT NULL DEFAULT now()

枚举类型

使用 SMALLINT + IntEnum

role SMALLINT NOT NULL DEFAULT 3 CHECK (role IN (1, 2, 3))

外键约束

禁止物理外键,应用层验证

-- 只创建索引,不创建外键
CREATE INDEX idx_projects_owner_id ON projects(owner_id);

迁移文件模板

基本结构

"""create_xxx_service_tables

Revision ID: xxx
Revises: yyy
Create Date: 2026-02-03
"""
from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql

revision = 'xxx'
down_revision = 'yyy'  # 前一个迁移的 revision
branch_labels = None
depends_on = None

def upgrade() -> None:
    """升级:创建表"""
    # 1. 创建表
    op.create_table(
        'table_name',
        sa.Column('id', postgresql.UUID(as_uuid=True), primary_key=True),
        # ... 其他列
        sa.Column('created_at', postgresql.TIMESTAMP(timezone=True), 
                  nullable=False, server_default=sa.text('now()')),
        sa.Column('updated_at', postgresql.TIMESTAMP(timezone=True), 
                  nullable=False, server_default=sa.text('now()')),
    )
    
    # 2. 创建索引
    op.create_index('idx_table_column', 'table_name', ['column'])
    
    # 3. 添加注释
    op.execute("COMMENT ON TABLE table_name IS '表说明'")
    op.execute("COMMENT ON COLUMN table_name.id IS '主键说明'")
    
    # 4. 创建触发器
    op.execute("""
        CREATE TRIGGER update_table_name_updated_at
            BEFORE UPDATE ON table_name
            FOR EACH ROW
            EXECUTE FUNCTION update_updated_at_column()
    """)

def downgrade() -> None:
    """降级:删除表"""
    op.drop_table('table_name')

验证清单

迁移执行后,验证以下内容:

  • 所有表已创建(37 张表)
  • 所有索引已创建
  • 所有触发器已创建
  • 所有注释已添加
  • 无物理外键约束
  • 所有时间字段使用 TIMESTAMPTZ
  • 所有枚举字段使用 SMALLINT
  • UUID 主键无 server_default

相关文档


下一步行动

当前状态: 迁移文件骨架已创建,等待填充内容

建议

  1. 逐个服务填充迁移文件(User → Resource → AI → Project)
  2. 每个服务填充完成后,单独测试迁移
  3. 全部完成后,执行完整迁移并验证

预计工作量: 2-3 小时(手动编写 37 张表的建表语句)


文档状态: 🚧 进行中
最后更新: 2026-02-03 11:13
负责人: 后端架构团队