Files
planer/prisma/seed.ts
T
Florian WildeandClaude Opus 5 1876ae4c6b feat(betrieb): Health-Endpunkt und Seed für eine frische Datenbank
/api/health meldet Status, Version, Instanz und Erreichbarkeit der
Datenbank – ohne Anmeldung, deshalb ohne Zählstände, Namen oder Adressen.
update.sh wird sich später darauf stützen.

Der Seed legt die vier Bereiche an und ein erstes Verwaltungskonto aus
ADMIN_EMAIL und ADMIN_PASSWORT. Er läuft mehrfach ohne Schaden; ohne
ADMIN_PASSWORT entsteht ein Konto, das sich nur über OIDC oder Passkey
anmelden kann.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-10 13:02:49 +02:00

157 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Grundausstattung für eine frische Datenbank.
*
* Läuft mehrfach ohne Schaden: alles wird per upsert angelegt, vorhandene
* Einträge bleiben unangetastet. Es entstehen keine erfundenen Aufgaben oder
* Termine – dafür gibt es prisma/demo-seed.ts.
*/
import 'dotenv/config'
import { PrismaPg } from '@prisma/adapter-pg'
import bcrypt from 'bcryptjs'
import { PrismaClient } from '../src/generated/prisma/client.js'
const verbindung = process.env.DATABASE_URL
if (!verbindung) {
throw new Error('DATABASE_URL ist nicht gesetzt.')
}
const db = new PrismaClient({ adapter: new PrismaPg({ connectionString: verbindung }) })
const BEREICHE = [
{
name: 'Firma',
farbe: '#2563eb',
reihenfolge: 1,
arbeitsfensterVon: 7 * 60 + 30,
arbeitsfensterBis: 16 * 60 + 30,
kapazitaetMo: 360,
kapazitaetDi: 360,
kapazitaetMi: 360,
kapazitaetDo: 360,
kapazitaetFr: 240,
kapazitaetSa: 0,
kapazitaetSo: 0,
},
{
name: 'Gewerbe',
farbe: '#7c3aed',
reihenfolge: 2,
arbeitsfensterVon: 17 * 60,
arbeitsfensterBis: 21 * 60,
kapazitaetMo: 90,
kapazitaetDi: 90,
kapazitaetMi: 90,
kapazitaetDo: 90,
kapazitaetFr: 60,
kapazitaetSa: 180,
kapazitaetSo: 0,
},
{
name: 'Privat',
farbe: '#16a34a',
reihenfolge: 3,
arbeitsfensterVon: 17 * 60,
arbeitsfensterBis: 22 * 60,
kapazitaetMo: 60,
kapazitaetDi: 60,
kapazitaetMi: 60,
kapazitaetDo: 60,
kapazitaetFr: 120,
kapazitaetSa: 240,
kapazitaetSo: 240,
},
{
name: 'Homelab',
farbe: '#ea580c',
reihenfolge: 4,
arbeitsfensterVon: 19 * 60,
arbeitsfensterBis: 23 * 60,
kapazitaetMo: 0,
kapazitaetDi: 60,
kapazitaetMi: 0,
kapazitaetDo: 60,
kapazitaetFr: 0,
kapazitaetSa: 120,
kapazitaetSo: 60,
},
]
async function bereicheAnlegen(): Promise<void> {
for (const bereich of BEREICHE) {
await db.bereich.upsert({
where: { name: bereich.name },
update: {},
create: bereich,
})
}
console.log(`Bereiche geprüft: ${BEREICHE.map((b) => b.name).join(', ')}`)
}
async function verwaltungAnlegen(): Promise<void> {
const email = process.env.ADMIN_EMAIL?.trim().toLowerCase()
const passwort = process.env.ADMIN_PASSWORT
if (!email) {
console.log(
'ADMIN_EMAIL ist nicht gesetzt – kein Verwaltungskonto angelegt. ' +
'Bei reiner OIDC-Anmeldung ist das richtig: die erste Person, die sich ' +
'anmeldet, muss danach von Hand hochgestuft werden.',
)
return
}
const vorhanden = await db.benutzer.findUnique({
where: { email },
select: { id: true, rolle: true },
})
if (vorhanden) {
if (vorhanden.rolle !== 'ADMIN') {
await db.benutzer.update({ where: { id: vorhanden.id }, data: { rolle: 'ADMIN' } })
console.log(`${email} zur Verwaltung hochgestuft.`)
} else {
console.log(`${email} ist bereits Verwaltung.`)
}
return
}
if (!passwort) {
await db.benutzer.create({
data: { email, rolle: 'ADMIN', name: null },
})
console.log(
`${email} als Verwaltung angelegt, ohne Passwort. ` +
'Anmeldung ist damit nur über OIDC oder einen Passkey möglich.',
)
return
}
if (passwort.length < 12) {
throw new Error('ADMIN_PASSWORT ist zu kurz, mindestens 12 Zeichen.')
}
await db.benutzer.create({
data: {
email,
rolle: 'ADMIN',
passwortHash: await bcrypt.hash(passwort, 12),
},
})
console.log(`${email} als Verwaltung mit Passwort angelegt.`)
}
async function main(): Promise<void> {
await bereicheAnlegen()
await verwaltungAnlegen()
}
main()
.then(async () => {
await db.$disconnect()
})
.catch(async (fehler: unknown) => {
console.error(fehler)
await db.$disconnect()
process.exit(1)
})