# 部署修复说明 ## 问题解决 已修复在推送到现有环境时遇到的外键约束错误: ``` Error: insert or update on table "users" violates foreign key constraint "users_subscriptionPlanId_fkey" ``` ## 解决方案 通过修改种子脚本 (`prisma/seed.ts`),确保在数据库推送时: 1. **创建必需的套餐**:使用 `upsert` 确保 'free' 和 'pro' 套餐存在 2. **修复用户数据**:自动修复无效的套餐引用 3. **验证数据完整性**:确保所有用户都有有效的套餐关联 ## 使用方法 现在可以直接使用现有命令进行部署: ```bash npm run db:push ``` 这个命令会: 1. 推送数据库架构 (`prisma db push`) 2. 运行种子脚本 (`npm run db:seed`) 3. 自动处理数据修复 ## 种子脚本改进 ### 主要变更 1. **使用 upsert 而不是 create** ```typescript // 之前:如果套餐存在就跳过 if (existingPlans > 0) return // 现在:确保必需套餐存在 await prisma.subscriptionPlan.upsert({ where: { id: 'free' }, update: { name: 'free', isActive: true }, create: { /* 完整套餐数据 */ } }) ``` 2. **智能用户数据修复** ```typescript // 检查所有用户的套餐引用 const validPlanIds = ['free', 'pro'] const usersToUpdate = users.filter(user => { const hasValidSubscribePlan = validPlanIds.includes(user.subscribePlan) const hasValidSubscriptionPlanId = validPlanIds.includes(user.subscriptionPlanId) return !hasValidSubscribePlan || !hasValidSubscriptionPlanId }) // 修复无效引用 for (const user of usersToUpdate) { await prisma.user.update({ where: { id: user.id }, data: { subscribePlan: validPlanIds.includes(user.subscribePlan) ? user.subscribePlan : 'free', subscriptionPlanId: validPlanIds.includes(user.subscribePlan) ? user.subscribePlan : 'free' } }) } ``` ### 执行流程 1. **创建/更新套餐**:确保 'free' 和 'pro' 套餐存在 2. **检查用户数据**:找出有无效套餐引用的用户 3. **修复用户数据**:将无效引用改为 'free' 4. **验证结果**:确认所有数据都是一致的 ## 测试验证 种子脚本运行结果: ``` 🌱 Starting database seeding... 📦 Ensuring essential subscription plans exist... ✅ Created subscription plan: Free Plan ✅ Created subscription plan: Pro Plan 👥 Updating existing users... 👥 No users need subscription plan updates 📊 Seeding completed: • 2 subscription plans created • 2 users have valid plan associations 🎉 Database seeding finished successfully! ``` ## 部署到现有环境 现在可以安全地部署到任何现有环境: 1. **本地测试**: ```bash npm run db:push npm run build ``` 2. **生产部署**: ```bash npm run db:push npm start ``` ## 优势 1. **无需额外脚本**:使用现有的 `npm run db:push` 命令 2. **自动修复**:种子脚本自动处理数据不一致问题 3. **向后兼容**:不会破坏现有数据 4. **幂等操作**:可以重复运行而不会出错 ## 注意事项 1. **Stripe 配置**:部署后需要设置 Pro 套餐的 Stripe 价格 ID ```sql UPDATE subscription_plans SET "stripePriceId" = 'price_your_stripe_price_id' WHERE name = 'pro'; ``` 2. **数据验证**:部署后验证定价页面和订阅功能 3. **备份建议**:在生产环境部署前建议备份数据库 ## 故障排除 如果仍然遇到问题: 1. **检查套餐**: ```sql SELECT id, name, "isActive" FROM subscription_plans; ``` 2. **检查用户**: ```sql SELECT "subscribePlan", COUNT(*) FROM users GROUP BY "subscribePlan"; ``` 3. **手动修复**: ```sql UPDATE users SET "subscribePlan" = 'free' WHERE "subscribePlan" NOT IN ('free', 'pro'); ```