Initial commit: FL-Akademie LMS mit Docker, Admin, Portal und Dokumentation.

Made-with: Cursor
This commit is contained in:
lo
2026-04-13 23:17:07 +02:00
commit d3367f0046
66 changed files with 3641 additions and 0 deletions

203
prisma/seed.ts Normal file
View File

@@ -0,0 +1,203 @@
import { PrismaClient, BillingInterval, Role } from "@prisma/client";
import bcrypt from "bcryptjs";
import { defaultLandingContent } from "../lib/landing";
const prisma = new PrismaClient();
async function main() {
const passwordHash = await bcrypt.hash("devpassword", 10);
const admin = await prisma.user.upsert({
where: { email: "admin@akademie.local" },
update: {},
create: {
email: "admin@akademie.local",
name: "MatzeFix",
passwordHash,
role: Role.ADMIN,
},
});
const instructor = await prisma.user.upsert({
where: { email: "matze@akademie.local" },
update: {},
create: {
email: "matze@akademie.local",
name: "MatzeFix",
passwordHash,
role: Role.INSTRUCTOR,
},
});
const learner = await prisma.user.upsert({
where: { email: "lernender@akademie.local" },
update: {},
create: {
email: "lernender@akademie.local",
name: "Demo Lernender",
passwordHash,
role: Role.LEARNER,
},
});
const catKostenlos = await prisma.category.upsert({
where: { slug: "kostenlos" },
update: {},
create: { slug: "kostenlos", name: "kostenlos" },
});
const catModul1 = await prisma.category.upsert({
where: { slug: "modul-1" },
update: {},
create: { slug: "modul-1", name: "Modul 1" },
});
const catUebung = await prisma.category.upsert({
where: { slug: "uebung-der-woche" },
update: {},
create: { slug: "uebung-der-woche", name: "Übung der Woche" },
});
const courseSlug = "modul-1-die-fahrschule";
let course = await prisma.course.findUnique({ where: { slug: courseSlug } });
if (!course) {
course = await prisma.course.create({
data: {
slug: courseSlug,
title: "Modul 1 Die Fahrschule",
description:
"Von der Fahrschulauswahl bis zu den ersten Übungen strukturiert und praxisnah.",
published: true,
priceCents: 0,
billingInterval: BillingInterval.NONE,
ratingAverage: 4.8,
ratingCount: 12,
authorId: instructor.id,
authorName: "MatzeFix",
categories: {
create: [
{ categoryId: catKostenlos.id },
{ categoryId: catModul1.id },
],
},
modules: {
create: [
{
title: "Einstieg",
sortOrder: 0,
lessons: {
create: [
{
slug: "wie-waehle-ich-die-richtige-fahrschule-aus",
title: "Wie wähle ich die richtige Fahrschule aus?",
sortOrder: 0,
contentHtml: `
<p>Die Wahl der Fahrschule prägt deinen gesamten Lernweg. Achte auf:</p>
<ul>
<li>Kommunikation und Transparenz bei Kosten</li>
<li>Motorrad-spezifische Erfahrung der Trainer</li>
<li>Übungsflächen und realistische Sonderfahrten</li>
</ul>
`,
},
{
slug: "ausruestung-und-erste-schritte",
title: "Ausrüstung und erste Schritte",
sortOrder: 1,
contentHtml:
"<p>Helm, Handschuhe, Protektoren passend zur Jahreszeit und zum Übungsplatz.</p>",
},
],
},
},
{
title: "Grundlagen auf dem Platz",
sortOrder: 1,
lessons: {
create: [
{
slug: "langsames-fahren-und-balance",
title: "Langsames Fahren und Balance",
sortOrder: 0,
contentHtml:
"<p>Übe Schrittgeschwindigkeit, Kupplungsfeinfühlen und Blickführung.</p>",
},
],
},
},
],
},
},
});
}
const demoPaidSlug = "demo-ubung-der-woche";
let paid = await prisma.course.findUnique({ where: { slug: demoPaidSlug } });
if (!paid) {
paid = await prisma.course.create({
data: {
slug: demoPaidSlug,
title: "Demo Übung der Woche",
description: "Beispiel für wiederkehrende Inhalte (Preisfeld für späteres Abo).",
published: true,
priceCents: 2396,
billingInterval: BillingInterval.QUARTER,
ratingAverage: 4,
ratingCount: 1,
authorId: instructor.id,
authorName: "MatzeFix",
categories: {
create: [
{ categoryId: catKostenlos.id },
{ categoryId: catUebung.id },
],
},
modules: {
create: [
{
title: "Woche 1",
sortOrder: 0,
lessons: {
create: [
{
slug: "uebung-saubere-blickfuehrung",
title: "Übung: Saubere Blickführung",
sortOrder: 0,
contentHtml:
"<p>Blick früh in die Kurve, Kurveneinlage planen, ruhige Handgelenke.</p>",
},
],
},
},
],
},
},
});
}
await prisma.enrollment.upsert({
where: {
userId_courseId: { userId: learner.id, courseId: course.id },
},
update: {},
create: { userId: learner.id, courseId: course.id },
});
await prisma.landingPage.upsert({
where: { id: "default" },
update: {},
create: {
id: "default",
content: defaultLandingContent() as object,
},
});
console.log("Seed OK:", { admin: admin.email, learner: learner.email });
}
main()
.then(() => prisma.$disconnect())
.catch(async (e) => {
console.error(e);
await prisma.$disconnect();
process.exit(1);
});