Files
planer/prisma/demo-seed.ts
Florian WildeandClaude Opus 5 a88273117c chore: Screenshot-Kette und Demo-Seed
npm run screenshots startet eine Wegwerf-Instanz in einem eigenen
Compose-Projekt mit eigener Datenbank, spielt ausschließlich erfundene
Daten ein, fährt die Seiten mit Playwright ab und räumt am Ende alles
wieder weg. Je Seite entstehen vier Bilder: hell und dunkel, Schreibtisch
und Handy. Die Uhr steht fest, damit sich zwischen zwei Läufen nur das
ändert, was sich wirklich geändert hat.

Der Demo-Seed verweigert den Dienst ohne DEMO_MODUS=true — er würde sonst
erfundene Daten in eine echte Datenbank schreiben.

Test- und Werkzeugordner sind jetzt aus dem Docker-Kontext ausgenommen.
Ein Typfehler in scripts/screenshots.ts hatte den Bau des Abbilds
blockiert, obwohl die Datei dort nichts zu suchen hat.

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

173 lines
4.3 KiB
TypeScript

/**
* Daten für die Screenshot-Instanz.
*
* Alles hier ist frei erfunden. Diese Datei darf niemals gegen eine
* Datenbank mit echten Daten laufen — deshalb bricht sie ab, wenn
* DEMO_MODUS nicht ausdrücklich auf true steht.
*
* Aufruf: über npm run screenshots, nicht von Hand.
*/
import 'dotenv/config'
import { PrismaPg } from '@prisma/adapter-pg'
import bcrypt from 'bcryptjs'
import { PrismaClient } from '../src/generated/prisma/client.js'
if (process.env.DEMO_MODUS !== 'true') {
console.error(
'Der Demo-Seed läuft nur mit DEMO_MODUS=true. Das ist Absicht: er würde ' +
'sonst erfundene Daten in eine echte Datenbank schreiben.',
)
process.exit(1)
}
const verbindung = process.env.DATABASE_URL
if (!verbindung) {
console.error('DATABASE_URL ist nicht gesetzt.')
process.exit(1)
}
const db = new PrismaClient({ adapter: new PrismaPg({ connectionString: verbindung }) })
export const DEMO_EMAIL = 'martina.beispiel@planer.invalid'
export const DEMO_PASSWORT = 'demo-instanz-nur-fuer-bilder'
const BEREICHE = [
{
name: 'Firma',
farbe: '#2563eb',
reihenfolge: 1,
arbeitsfensterVon: 450,
arbeitsfensterBis: 990,
kapazitaetMo: 360,
kapazitaetDi: 360,
kapazitaetMi: 360,
kapazitaetDo: 360,
kapazitaetFr: 240,
kapazitaetSa: 0,
kapazitaetSo: 0,
},
{
name: 'Gewerbe',
farbe: '#7c3aed',
reihenfolge: 2,
arbeitsfensterVon: 1020,
arbeitsfensterBis: 1260,
kapazitaetMo: 90,
kapazitaetDi: 90,
kapazitaetMi: 90,
kapazitaetDo: 90,
kapazitaetFr: 60,
kapazitaetSa: 180,
kapazitaetSo: 0,
},
{
name: 'Privat',
farbe: '#16a34a',
reihenfolge: 3,
arbeitsfensterVon: 1020,
arbeitsfensterBis: 1320,
kapazitaetMo: 60,
kapazitaetDi: 60,
kapazitaetMi: 60,
kapazitaetDo: 60,
kapazitaetFr: 120,
kapazitaetSa: 240,
kapazitaetSo: 240,
},
{
name: 'Homelab',
farbe: '#ea580c',
reihenfolge: 4,
arbeitsfensterVon: 1140,
arbeitsfensterBis: 1380,
kapazitaetMo: 0,
kapazitaetDi: 60,
kapazitaetMi: 0,
kapazitaetDo: 60,
kapazitaetFr: 0,
kapazitaetSa: 120,
kapazitaetSo: 60,
},
]
/** Erfundene Protokolleinträge, damit die Protokollseite nicht leer wirkt. */
const PROTOKOLL = [
{ aktion: 'bereich.angelegt', objektTyp: 'Bereich', details: { name: 'Homelab' } },
{
aktion: 'bereich.geaendert',
objektTyp: 'Bereich',
details: { vorher: 'Nebenerwerb', nachher: 'Gewerbe' },
},
{
aktion: 'passkey.angelegt',
objektTyp: 'Passkey',
details: { bezeichnung: 'Diensthandy' },
},
]
async function main(): Promise<void> {
console.log('Demo-Daten einspielen.')
for (const bereich of BEREICHE) {
await db.bereich.upsert({
where: { name: bereich.name },
update: bereich,
create: bereich,
})
}
const benutzer = await db.benutzer.upsert({
where: { email: DEMO_EMAIL },
update: { rolle: 'ADMIN', name: 'Martina Beispiel' },
create: {
email: DEMO_EMAIL,
name: 'Martina Beispiel',
rolle: 'ADMIN',
passwortHash: await bcrypt.hash(DEMO_PASSWORT, 10),
},
})
await db.auditEintrag.deleteMany({})
// Feste Zeitpunkte, damit die Bilder zwischen zwei Läufen gleich bleiben.
let versatz = 0
for (const eintrag of PROTOKOLL) {
versatz += 37
await db.auditEintrag.create({
data: {
zeitpunkt: new Date(Date.UTC(2026, 2, 17, 9, versatz % 60)),
benutzerId: benutzer.id,
benutzerEmail: benutzer.email,
aktion: eintrag.aktion,
objektTyp: eintrag.objektTyp,
details: eintrag.details,
instanz: 'daheim',
},
})
}
await db.passkey.deleteMany({ where: { benutzerId: benutzer.id } })
await db.passkey.create({
data: {
benutzerId: benutzer.id,
credentialId: 'demo-passkey-diensthandy',
publicKey: Buffer.from([0]),
bezeichnung: 'Diensthandy',
gesichert: true,
erstelltAm: new Date(Date.UTC(2026, 1, 3, 8, 15)),
zuletztBenutzt: new Date(Date.UTC(2026, 2, 17, 7, 42)),
},
})
console.log(`Demo-Daten stehen bereit. Anmeldung: ${DEMO_EMAIL}`)
}
main()
.then(async () => {
await db.$disconnect()
})
.catch(async (fehler: unknown) => {
console.error(fehler)
await db.$disconnect()
process.exit(1)
})