148 lines
3.8 KiB
Markdown
148 lines
3.8 KiB
Markdown
# 部署修复说明
|
||
|
||
## 问题解决
|
||
|
||
已修复在推送到现有环境时遇到的外键约束错误:
|
||
|
||
```
|
||
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');
|
||
```
|