# Phase 3: 数据库迁移 - 删除 storyboard_resources 表 **日期**: 2026-02-10 **类型**: 数据库迁移 **影响范围**: PostgreSQL 数据库 ## 背景 根据 [ADR 04: 移除废弃的 storyboard_resources 表](../adrs/04-remove-storyboard-resources-table.md),在完成代码清理后,现在执行数据库迁移删除废弃的表。 ## 变更内容 ### 1. 创建迁移文件 **文件**: `server/alembic/versions/20260210_2059_bb1f354cdf48_drop_storyboard_resources_table.py` **Revision ID**: `bb1f354cdf48` **Parent Revision**: `20260210_1500` ### 2. 迁移脚本 #### upgrade() 函数 ```python def upgrade() -> None: """删除 storyboard_resources 表""" if table_exists('storyboard_resources'): # 删除表(会自动删除索引和约束) op.drop_table('storyboard_resources') print("✅ 已删除 storyboard_resources 表") else: print("⚠️ storyboard_resources 表不存在,跳过删除") ``` **特性**: - 检查表是否存在(幂等性) - 自动删除所有索引和约束 - 输出执行日志 #### downgrade() 函数 ```python def downgrade() -> None: """回滚:重新创建 storyboard_resources 表""" if not table_exists('storyboard_resources'): # 重新创建表 op.create_table( 'storyboard_resources', sa.Column('storyboard_resource_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('storyboard_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('project_resource_id', postgresql.UUID(as_uuid=True), nullable=False), sa.Column('resource_type', sa.SmallInteger(), nullable=False), sa.Column('display_order', sa.Integer(), nullable=False, server_default='0'), sa.Column('created_at', sa.TIMESTAMP(timezone=True), nullable=False, server_default=sa.text('now()')), sa.PrimaryKeyConstraint('storyboard_resource_id') ) # 创建索引 op.create_index('idx_storyboard_resources_storyboard_id', 'storyboard_resources', ['storyboard_id']) op.create_index('idx_storyboard_resources_project_resource_id', 'storyboard_resources', ['project_resource_id']) op.create_index('idx_storyboard_resources_type', 'storyboard_resources', ['resource_type']) # 创建唯一约束 op.create_unique_constraint( 'storyboard_resources_unique', 'storyboard_resources', ['storyboard_id', 'project_resource_id'] ) print("✅ 已重新创建 storyboard_resources 表") else: print("⚠️ storyboard_resources 表已存在,跳过创建") ``` **特性**: - 完整恢复表结构 - 恢复所有索引 - 恢复唯一约束 - 支持安全回滚 ### 3. 执行迁移 #### 3.1 回退到上一版本 ```bash docker exec jointo-server-app alembic downgrade -1 ``` **输出**: ``` Running downgrade bb1f354cdf48 -> 20260210_1500, drop_storyboard_resources_table ⚠️ storyboard_resources 表已存在,跳过创建 ``` #### 3.2 执行迁移 ```bash docker exec jointo-server-app alembic upgrade head ``` **输出**: ``` Running upgrade 20260210_1500 -> bb1f354cdf48, drop_storyboard_resources_table DROP TABLE storyboard_resources ✅ 已删除 storyboard_resources 表 ``` ### 4. 验证结果 #### 4.1 检查表是否存在 ```bash docker exec jointo-server-postgres psql -U jointoAI -d jointo -c "\dt storyboard_resources" ``` **结果**: ✅ `Did not find any relation named "storyboard_resources".` #### 4.2 检查 Alembic 版本 ```bash docker exec jointo-server-app alembic current ``` **结果**: ✅ `bb1f354cdf48 (head)` #### 4.3 运行测试 ```bash docker exec jointo-server-app pytest tests/unit/services/test_ai_conversation_service.py -v ``` **结果**: ✅ 全部通过(19 个测试) ## 数据库变更详情 ### 删除的表 **表名**: `storyboard_resources` **表结构**: ```sql CREATE TABLE storyboard_resources ( storyboard_resource_id UUID PRIMARY KEY, storyboard_id UUID NOT NULL, project_resource_id UUID NOT NULL, resource_type SMALLINT NOT NULL, display_order INTEGER NOT NULL DEFAULT 0, created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT now(), CONSTRAINT storyboard_resources_unique UNIQUE (storyboard_id, project_resource_id) ); ``` **删除的索引**: 1. `idx_storyboard_resources_storyboard_id` - 分镜ID索引 2. `idx_storyboard_resources_project_resource_id` - 资源ID索引 3. `idx_storyboard_resources_type` - 资源类型索引 **删除的约束**: 1. `storyboard_resources_unique` - 唯一约束(storyboard_id + project_resource_id) ### 保留的表 **相关表**(未受影响): - `storyboard_items` - 分镜元素关联表(替代方案) - `storyboards` - 分镜主表 - `project_resources` - 项目素材表 - `project_element_tags` - 项目元素标签表 ## 风险评估 ### 低风险 - ✅ 表已废弃,无业务逻辑依赖 - ✅ 代码已清理,无残留引用 - ✅ 有完整的回滚脚本 - ✅ 测试全部通过 ### 数据安全 - ✅ 表中无重要数据(已被 `storyboard_items` 替代) - ✅ 删除操作不影响其他表 - ✅ 支持完整回滚 ## 回滚方案 如需回滚,执行: ```bash docker exec jointo-server-app alembic downgrade -1 ``` **注意**: - 回滚会重新创建空表 - 不会恢复历史数据 - 需要同时回滚代码变更 ## 性能影响 ### 正面影响 - ✅ 减少数据库表数量 - ✅ 减少索引维护开销 - ✅ 简化数据库结构 ### 无影响 - ✅ 不影响查询性能(表已废弃) - ✅ 不影响写入性能(无业务写入) ## 下一步 继续执行 [ADR 04](../adrs/04-remove-storyboard-resources-table.md) 的后续阶段: ### Phase 4: 代码清理 - 重命名误导性方法 - 清理残留引用 - 更新文档 ### Phase 5: 前端适配 - 修改 API 服务层 - 修改类型定义 - 修改 UI 组件 - 更新 Mock 数据 ## 参考 - [ADR 04: 移除废弃的 storyboard_resources 表](../adrs/04-remove-storyboard-resources-table.md) - [Phase 1 Changelog](./2026-02-10-remove-storyboard-resources-table-phase1.md) - [Phase 2 Changelog](./2026-02-10-remove-storyboard-resources-table-phase2.md) - [Alembic 迁移文件](../../alembic/versions/20260210_2059_bb1f354cdf48_drop_storyboard_resources_table.py)