From 35ecb2fa780bf368449b06702cc5c62244b4a628 Mon Sep 17 00:00:00 2001 From: Florian Wilde Date: Fri, 11 Sep 2026 13:34:40 +0200 Subject: [PATCH] chore: Screenshot-Instanz mit eingerichteten Meldewegen MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die Wegwerf-Instanz bekommt je Lauf ein frisch erzeugtes VAPID-Paar und einen Mailhost, den es nie geben wird. Damit zeigen die Bilder den eingerichteten Normalfall statt zweier Warnhinweise — und im Verzeichnis bleibt kein privater Schluessel liegen. Kein Push-Geraet mehr in den Demo-Daten: Seine Schluessel liegen verschluesselt, und der Versand entfernt jedes Geraet, dessen Schluessel er nicht lesen kann. Der erfundene Eintrag waere beim ersten Lauf wieder verschwunden. Dass der Browser im Bild "blockiert" meldet, laesst sich nicht abstellen: Chromium im Kopflosbetrieb antwortet auf Notification.permission immer so. Das Handbuch sagt es jetzt dazu. Co-Authored-By: Claude Opus 5 --- docker-compose.screenshots.yml | 11 +++++++++++ docs/handbuch/benachrichtigungen.md | 3 +++ prisma/demo-seed.ts | 19 ++++--------------- scripts/screenshots.ts | 7 +++++++ 4 files changed, 25 insertions(+), 15 deletions(-) diff --git a/docker-compose.screenshots.yml b/docker-compose.screenshots.yml index b92667c..f226003 100644 --- a/docker-compose.screenshots.yml +++ b/docker-compose.screenshots.yml @@ -57,5 +57,16 @@ services: WEBAUTHN_RP_NAME: Planer WEBAUTHN_ORIGIN: http://127.0.0.1:${SCREENSHOT_APP_PORT:-3200} DEMO_MODUS: 'true' + # Damit die Karte "Benachrichtigungen" den Normalfall zeigt und nicht + # den Hinweis, dass nichts eingerichtet ist. Das Schluesselpaar erzeugt + # scripts/screenshots.ts fuer jeden Lauf neu – es steht bewusst nirgends + # im Verzeichnis. + VAPID_OEFFENTLICH: ${SCREENSHOT_VAPID_OEFFENTLICH:-} + VAPID_PRIVAT: ${SCREENSHOT_VAPID_PRIVAT:-} + VAPID_KONTAKT: mailto:planer@planer.invalid + # Ein Host, den es nie geben wird: die Oberflaeche zeigt E-Mail als + # moeglich, hinaus geht trotzdem nichts. + SMTP_HOST: smtp.planer.invalid + SMTP_ABSENDER: Planer ports: - '${SCREENSHOT_APP_PORT:-3200}:3000' diff --git a/docs/handbuch/benachrichtigungen.md b/docs/handbuch/benachrichtigungen.md index deed848..b315671 100644 --- a/docs/handbuch/benachrichtigungen.md +++ b/docs/handbuch/benachrichtigungen.md @@ -6,6 +6,9 @@ Wichtige. Was du hier einschaltest, kommt. Alles andere nicht. ![Benachrichtigungen in den Einstellungen](../bilder/benachrichtigungen-hell-schreibtisch.png) +_Der Browser auf dem Bild hat Benachrichtigungen blockiert — so sieht die +Karte aus, wenn die Erlaubnis fehlt. Wie du sie erteilst, steht weiter unten._ + Du findest die Einstellung unter **Einstellungen → Benachrichtigungen**. ## Die zwei Wege diff --git a/prisma/demo-seed.ts b/prisma/demo-seed.ts index a27b481..7e81a9c 100644 --- a/prisma/demo-seed.ts +++ b/prisma/demo-seed.ts @@ -437,21 +437,10 @@ async function main(): Promise { }, }) - await db.pushGeraet.deleteMany({ where: { benutzerId: benutzer.id } }) - await db.pushGeraet.create({ - data: { - benutzerId: benutzer.id, - // Erfunden und unerreichbar. Die Schlüsselfelder halten sonst - // verschlüsselte Werte; hier stehen Platzhalter, weil aus der - // Demo-Instanz ohnehin nichts hinausgeht. - endpunkt: 'https://push.invalid/demo-arbeitsplatz', - p256dh: 'demo', - auth: 'demo', - bezeichnung: 'Firefox auf Windows', - erstelltAm: new Date(Date.UTC(2026, 1, 3, 8, 20)), - zuletztBenutzt: new Date(Date.UTC(2026, 2, 17, 6, 5)), - }, - }) + // Kein Push-Gerät in den Demo-Daten: Seine Schlüssel liegen + // verschlüsselt, und der Versand entfernt jedes Gerät, dessen Schlüssel er + // nicht lesen kann. Ein erfundener Eintrag verschwände beim ersten Lauf + // wieder — die Bilder zeigen deshalb den Zustand vor der ersten Anmeldung. console.log(`Demo-Daten stehen bereit. Anmeldung: ${DEMO_EMAIL}`) } diff --git a/scripts/screenshots.ts b/scripts/screenshots.ts index ede8135..d3dcae5 100644 --- a/scripts/screenshots.ts +++ b/scripts/screenshots.ts @@ -14,6 +14,7 @@ */ import { spawnSync } from 'node:child_process' import { fileURLToPath } from 'node:url' +import webpush from 'web-push' const WURZEL = fileURLToPath(new URL('..', import.meta.url)) const PROJEKT = 'planer-screenshots' @@ -22,10 +23,16 @@ const COMPOSE_DATEI = 'docker-compose.screenshots.yml' const APP_PORT = process.env.SCREENSHOT_APP_PORT ?? '3200' const DB_PORT = process.env.SCREENSHOT_DB_PORT ?? '5455' +// Frisches Paar je Lauf: Die Bilder sollen die eingerichtete Anwendung +// zeigen, ohne dass irgendwo ein privater Schluessel liegen bleibt. +const VAPID = webpush.generateVAPIDKeys() + const UMGEBUNG = { ...process.env, SCREENSHOT_APP_PORT: APP_PORT, SCREENSHOT_DB_PORT: DB_PORT, + SCREENSHOT_VAPID_OEFFENTLICH: VAPID.publicKey, + SCREENSHOT_VAPID_PRIVAT: VAPID.privateKey, } function meldung(text: string): void {