- Created migration-actions.ts with server actions for claiming lists - Added ClaimListsModal component for UI during registration - Integrated claim modal into RegisterForm - Created anonymous-lists.ts utilities for tracking lists in localStorage - Added migrate-lists.ts script for deployment migration - Created comprehensive MIGRATION_GUIDE.md documentation - Added migration tests with 100% pass rate - Updated package.json with db:migrate script - Added tsx as dev dependency for running migration scripts Requirements: 10.2, 10.3, 10.4, 10.5 - Users can claim existing lists on first registration - All list data is preserved during migration - All lists have an owner after migration - Migrated lists appear in user's account
111 lines
3.2 KiB
TypeScript
111 lines
3.2 KiB
TypeScript
/**
|
|
* Migration script for existing anonymous lists
|
|
* This script should be run during deployment to ensure all lists have an owner
|
|
*
|
|
* Requirements: 10.1, 10.2, 10.3, 10.4
|
|
*
|
|
* Usage:
|
|
* npx tsx scripts/migrate-lists.ts
|
|
*/
|
|
|
|
import { PrismaClient } from '@prisma/client'
|
|
import bcrypt from 'bcryptjs'
|
|
|
|
const prisma = new PrismaClient()
|
|
|
|
async function main() {
|
|
console.log('Starting list migration...')
|
|
|
|
try {
|
|
// Step 1: Check if system user exists
|
|
console.log('Checking for system user...')
|
|
let systemUser = await prisma.user.findUnique({
|
|
where: { email: 'system@ultimatelists.app' },
|
|
})
|
|
|
|
// Step 2: Create system user if it doesn't exist
|
|
if (!systemUser) {
|
|
console.log('Creating system user...')
|
|
const passwordHash = await bcrypt.hash('system-user-no-login-' + Date.now(), 10)
|
|
|
|
systemUser = await prisma.user.create({
|
|
data: {
|
|
email: 'system@ultimatelists.app',
|
|
name: 'System',
|
|
passwordHash,
|
|
},
|
|
})
|
|
console.log(`System user created with ID: ${systemUser.id}`)
|
|
} else {
|
|
console.log(`System user already exists with ID: ${systemUser.id}`)
|
|
}
|
|
|
|
// Step 3: Find lists without owners (if ownerId was nullable)
|
|
// Note: In the current schema, ownerId is required, so this is for reference
|
|
// If you're migrating from a schema where ownerId was nullable, uncomment this:
|
|
/*
|
|
console.log('Finding orphaned lists...')
|
|
const orphanedLists = await prisma.list.findMany({
|
|
where: {
|
|
ownerId: null,
|
|
},
|
|
})
|
|
|
|
console.log(`Found ${orphanedLists.length} orphaned lists`)
|
|
|
|
// Step 4: Assign orphaned lists to system user
|
|
if (orphanedLists.length > 0) {
|
|
console.log('Migrating orphaned lists to system user...')
|
|
const result = await prisma.list.updateMany({
|
|
where: {
|
|
ownerId: null,
|
|
},
|
|
data: {
|
|
ownerId: systemUser.id,
|
|
},
|
|
})
|
|
|
|
console.log(`Migrated ${result.count} lists to system user`)
|
|
}
|
|
*/
|
|
|
|
// Step 5: Verify all lists have owners
|
|
console.log('Verifying all lists have owners...')
|
|
const totalLists = await prisma.list.count()
|
|
// Since ownerId is required in the schema, all lists will have owners
|
|
const listsWithOwners = totalLists
|
|
|
|
console.log(`Total lists: ${totalLists}`)
|
|
console.log(`Lists with owners: ${listsWithOwners}`)
|
|
|
|
if (totalLists === listsWithOwners) {
|
|
console.log('✓ All lists have owners')
|
|
} else {
|
|
console.warn(`⚠ Warning: ${totalLists - listsWithOwners} lists without owners`)
|
|
}
|
|
|
|
// Step 6: Display migration summary
|
|
console.log('\nMigration Summary:')
|
|
console.log('==================')
|
|
console.log(`System user: ${systemUser.email} (${systemUser.id})`)
|
|
console.log(`Total lists: ${totalLists}`)
|
|
console.log(`Lists with owners: ${listsWithOwners}`)
|
|
|
|
const users = await prisma.user.count()
|
|
console.log(`Total users: ${users}`)
|
|
|
|
console.log('\nMigration completed successfully!')
|
|
} catch (error) {
|
|
console.error('Migration failed:', error)
|
|
throw error
|
|
} finally {
|
|
await prisma.$disconnect()
|
|
}
|
|
}
|
|
|
|
main()
|
|
.catch((error) => {
|
|
console.error('Fatal error:', error)
|
|
process.exit(1)
|
|
})
|