# AI Prompt System 唯一约束修复 **日期**: 2026-02-04 **类型**: Bug Fix **影响范围**: 数据库迁移、测试 ## 问题描述 在运行 AI Prompt System 测试时发现数据库缺少 `name + version` 唯一约束,导致 `test_create_duplicate_name_version` 测试失败。 检查发现迁移文件 `20260203_1521_9a6a8471bda0` 中 upgrade 和 downgrade 函数的操作反了: - upgrade() 删除了约束(应该是创建) - downgrade() 创建了约束(应该是删除) ## 解决方案 ### 1. 创建新迁移文件 创建迁移文件 `20260204_1626_410fc8822148_add_ai_prompts_system_name_version_unique_constraint.py`: ```python def upgrade() -> None: """升级数据库 - 添加 name+version 唯一约束""" op.create_unique_constraint( 'ai_prompts_system_name_version_unique', 'ai_prompts_system', ['name', 'version'] ) def downgrade() -> None: """回滚数据库 - 删除 name+version 唯一约束""" op.drop_constraint( 'ai_prompts_system_name_version_unique', 'ai_prompts_system', type_='unique' ) ``` ### 2. 清理重复数据 在运行迁移前,清理数据库中的重复数据: ```sql -- 删除重复记录,保留最早创建的 DELETE FROM ai_prompts_system a USING ai_prompts_system b WHERE a.prompt_id > b.prompt_id AND a.name = b.name AND a.version = b.version; ``` 删除了 26 条重复记录。 ### 3. 运行迁移 ```bash docker exec jointo-server-app alembic upgrade head ``` ### 4. 验证约束 ```sql SELECT conname, contype FROM pg_constraint WHERE conrelid = 'ai_prompts_system'::regclass; ``` 结果: ``` conname | contype ---------------------------------------+--------- ai_prompts_system_name_version_unique | u -- ✅ 唯一约束 ai_prompts_system_pkey | p -- 主键 ai_prompts_system_prompt_type_check | c -- 检查约束 ``` ## 测试结果 运行 Repository 测试: ```bash docker exec jointo-server-app pytest tests/unit/repositories/test_ai_prompt_system_repository.py -v ``` **结果**: ✅ 21 passed 所有测试通过,包括: - `test_create_duplicate_name_version` - 验证唯一约束正常工作 - 其他 20 个测试 - 验证基本功能正常 ## 影响 ### 数据完整性 - ✅ 保证同一名称和版本的提示词只能存在一个 - ✅ 防止数据重复 - ✅ 符合需求文档设计 ### 测试 - ✅ 所有 Repository 测试通过 - ✅ 唯一约束测试正常工作 ## 相关文件 **迁移文件**: - `server/alembic/versions/20260204_1626_410fc8822148_add_ai_prompts_system_name_version_.py` **测试文件**: - `server/tests/unit/repositories/test_ai_prompt_system_repository.py` ## 技术细节 ### 约束定义 ```sql ALTER TABLE ai_prompts_system ADD CONSTRAINT ai_prompts_system_name_version_unique UNIQUE (name, version); ``` ### 约束作用 - 同一个提示词名称可以有多个版本 - 但同一名称+版本的组合只能存在一次 - 例如: - ✅ 允许:("剧本提示词", "1.0.0") 和 ("剧本提示词", "1.1.0") - ❌ 禁止:两个 ("剧本提示词", "1.0.0") ## 后续建议 1. **审查旧迁移文件**: 检查 `20260203_1521_9a6a8471bda0` 是否需要修复(虽然新迁移已解决问题) 2. **测试数据清理**: 确保测试使用唯一的测试数据名称,避免冲突 3. **迁移审查流程**: 建立迁移文件审查机制,防止类似错误 ## 符合规范 - ✅ UUID v7 主键(应用层生成) - ✅ SMALLINT 枚举类型 - ✅ TIMESTAMPTZ 时间字段 - ✅ 无物理外键约束(应用层保证引用完整性) - ✅ 唯一约束(数据库层保证数据完整性)