228 lines
7.1 KiB
TypeScript
Executable File
228 lines
7.1 KiB
TypeScript
Executable File
// prisma/seed.ts
|
|
import { PrismaClient, UserRole, ContentStatus, ProficiencyLevel, ExerciseType } from '@prisma/client'
|
|
import { Pool } from 'pg'
|
|
import { PrismaPg } from '@prisma/adapter-pg'
|
|
|
|
const connectionString = process.env.DIRECT_URL
|
|
|
|
async function main() {
|
|
console.log('🌱 Starting seed...')
|
|
|
|
// 1. Setup the Adapter (Crucial for Prisma 7 + Serverless)
|
|
const pool = new Pool({ connectionString })
|
|
const adapter = new PrismaPg(pool)
|
|
const prisma = new PrismaClient({ adapter })
|
|
|
|
try {
|
|
// 2. Create a Teacher/Super Admin
|
|
const teacher = await prisma.profile.upsert({
|
|
where: { email: 'admin@acve.com' },
|
|
update: {},
|
|
create: {
|
|
email: 'admin@acve.com',
|
|
fullName: 'ACVE Admin',
|
|
// ✅ CORRECT: Uses the strict Enum value
|
|
role: UserRole.SUPER_ADMIN,
|
|
avatarUrl: 'https://github.com/shadcn.png',
|
|
},
|
|
})
|
|
console.log(`👤 Created User: ${teacher.email}`)
|
|
|
|
// 3. Create a Law Firm (B2B)
|
|
const lawFirm = await prisma.company.create({
|
|
data: {
|
|
name: 'García & Partners',
|
|
billingEmail: 'billing@garcia.com',
|
|
maxSeats: 10,
|
|
memberships: {
|
|
create: {
|
|
userId: teacher.id,
|
|
// ✅ FIXED: Use 'ORG_ADMIN' to match your UserRole terminology
|
|
// Since this field is a String in schema, we use the string value explicitly.
|
|
role: 'ORG_ADMIN',
|
|
},
|
|
},
|
|
},
|
|
})
|
|
console.log(`🏢 Created Law Firm: ${lawFirm.name}`)
|
|
|
|
// 4. Create the Bilingual Course (Contract Law)
|
|
const course = await prisma.course.create({
|
|
data: {
|
|
title: {
|
|
en: "Legal English: Contract Basics",
|
|
es: "Inglés Jurídico: Fundamentos de Contratos"
|
|
},
|
|
slug: "contract-law-101",
|
|
description: {
|
|
en: "Master the terminology of international contracts.",
|
|
es: "Domina la terminología de contratos internacionales."
|
|
},
|
|
level: ProficiencyLevel.INTERMEDIATE,
|
|
status: ContentStatus.PUBLISHED,
|
|
price: 499.00,
|
|
authorId: teacher.id,
|
|
tags: ["contracts", "civil law", "compliance"],
|
|
|
|
modules: {
|
|
create: {
|
|
title: { en: "Module 1: Offer and Acceptance", es: "Módulo 1: Oferta y Aceptación" },
|
|
orderIndex: 1,
|
|
lessons: {
|
|
create: {
|
|
title: { en: "The Elements of a Contract", es: "Los Elementos de un Contrato" },
|
|
slug: "elements-of-contract",
|
|
orderIndex: 1,
|
|
estimatedDuration: 600,
|
|
isFreePreview: true,
|
|
exercises: {
|
|
create: {
|
|
type: ExerciseType.MULTIPLE_CHOICE,
|
|
orderIndex: 1,
|
|
content: {
|
|
question: "What is 'Consideration' in a contract?",
|
|
options: ["Payment", "Thoughtfulness", "A value exchange", "A signature"],
|
|
correctAnswer: "A value exchange"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
})
|
|
console.log(`📚 Created Course: ${course.slug}`)
|
|
|
|
const miniGames = [
|
|
{
|
|
slug: "translation",
|
|
title: "Legal Translation Challenge",
|
|
description: "Translate legal terms accurately in context.",
|
|
difficulty: "BEGINNER",
|
|
questions: [
|
|
{
|
|
prompt: "Spanish term: incumplimiento contractual",
|
|
choices: ["Contractual compliance", "Breach of contract", "Contract interpretation", "Mutual assent"],
|
|
answerIndex: 1,
|
|
},
|
|
{
|
|
prompt: "Spanish term: medida cautelar",
|
|
choices: ["Class action", "Summary judgment", "Injunctive relief", "Arbitration clause"],
|
|
answerIndex: 2,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: "term-matching",
|
|
title: "Term Matching Game",
|
|
description: "Match legal terms with accurate definitions.",
|
|
difficulty: "INTERMEDIATE",
|
|
questions: [
|
|
{
|
|
prompt: "Match: consideration",
|
|
choices: [
|
|
"A legally binding command from the court",
|
|
"A bargained-for exchange of value between parties",
|
|
"A prior case that has no legal effect",
|
|
"A statement made outside of court",
|
|
],
|
|
answerIndex: 1,
|
|
},
|
|
{
|
|
prompt: "Match: injunction",
|
|
choices: [
|
|
"A court order requiring a party to do or stop doing something",
|
|
"A clause that sets venue for disputes",
|
|
"A witness statement under oath",
|
|
"A mandatory arbitration waiver",
|
|
],
|
|
answerIndex: 0,
|
|
},
|
|
],
|
|
},
|
|
{
|
|
slug: "contract-clauses",
|
|
title: "Contract Clause Practice",
|
|
description: "Pick the best clause drafting option for each scenario.",
|
|
difficulty: "ADVANCED",
|
|
questions: [
|
|
{
|
|
prompt: "Choose the strongest force majeure clause element:",
|
|
choices: [
|
|
"No definition of triggering events",
|
|
"Broad reference without notice obligations",
|
|
"Defined events, notice timeline, and mitigation duty",
|
|
"Automatic termination without limits",
|
|
],
|
|
answerIndex: 2,
|
|
},
|
|
{
|
|
prompt: "Best limitation of liability drafting choice:",
|
|
choices: [
|
|
"Exclude all damages including willful misconduct",
|
|
"Cap liability with carve-outs for fraud and gross negligence",
|
|
"No cap and no exclusions",
|
|
"Cap liability only for one party",
|
|
],
|
|
answerIndex: 1,
|
|
},
|
|
],
|
|
},
|
|
]
|
|
|
|
const prismaAny = prisma as unknown as {
|
|
miniGame: {
|
|
upsert: (args: object) => Promise<{ id: string }>
|
|
}
|
|
miniGameQuestion: {
|
|
deleteMany: (args: object) => Promise<unknown>
|
|
createMany: (args: object) => Promise<unknown>
|
|
}
|
|
}
|
|
for (const game of miniGames) {
|
|
const saved = await prismaAny.miniGame.upsert({
|
|
where: { slug: game.slug },
|
|
update: {
|
|
title: game.title,
|
|
description: game.description,
|
|
difficulty: game.difficulty,
|
|
isActive: true,
|
|
},
|
|
create: {
|
|
slug: game.slug,
|
|
title: game.title,
|
|
description: game.description,
|
|
difficulty: game.difficulty,
|
|
isActive: true,
|
|
},
|
|
})
|
|
|
|
await prismaAny.miniGameQuestion.deleteMany({
|
|
where: { miniGameId: saved.id },
|
|
})
|
|
|
|
await prismaAny.miniGameQuestion.createMany({
|
|
data: game.questions.map((q, index) => ({
|
|
miniGameId: saved.id,
|
|
prompt: q.prompt,
|
|
choices: q.choices,
|
|
answerIndex: q.answerIndex,
|
|
orderIndex: index,
|
|
})),
|
|
})
|
|
}
|
|
console.log(`🧩 Seeded ${miniGames.length} mini-games`)
|
|
|
|
console.log('✅ Seed complete!')
|
|
|
|
} catch (e) {
|
|
console.error(e)
|
|
process.exit(1)
|
|
} finally {
|
|
await prisma.$disconnect()
|
|
}
|
|
}
|
|
|
|
main()
|