fix: align learn schema with existing LearnCourse/LearnModule models
- Remove duplicate Course/Module models (GitHub main already has LearnCourse/LearnModule) - Add seed-learn.json with Daily Fiqh for Beginners (5 modules) - Add seed-learn.js using prisma.learnCourse / prisma.learnModule - Seed includes quizData, keyTakeaway, duration, giteaPath - Matches existing API routes: /api/learn/courses, /api/learn/tts, /api/learn/progress TODO: - Add markdown content to modules (currently content field is null) - Generate TTS audio files for listen toggle - Add intermediate/advanced courses
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Seed script for micro-learning courses.
|
||||
* Reads prisma/seed-learn.json and creates LearnCourse/LearnModule records.
|
||||
*
|
||||
* Run:
|
||||
* npx prisma db push
|
||||
* node prisma/seed-learn.js
|
||||
*/
|
||||
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
const seedPath = path.join(__dirname, 'seed-learn.json');
|
||||
const raw = fs.readFileSync(seedPath, 'utf-8');
|
||||
const data = JSON.parse(raw);
|
||||
|
||||
console.log(`Seeding ${data.courses.length} course(s)...`);
|
||||
|
||||
for (const course of data.courses) {
|
||||
const { modules, ...courseData } = course;
|
||||
|
||||
// Upsert course (match by slug)
|
||||
const upserted = await prisma.learnCourse.upsert({
|
||||
where: { slug: courseData.slug },
|
||||
update: {
|
||||
title: courseData.title,
|
||||
author: courseData.author,
|
||||
description: courseData.description,
|
||||
difficulty: courseData.difficulty,
|
||||
imageUrl: courseData.imageUrl,
|
||||
giteaPath: courseData.giteaPath,
|
||||
priceFlh: courseData.priceFlh,
|
||||
priceUsd: courseData.priceUsd,
|
||||
subscriptionOnly: courseData.subscriptionOnly,
|
||||
published: courseData.published,
|
||||
},
|
||||
create: {
|
||||
slug: courseData.slug,
|
||||
title: courseData.title,
|
||||
author: courseData.author,
|
||||
description: courseData.description,
|
||||
difficulty: courseData.difficulty,
|
||||
imageUrl: courseData.imageUrl,
|
||||
giteaPath: courseData.giteaPath,
|
||||
priceFlh: courseData.priceFlh,
|
||||
priceUsd: courseData.priceUsd,
|
||||
subscriptionOnly: courseData.subscriptionOnly,
|
||||
published: courseData.published,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(` Course: ${upserted.title} (${upserted.id})`);
|
||||
|
||||
// Delete old modules (clean re-seed for dev)
|
||||
await prisma.learnModule.deleteMany({ where: { courseId: upserted.id } });
|
||||
|
||||
// Create modules
|
||||
if (modules && modules.length > 0) {
|
||||
const totalMinutes = modules.reduce((sum, m) => sum + (m.duration || 5), 0);
|
||||
|
||||
for (const m of modules) {
|
||||
await prisma.learnModule.create({
|
||||
data: {
|
||||
courseId: upserted.id,
|
||||
order: m.order,
|
||||
title: m.title,
|
||||
slug: m.slug,
|
||||
keyTakeaway: m.keyTakeaway,
|
||||
duration: m.duration || 5,
|
||||
content: m.content || null,
|
||||
audioPath: m.audioPath || null,
|
||||
quizData:
|
||||
typeof m.quizData === 'string'
|
||||
? m.quizData
|
||||
: JSON.stringify(m.quizData || []),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Update course with derived fields
|
||||
await prisma.learnCourse.update({
|
||||
where: { id: upserted.id },
|
||||
data: {
|
||||
moduleCount: modules.length,
|
||||
totalMinutes,
|
||||
},
|
||||
});
|
||||
|
||||
console.log(` → ${modules.length} module(s) created (${totalMinutes} min total)`);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Seeding complete.');
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user