Prmbr/docs/deployment-fix.md
2025-08-05 23:42:48 +08:00

3.8 KiB
Raw Blame History

部署修复说明

问题解决

已修复在推送到现有环境时遇到的外键约束错误:

Error: insert or update on table "users" violates foreign key constraint "users_subscriptionPlanId_fkey"

解决方案

通过修改种子脚本 (prisma/seed.ts),确保在数据库推送时:

  1. 创建必需的套餐:使用 upsert 确保 'free' 和 'pro' 套餐存在
  2. 修复用户数据:自动修复无效的套餐引用
  3. 验证数据完整性:确保所有用户都有有效的套餐关联

使用方法

现在可以直接使用现有命令进行部署:

npm run db:push

这个命令会:

  1. 推送数据库架构 (prisma db push)
  2. 运行种子脚本 (npm run db:seed)
  3. 自动处理数据修复

种子脚本改进

主要变更

  1. 使用 upsert 而不是 create

    // 之前:如果套餐存在就跳过
    if (existingPlans > 0) return
    
    // 现在:确保必需套餐存在
    await prisma.subscriptionPlan.upsert({
      where: { id: 'free' },
      update: { name: 'free', isActive: true },
      create: { /* 完整套餐数据 */ }
    })
    
  2. 智能用户数据修复

    // 检查所有用户的套餐引用
    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. 本地测试

    npm run db:push
    npm run build
    
  2. 生产部署

    npm run db:push
    npm start
    

优势

  1. 无需额外脚本:使用现有的 npm run db:push 命令
  2. 自动修复:种子脚本自动处理数据不一致问题
  3. 向后兼容:不会破坏现有数据
  4. 幂等操作:可以重复运行而不会出错

注意事项

  1. Stripe 配置:部署后需要设置 Pro 套餐的 Stripe 价格 ID

    UPDATE subscription_plans 
    SET "stripePriceId" = 'price_your_stripe_price_id' 
    WHERE name = 'pro';
    
  2. 数据验证:部署后验证定价页面和订阅功能

  3. 备份建议:在生产环境部署前建议备份数据库

故障排除

如果仍然遇到问题:

  1. 检查套餐

    SELECT id, name, "isActive" FROM subscription_plans;
    
  2. 检查用户

    SELECT "subscribePlan", COUNT(*) FROM users GROUP BY "subscribePlan";
    
  3. 手动修复

    UPDATE users SET "subscribePlan" = 'free' 
    WHERE "subscribePlan" NOT IN ('free', 'pro');