CognxSafeTrack
feat: implement inbound audio/image transcription, secure media proxy, and client-side bulk contact import
30d60ea | import { PrismaClient } from '@repo/database'; | |
| import { logger } from '../logger'; | |
| import * as dotenv from 'dotenv'; | |
| import * as path from 'path'; | |
| // Root .env contains the real Neon URL | |
| dotenv.config({ path: path.join(__dirname, '../../../../.env') }); | |
| const prisma = new PrismaClient(); | |
| async function migrate() { | |
| logger.info('π Starting JSON to SQL Migration (Neon)...'); | |
| // 1. Migrate Badges (UserProgress.badges -> UserBadge) | |
| const progressWithBadges = await prisma.userProgress.findMany({ | |
| where: { | |
| badges: { not: undefined } | |
| } | |
| }); | |
| logger.info(`Found ${progressWithBadges.length} UserProgress records with badges JSON.`); | |
| for (const progress of progressWithBadges) { | |
| const badges = progress.badges as any; | |
| if (Array.isArray(badges)) { | |
| for (const badgeName of badges) { | |
| if (typeof badgeName !== 'string') continue; | |
| const existing = await (prisma as any).userBadge.findFirst({ | |
| where: { | |
| userProgressId: progress.id, | |
| name: badgeName | |
| } | |
| }); | |
| if (!existing) { | |
| await (prisma as any).userBadge.create({ | |
| data: { | |
| userProgressId: progress.id, | |
| name: badgeName | |
| } | |
| }); | |
| logger.info(`Migrated badge "${badgeName}" for UserProgress ${progress.id}`); | |
| } | |
| } | |
| } | |
| } | |
| /* | |
| // 2. Migrate Team Members (BusinessProfile.teamMembers -> TeamMember) | |
| // DEPRECATED: Field removed from schema | |
| ... | |
| */ | |
| logger.info('β Neon data migration completed successfully!'); | |
| } | |
| migrate() | |
| .catch(err => { | |
| logger.error('β Migration failed:', err); | |
| process.exit(1); | |
| }) | |
| .finally(async () => { | |
| await prisma.$disconnect(); | |
| }); | |