836 lines
21 KiB
TypeScript
836 lines
21 KiB
TypeScript
import {
|
|
AbsenceReason,
|
|
InvitationStatus,
|
|
NotdienstAlertStatus,
|
|
NotdienstPlanStatus,
|
|
PrismaClient,
|
|
TerminStatus,
|
|
TerminType,
|
|
UserRole,
|
|
} from "@prisma/client";
|
|
import { hash } from "bcryptjs";
|
|
|
|
// =====================================================================
|
|
// Kita-Planer · Dev-Seed
|
|
// ---------------------------------------------------------------------
|
|
// Default: nicht destruktiv. Seed-Daten werden nur angelegt, wenn die DB
|
|
// noch keine Kita und keine User enthaelt.
|
|
//
|
|
// Reset: `npm run db:seed:reset` loescht gezielt die Demo-Daten und baut
|
|
// sie neu auf. Production wird nur mit ALLOW_DATABASE_SEED=true erlaubt.
|
|
// =====================================================================
|
|
|
|
const prisma = new PrismaClient();
|
|
|
|
const DEMO_KITA_SLUG = "waldameisen";
|
|
const DEFAULT_PASSWORD = "password123";
|
|
const PRIVACY_POLICY_VERSION = "2026-05-01";
|
|
const RESET_MODE = process.argv.includes("--reset");
|
|
|
|
const DEMO_USER_EMAILS = [
|
|
"super@kita-planer.local",
|
|
"admin@waldameisen.local",
|
|
"erzieher@waldameisen.local",
|
|
"mueller@waldameisen.local",
|
|
"schmidt@waldameisen.local",
|
|
"yilmaz@waldameisen.local",
|
|
"pending@waldameisen.local",
|
|
];
|
|
|
|
const DEMO_VERIFICATION_TOKENS = [
|
|
"demo-pending-parent-token",
|
|
"demo-invite-token",
|
|
];
|
|
|
|
type SeedContext = Awaited<ReturnType<typeof createDemoUsers>>;
|
|
|
|
function dateOnly(date: Date) {
|
|
return new Date(date.getFullYear(), date.getMonth(), date.getDate());
|
|
}
|
|
|
|
function addDays(date: Date, days: number) {
|
|
const next = new Date(date);
|
|
next.setDate(next.getDate() + days);
|
|
return dateOnly(next);
|
|
}
|
|
|
|
function addWeeks(date: Date, weeks: number) {
|
|
return addDays(date, weeks * 7);
|
|
}
|
|
|
|
function startOfIsoWeek(date: Date) {
|
|
const normalized = dateOnly(date);
|
|
const day = normalized.getDay() || 7;
|
|
return addDays(normalized, 1 - day);
|
|
}
|
|
|
|
function startOfMonth(date: Date) {
|
|
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
}
|
|
|
|
function getPreviousMonth(date: Date) {
|
|
return new Date(date.getFullYear(), date.getMonth() - 1, 1);
|
|
}
|
|
|
|
function getLastDayOfPreviousMonth(date: Date) {
|
|
return dateOnly(new Date(date.getFullYear(), date.getMonth(), 0));
|
|
}
|
|
|
|
function getTargetMonth(date: Date) {
|
|
return new Date(date.getFullYear(), date.getMonth() + 1, 1);
|
|
}
|
|
|
|
function getWorkingDays(year: number, month: number, limit?: number) {
|
|
const days: Date[] = [];
|
|
const cursor = new Date(year, month - 1, 1);
|
|
|
|
while (cursor.getMonth() === month - 1) {
|
|
const day = cursor.getDay();
|
|
if (day !== 0 && day !== 6) {
|
|
days.push(dateOnly(cursor));
|
|
}
|
|
cursor.setDate(cursor.getDate() + 1);
|
|
}
|
|
|
|
return typeof limit === "number" ? days.slice(0, limit) : days;
|
|
}
|
|
|
|
function isSeedAllowed() {
|
|
if (
|
|
process.env.NODE_ENV === "development" ||
|
|
process.env.ALLOW_DATABASE_SEED === "true"
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
console.log(
|
|
"Seed uebersprungen: NODE_ENV ist nicht development. Setze ALLOW_DATABASE_SEED=true, wenn das bewusst gewuenscht ist.",
|
|
);
|
|
return false;
|
|
}
|
|
|
|
async function isDatabaseEmpty() {
|
|
const [kitaCount, userCount] = await Promise.all([
|
|
prisma.kita.count(),
|
|
prisma.user.count(),
|
|
]);
|
|
|
|
return kitaCount === 0 && userCount === 0;
|
|
}
|
|
|
|
async function resetDemoData() {
|
|
const demoUsers = await prisma.user.findMany({
|
|
where: {
|
|
OR: [
|
|
{ email: { in: DEMO_USER_EMAILS } },
|
|
{ kita: { slug: DEMO_KITA_SLUG } },
|
|
],
|
|
},
|
|
select: { id: true },
|
|
});
|
|
|
|
await prisma.verificationToken.deleteMany({
|
|
where: {
|
|
OR: [
|
|
{ token: { in: DEMO_VERIFICATION_TOKENS } },
|
|
{ identifier: { in: demoUsers.map((user) => user.id) } },
|
|
],
|
|
},
|
|
});
|
|
|
|
await prisma.kita.deleteMany({ where: { slug: DEMO_KITA_SLUG } });
|
|
await prisma.user.deleteMany({ where: { email: { in: DEMO_USER_EMAILS } } });
|
|
}
|
|
|
|
async function createDemoUsers(passwordHash: string, consentAt: Date) {
|
|
const superAdmin = await prisma.user.create({
|
|
data: {
|
|
email: "super@kita-planer.local",
|
|
passwordHash,
|
|
firstName: "Sys",
|
|
lastName: "Admin",
|
|
role: UserRole.SUPERADMIN,
|
|
privacyPolicyAcceptedAt: consentAt,
|
|
privacyPolicyVersion: PRIVACY_POLICY_VERSION,
|
|
emailVerifiedAt: consentAt,
|
|
},
|
|
});
|
|
|
|
const kita = await prisma.kita.create({
|
|
data: {
|
|
name: "Waldameisen e.V.",
|
|
slug: DEMO_KITA_SLUG,
|
|
notdienstModuleEnabled: true,
|
|
terminModuleEnabled: true,
|
|
adressbuchModuleEnabled: true,
|
|
notdienstMinPerChildPerMonth: 2,
|
|
notdienstReminderDaysBefore: 7,
|
|
},
|
|
});
|
|
|
|
const familyMueller = await prisma.family.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
name: "Familie Mueller",
|
|
},
|
|
});
|
|
|
|
const familySchmidtYilmaz = await prisma.family.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
name: "Familie Schmidt-Yilmaz",
|
|
},
|
|
});
|
|
|
|
const familyFischer = await prisma.family.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
name: "Familie Fischer",
|
|
},
|
|
});
|
|
|
|
const admin = await prisma.user.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
email: "admin@waldameisen.local",
|
|
passwordHash,
|
|
firstName: "Anna",
|
|
lastName: "Vorstand",
|
|
role: UserRole.ADMIN,
|
|
privacyPolicyAcceptedAt: consentAt,
|
|
privacyPolicyVersion: PRIVACY_POLICY_VERSION,
|
|
directoryOptInAt: consentAt,
|
|
emailVerifiedAt: consentAt,
|
|
phone: "+49 30 1000 1000",
|
|
street: "Kitaweg 1",
|
|
postalCode: "10115",
|
|
city: "Berlin",
|
|
},
|
|
});
|
|
|
|
const erzieherUser = await prisma.user.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
email: "erzieher@waldameisen.local",
|
|
passwordHash,
|
|
firstName: "Eva",
|
|
lastName: "Erzieherin",
|
|
role: UserRole.ERZIEHER,
|
|
privacyPolicyAcceptedAt: consentAt,
|
|
privacyPolicyVersion: PRIVACY_POLICY_VERSION,
|
|
emailVerifiedAt: consentAt,
|
|
phone: "+49 30 1000 2000",
|
|
street: "Kitaweg 1",
|
|
postalCode: "10115",
|
|
city: "Berlin",
|
|
},
|
|
});
|
|
|
|
const koordinator = await prisma.user.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
familyId: familyMueller.id,
|
|
email: "mueller@waldameisen.local",
|
|
passwordHash,
|
|
firstName: "Maria",
|
|
lastName: "Mueller",
|
|
role: UserRole.KOORDINATOR,
|
|
privacyPolicyAcceptedAt: consentAt,
|
|
privacyPolicyVersion: PRIVACY_POLICY_VERSION,
|
|
directoryOptInAt: consentAt,
|
|
emailVerifiedAt: consentAt,
|
|
phone: "+49 30 1234 5678",
|
|
street: "Beispielweg 1",
|
|
postalCode: "10115",
|
|
city: "Berlin",
|
|
},
|
|
});
|
|
|
|
const elternSchmidt = await prisma.user.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
familyId: familySchmidtYilmaz.id,
|
|
email: "schmidt@waldameisen.local",
|
|
passwordHash,
|
|
firstName: "Lukas",
|
|
lastName: "Schmidt",
|
|
role: UserRole.ELTERN,
|
|
privacyPolicyAcceptedAt: consentAt,
|
|
privacyPolicyVersion: PRIVACY_POLICY_VERSION,
|
|
emailVerifiedAt: consentAt,
|
|
},
|
|
});
|
|
|
|
const elternYilmaz = await prisma.user.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
familyId: familySchmidtYilmaz.id,
|
|
email: "yilmaz@waldameisen.local",
|
|
passwordHash,
|
|
firstName: "Aylin",
|
|
lastName: "Yilmaz",
|
|
role: UserRole.ELTERN,
|
|
privacyPolicyAcceptedAt: consentAt,
|
|
privacyPolicyVersion: PRIVACY_POLICY_VERSION,
|
|
directoryOptInAt: consentAt,
|
|
emailVerifiedAt: consentAt,
|
|
phone: "+49 30 9876 5432",
|
|
street: "Parkstrasse 8",
|
|
postalCode: "10405",
|
|
city: "Berlin",
|
|
},
|
|
});
|
|
|
|
const pendingParent = await prisma.user.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
familyId: familyFischer.id,
|
|
email: "pending@waldameisen.local",
|
|
passwordHash: "",
|
|
firstName: "Lena",
|
|
lastName: "Fischer",
|
|
role: UserRole.ELTERN,
|
|
},
|
|
});
|
|
|
|
return {
|
|
kita,
|
|
familyMueller,
|
|
familySchmidtYilmaz,
|
|
familyFischer,
|
|
superAdmin,
|
|
admin,
|
|
erzieherUser,
|
|
koordinator,
|
|
elternSchmidt,
|
|
elternYilmaz,
|
|
pendingParent,
|
|
};
|
|
}
|
|
|
|
async function createChildren({
|
|
kita,
|
|
familyMueller,
|
|
familySchmidtYilmaz,
|
|
familyFischer,
|
|
}: SeedContext) {
|
|
const anna = await prisma.child.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
familyId: familyMueller.id,
|
|
firstName: "Anna",
|
|
lastName: "Mueller",
|
|
dateOfBirth: new Date("2021-03-15"),
|
|
},
|
|
});
|
|
|
|
const ben = await prisma.child.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
familyId: familyMueller.id,
|
|
firstName: "Ben",
|
|
lastName: "Mueller",
|
|
dateOfBirth: new Date("2023-07-22"),
|
|
notes: "Geschwisterkind von Anna.",
|
|
},
|
|
});
|
|
|
|
const clara = await prisma.child.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
familyId: familySchmidtYilmaz.id,
|
|
firstName: "Clara",
|
|
lastName: "Schmidt",
|
|
dateOfBirth: new Date("2022-11-03"),
|
|
},
|
|
});
|
|
|
|
const emil = await prisma.child.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
familyId: familySchmidtYilmaz.id,
|
|
firstName: "Emil",
|
|
lastName: "Yilmaz",
|
|
dateOfBirth: new Date("2021-09-09"),
|
|
},
|
|
});
|
|
|
|
const nina = await prisma.child.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
familyId: familyFischer.id,
|
|
firstName: "Nina",
|
|
lastName: "Fischer",
|
|
dateOfBirth: new Date("2022-05-30"),
|
|
},
|
|
});
|
|
|
|
return { anna, ben, clara, emil, nina };
|
|
}
|
|
|
|
async function createEducators(kitaId: string) {
|
|
const sabine = await prisma.educator.create({
|
|
data: { kitaId, firstName: "Sabine", lastName: "Schulze" },
|
|
});
|
|
const petra = await prisma.educator.create({
|
|
data: { kitaId, firstName: "Petra", lastName: "Klein" },
|
|
});
|
|
const jonas = await prisma.educator.create({
|
|
data: { kitaId, firstName: "Jonas", lastName: "Wagner" },
|
|
});
|
|
const norbert = await prisma.educator.create({
|
|
data: {
|
|
kitaId,
|
|
firstName: "Norbert",
|
|
lastName: "Altmann",
|
|
active: false,
|
|
},
|
|
});
|
|
|
|
return { sabine, petra, jonas, norbert };
|
|
}
|
|
|
|
async function createParentDuties({
|
|
kita,
|
|
koordinator,
|
|
elternSchmidt,
|
|
elternYilmaz,
|
|
}: SeedContext) {
|
|
const waesche = await prisma.parentDuty.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
name: "Waeschedienst",
|
|
description: "Kita-Waesche waschen und zurueckbringen.",
|
|
},
|
|
});
|
|
|
|
const einkauf = await prisma.parentDuty.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
name: "Einkauf",
|
|
description: "Woechentlicher Einkauf fuer die Kita-Kueche.",
|
|
},
|
|
});
|
|
|
|
const garten = await prisma.parentDuty.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
name: "Gartendienst",
|
|
description: "Aussenbereich pflegen und Spielmaterial pruefen.",
|
|
},
|
|
});
|
|
|
|
await prisma.parentDutyAssignment.createMany({
|
|
data: [
|
|
{ kitaId: kita.id, dutyId: waesche.id, userId: elternSchmidt.id },
|
|
{ kitaId: kita.id, dutyId: einkauf.id, userId: koordinator.id },
|
|
{ kitaId: kita.id, dutyId: garten.id, userId: elternYilmaz.id },
|
|
],
|
|
});
|
|
}
|
|
|
|
async function createAbsences(
|
|
{ kita }: SeedContext,
|
|
children: Awaited<ReturnType<typeof createChildren>>,
|
|
) {
|
|
const today = dateOnly(new Date());
|
|
|
|
await prisma.absence.createMany({
|
|
data: [
|
|
{
|
|
kitaId: kita.id,
|
|
childId: children.nina.id,
|
|
startDate: today,
|
|
endDate: today,
|
|
reason: AbsenceReason.ILLNESS,
|
|
note: "Fieber, bleibt heute zuhause.",
|
|
},
|
|
{
|
|
kitaId: kita.id,
|
|
childId: children.emil.id,
|
|
startDate: addDays(today, 1),
|
|
endDate: addDays(today, 2),
|
|
reason: AbsenceReason.VACATION,
|
|
note: "Familienbesuch.",
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
async function createDutyPlan({
|
|
kita,
|
|
familyMueller,
|
|
familySchmidtYilmaz,
|
|
familyFischer,
|
|
}: SeedContext) {
|
|
const waesche = await prisma.dutyType.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
name: "Waeschedienst",
|
|
description: "Woechentlicher Dienstplan fuer Kita-Waesche.",
|
|
},
|
|
});
|
|
|
|
const einkauf = await prisma.dutyType.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
name: "Einkauf",
|
|
description: "Woechentlicher Einkauf nach Kita-Liste.",
|
|
},
|
|
});
|
|
|
|
const families = [familyMueller, familySchmidtYilmaz, familyFischer];
|
|
const currentWeek = startOfIsoWeek(new Date());
|
|
|
|
await prisma.dutyAssignment.createMany({
|
|
data: Array.from({ length: 8 }).flatMap((_, index) => {
|
|
const startDate = addWeeks(currentWeek, index);
|
|
const endDate = addDays(startDate, 6);
|
|
return [
|
|
{
|
|
kitaId: kita.id,
|
|
dutyTypeId: waesche.id,
|
|
familyId: families[index % families.length].id,
|
|
startDate,
|
|
endDate,
|
|
},
|
|
{
|
|
kitaId: kita.id,
|
|
dutyTypeId: einkauf.id,
|
|
familyId: families[(index + 1) % families.length].id,
|
|
startDate,
|
|
endDate,
|
|
},
|
|
];
|
|
}),
|
|
});
|
|
}
|
|
|
|
async function createInvites({ kita, admin, pendingParent }: SeedContext) {
|
|
const expires = addDays(new Date(), 7);
|
|
|
|
await prisma.invitation.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
email: "invite@waldameisen.local",
|
|
role: UserRole.ELTERN,
|
|
token: "demo-invite-token",
|
|
status: InvitationStatus.PENDING,
|
|
expiresAt: expires,
|
|
invitedById: admin.id,
|
|
},
|
|
});
|
|
|
|
await prisma.verificationToken.create({
|
|
data: {
|
|
identifier: pendingParent.id,
|
|
token: "demo-pending-parent-token",
|
|
expires,
|
|
},
|
|
});
|
|
}
|
|
|
|
async function createAnnouncements({
|
|
kita,
|
|
admin,
|
|
koordinator,
|
|
}: SeedContext) {
|
|
const sommerfest = await prisma.announcement.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
title: "Sommerfest: Helferliste und Ablauf",
|
|
content:
|
|
"## Liebe Familien,\n\nunser Sommerfest findet naechsten Monat im Kita-Garten statt. Bitte merkt euch den Termin vor. Details zu Aufbau, Kuchen und Getraenken folgen ueber das Schwarze Brett.",
|
|
authorId: admin.id,
|
|
},
|
|
});
|
|
|
|
await prisma.announcement.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
title: "Neue Garderoben-Regelung",
|
|
content:
|
|
"Ab Montag bitten wir alle Familien, Wechselkleidung wieder in die beschrifteten Boxen zu legen. So bleibt der Morgen fuer Kinder und Team entspannter.",
|
|
authorId: admin.id,
|
|
},
|
|
});
|
|
|
|
await prisma.announcementRead.create({
|
|
data: {
|
|
userId: koordinator.id,
|
|
announcementId: sommerfest.id,
|
|
},
|
|
});
|
|
}
|
|
|
|
async function createTermine({
|
|
kita,
|
|
admin,
|
|
koordinator,
|
|
elternSchmidt,
|
|
elternYilmaz,
|
|
}: SeedContext) {
|
|
const now = new Date();
|
|
|
|
const elternabend = await prisma.termin.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
title: "Elternabend Fruehling",
|
|
description: "Austausch zu Terminen, Notdienst und Sommerplanung.",
|
|
type: TerminType.ELTERNABEND,
|
|
status: TerminStatus.CONFIRMED,
|
|
startDate: addDays(now, 10),
|
|
endDate: addDays(now, 10),
|
|
allDay: false,
|
|
mitbringselListEnabled: true,
|
|
createdById: admin.id,
|
|
approvedById: admin.id,
|
|
approvedAt: now,
|
|
},
|
|
});
|
|
|
|
await prisma.termin.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
title: "Teamtag",
|
|
description: "Die Kita bleibt wegen interner Fortbildung geschlossen.",
|
|
type: TerminType.TEAMTAG,
|
|
status: TerminStatus.CONFIRMED,
|
|
startDate: addDays(now, 18),
|
|
endDate: addDays(now, 18),
|
|
allDay: true,
|
|
createdById: admin.id,
|
|
approvedById: admin.id,
|
|
approvedAt: now,
|
|
},
|
|
});
|
|
|
|
await prisma.termin.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
title: "Elterncafe im Garten",
|
|
description: "Anfrage eines Elternteils, noch nicht bestaetigt.",
|
|
type: TerminType.ELTERNCAFE,
|
|
status: TerminStatus.PENDING,
|
|
startDate: addDays(now, 24),
|
|
endDate: addDays(now, 24),
|
|
allDay: false,
|
|
createdById: elternSchmidt.id,
|
|
},
|
|
});
|
|
|
|
await prisma.termin.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
title: "Spontaner Ausflug",
|
|
description: "Beispiel fuer eine abgelehnte Terminanfrage.",
|
|
type: TerminType.SONSTIGES,
|
|
status: TerminStatus.REJECTED,
|
|
startDate: addDays(now, -6),
|
|
endDate: addDays(now, -6),
|
|
allDay: true,
|
|
createdById: elternYilmaz.id,
|
|
approvedById: koordinator.id,
|
|
approvedAt: addDays(now, -5),
|
|
rejectionReason: "Zu kurzfristig fuer die Gruppe.",
|
|
},
|
|
});
|
|
|
|
await prisma.mitbringselItem.createMany({
|
|
data: [
|
|
{
|
|
kitaId: kita.id,
|
|
terminId: elternabend.id,
|
|
userId: koordinator.id,
|
|
content: "Obstplatte",
|
|
},
|
|
{
|
|
kitaId: kita.id,
|
|
terminId: elternabend.id,
|
|
userId: elternSchmidt.id,
|
|
content: "Brot und Aufstrich",
|
|
},
|
|
],
|
|
});
|
|
}
|
|
|
|
async function createNotdienstData(
|
|
{ kita, koordinator, elternSchmidt, elternYilmaz }: SeedContext,
|
|
children: Awaited<ReturnType<typeof createChildren>>,
|
|
educators: Awaited<ReturnType<typeof createEducators>>,
|
|
) {
|
|
const today = dateOnly(new Date());
|
|
const currentMonth = startOfMonth(today);
|
|
const previousMonth = getPreviousMonth(today);
|
|
const previousAssignmentDate = getLastDayOfPreviousMonth(today);
|
|
const targetMonth = getTargetMonth(today);
|
|
|
|
const availabilityPairs = [
|
|
{ childId: children.anna.id, userId: koordinator.id },
|
|
{ childId: children.clara.id, userId: elternSchmidt.id },
|
|
{ childId: children.emil.id, userId: elternYilmaz.id },
|
|
{ childId: children.ben.id, userId: koordinator.id },
|
|
];
|
|
|
|
const targetWorkingDays = getWorkingDays(
|
|
targetMonth.getFullYear(),
|
|
targetMonth.getMonth() + 1,
|
|
12,
|
|
);
|
|
|
|
await prisma.notdienstAvailability.createMany({
|
|
data: targetWorkingDays.map((date, index) => {
|
|
const pair = availabilityPairs[index % availabilityPairs.length];
|
|
return {
|
|
kitaId: kita.id,
|
|
childId: pair.childId,
|
|
userId: pair.userId,
|
|
date,
|
|
};
|
|
}),
|
|
});
|
|
|
|
const currentPlan = await prisma.notdienstPlan.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
year: currentMonth.getFullYear(),
|
|
month: currentMonth.getMonth() + 1,
|
|
status: NotdienstPlanStatus.PUBLISHED,
|
|
createdById: koordinator.id,
|
|
publishedAt: new Date(),
|
|
},
|
|
});
|
|
|
|
await prisma.notdienstAssignment.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
planId: currentPlan.id,
|
|
childId: children.anna.id,
|
|
date: today,
|
|
},
|
|
});
|
|
|
|
const previousPlan = await prisma.notdienstPlan.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
year: previousMonth.getFullYear(),
|
|
month: previousMonth.getMonth() + 1,
|
|
status: NotdienstPlanStatus.PUBLISHED,
|
|
createdById: koordinator.id,
|
|
publishedAt: addDays(today, -10),
|
|
},
|
|
});
|
|
|
|
const pastAssignment = await prisma.notdienstAssignment.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
planId: previousPlan.id,
|
|
childId: children.clara.id,
|
|
date: previousAssignmentDate,
|
|
},
|
|
});
|
|
|
|
await prisma.notdienstAlert.create({
|
|
data: {
|
|
kitaId: kita.id,
|
|
assignmentId: pastAssignment.id,
|
|
parentUserId: elternSchmidt.id,
|
|
triggeredById: koordinator.id,
|
|
educatorId: educators.sabine.id,
|
|
status: NotdienstAlertStatus.CONFIRMED,
|
|
confirmationToken: "demo-confirmed-alert-token",
|
|
triggeredAt: previousAssignmentDate,
|
|
confirmedAt: previousAssignmentDate,
|
|
notes: "Beispiel-Alarm aus Seed-Daten.",
|
|
},
|
|
});
|
|
}
|
|
|
|
async function createDemoData() {
|
|
console.log("Seeding Kita-Planer demo data...");
|
|
|
|
const passwordHash = await hash(DEFAULT_PASSWORD, 12);
|
|
const consentAt = new Date();
|
|
const context = await createDemoUsers(passwordHash, consentAt);
|
|
const children = await createChildren(context);
|
|
const educators = await createEducators(context.kita.id);
|
|
|
|
await createParentDuties(context);
|
|
await createDutyPlan(context);
|
|
await createAbsences(context, children);
|
|
await createInvites(context);
|
|
await createAnnouncements(context);
|
|
await createTermine(context);
|
|
await createNotdienstData(context, children, educators);
|
|
|
|
printSummary(context, children);
|
|
}
|
|
|
|
async function seedIfEmpty() {
|
|
if (!(await isDatabaseEmpty())) {
|
|
console.log("Seed uebersprungen: Datenbank enthaelt bereits Kita- oder User-Daten.");
|
|
return;
|
|
}
|
|
|
|
await createDemoData();
|
|
}
|
|
|
|
function printSummary(
|
|
{
|
|
kita,
|
|
superAdmin,
|
|
admin,
|
|
erzieherUser,
|
|
koordinator,
|
|
elternSchmidt,
|
|
elternYilmaz,
|
|
pendingParent,
|
|
}: SeedContext,
|
|
children: Awaited<ReturnType<typeof createChildren>>,
|
|
) {
|
|
console.log("Seed complete");
|
|
console.log("");
|
|
console.log(` Kita: ${kita.name} (${kita.slug})`);
|
|
console.log("");
|
|
console.log(` Logins (Passwort jeweils: ${DEFAULT_PASSWORD})`);
|
|
console.log(` Superadmin: ${superAdmin.email}`);
|
|
console.log(` Admin: ${admin.email}`);
|
|
console.log(` Erzieherin: ${erzieherUser.email}`);
|
|
console.log(` Koordinator: ${koordinator.email}`);
|
|
console.log(` Eltern: ${elternSchmidt.email}`);
|
|
console.log(` Eltern: ${elternYilmaz.email}`);
|
|
console.log("");
|
|
console.log(
|
|
` Offener Invite: ${pendingParent.email} -> /invite/demo-pending-parent-token`,
|
|
);
|
|
console.log(
|
|
` Kinder: ${Object.values(children)
|
|
.map((child) => `${child.firstName} ${child.lastName}`)
|
|
.join(", ")}`,
|
|
);
|
|
}
|
|
|
|
async function main() {
|
|
if (!isSeedAllowed()) {
|
|
return;
|
|
}
|
|
|
|
if (RESET_MODE) {
|
|
console.log("Reset demo seed data...");
|
|
await resetDemoData();
|
|
await createDemoData();
|
|
return;
|
|
}
|
|
|
|
await seedIfEmpty();
|
|
}
|
|
|
|
main()
|
|
.catch((error) => {
|
|
console.error("Seed failed:", error);
|
|
process.exit(1);
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect();
|
|
});
|