diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..458fa0c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,50 @@ +# Changelog + +Alle nennenswerten Änderungen an Flimmer stehen in dieser Datei. + +Das Format folgt [Keep a Changelog](https://keepachangelog.com/de/1.1.0/), +die Versionierung [Semantic Versioning](https://semver.org/lang/de/). + +## [Unveröffentlicht] + +## [0.1.0] — 2026-09-01 + +Erste lauffähige Etappe: Gerüst, Marke, Datenmodell und Anmeldung. + +### Hinzugefügt + +- **Projektgerüst** mit Next.js 16 (App Router), TypeScript, Tailwind CSS v4 + und `standalone`-Build für schlanke Container. +- **Marke Flimmer**: Logo als SVG in drei Varianten (Bildmarke, Bildmarke mit + Wortmarke, monochrom) plus Maskable-Variante. Die Wortmarke ist aus Pfaden + konstruiert und braucht keine installierte Schrift. +- **Icon-Generator** (`npm run icons`): erzeugt Favicon (SVG und ICO), + PWA-Icons in sieben Größen, Maskable-Icons, Apple-Touch-Icon und OG-Bild + aus den SVG-Quellen. +- **Design-Tokens** als CSS-Variablen, über `@theme inline` an Tailwind + angebunden. Dunkles Standard-Theme und heller Modus mit Umschalter + (Dunkel / Hell / System), ohne Aufblitzen beim Laden. Alle Farbkombinationen + erfüllen WCAG AA; getrennte Verläufe für Flächen und Text sorgen dafür, dass + auch der Signaturverlauf im hellen Modus lesbar bleibt. +- **Datenmodell** (Prisma, PostgreSQL) für Konten, Katalog (Titel, Staffeln, + Episoden, Streamingdienste), persönliches Tracking, Universen mit + Reihenfolgen sowie Benachrichtigungen und Hintergrundläufe. +- **Authentifizierung**: Registrierung und Anmeldung mit E-Mail und Passwort + (bcrypt), Sitzungen als opake Token in der Datenbank mit httpOnly-Cookie. + Der erste registrierte Zugang wird automatisch Administrator; die + Registrierung lässt sich instanzweit abschalten. +- **Optionales SSO** über OIDC (Authorization Code mit PKCE) für Authelia, + Keycloak, Authentik und Verwandte — per Umgebungsvariablen aktivierbar, + mit Zuordnung zu vorhandenen Konten über die E-Mail-Adresse. +- **API-Schlüssel** je Nutzer als Grundlage für die spätere REST-API. +- **Docker-Compose-Setup** für den Selbstbetrieb (App und PostgreSQL, + persistente Volumes, Healthcheck) samt Entrypoint, der ausstehende + Migrationen beim Start einspielt. +- **Healthcheck** unter `/api/health`, der auch die Datenbank prüft. +- **PWA-Manifest** mit allen Icon-Größen. +- **Oberflächentexte** auf Deutsch, gebündelt in `src/i18n` und so aufgebaut, + dass weitere Sprachen als zusätzliche Datei dazukommen können. +- **Seed-Skript** mit Demo-Konten sowie README und Design-Dokumentation. + +[Unveröffentlicht]: https://git.wilde-server.de/florian.wilde/flimmer/compare/v0.1.0...HEAD +[0.1.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.1.0 diff --git a/CLAUDE.md b/CLAUDE.md index 2d67c14..9e03a9d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -83,3 +83,13 @@ Statistiken, Benachrichtigungen, REST-API, PWA. Oberflächensprache **Deutsch**. ## Fortschritt - Stand: **Etappe 1 läuft** (Start 2026-09-01 18:09) + + + +# This is NOT the Next.js you know + +This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices. + +This block is written and re-added by `next dev` — verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean. + + diff --git a/DEVLOG.md b/DEVLOG.md index dd83e3a..121b11c 100644 --- a/DEVLOG.md +++ b/DEVLOG.md @@ -1,7 +1,6 @@ # DEVLOG — Entwicklungszeiterfassung Flimmer Alle Zeiten per `date`-Befehl erfasst (Europe/Berlin), nicht geschätzt. -Format je Eintrag: `Start – Ende (Dauer) — Beschreibung`. --- @@ -9,4 +8,23 @@ Format je Eintrag: `Start – Ende (Dauer) — Beschreibung`. | # | Start | Ende | Dauer | Arbeitsschritt | |---|---|---|---|---| -| 1.1 | 2026-09-01 18:09 | | | Rückfragen geklärt, Repo/Toolchain geprüft, Projekt-CLAUDE.md angelegt | +| 1.1 | 18:09 | 18:12 | 3 min | Rückfragen geklärt, Repo und Werkzeugkette geprüft, Projekt-`CLAUDE.md` als Gedächtnis angelegt | +| 1.2 | 18:12 | 18:22 | 10 min | `package.json`, TypeScript-, Next- und PostCSS-Konfiguration; Abhängigkeiten installiert (Aufräumen nach hängendem npm-Prozess) | +| 1.3 | 18:22 | 18:26 | 4 min | Design-Tokens in `globals.css`: Farbwelt dunkel/hell, Verläufe, Bausteine, Mikro-Animation | +| 1.4 | 18:26 | 18:33 | 7 min | Logo entworfen: Bildmarke, Wortmarke aus Pfaden, Lockup, monochrom, Maskable; Icon-Generator und alle Rasterableitungen | +| 1.5 | 18:33 | 18:36 | 3 min | Prisma-Schema (22 Modelle), Umstellung auf Prisma 7 mit Treiber-Adapter, erste Migration | +| 1.6 | 18:36 | 18:40 | 4 min | Kernbibliotheken: Umgebungsprüfung, DB-Singleton, Auth (Passwörter, Sitzungen, API-Schlüssel), Instanz-Einstellungen, i18n | +| 1.7 | 18:40 | 18:44 | 4 min | App-Hülle: Layout mit Theme-Bootstrap, Header, Navigation, Nutzermenü, Anmeldung und Registrierung, Healthcheck; visuelle Kontrolle in beiden Themes und Kontrastkorrektur für den hellen Modus | +| 1.8 | 18:44 | 18:52 | 8 min | Docker-Setup (Dockerfile, Compose, Entrypoint mit Migrationslauf), OIDC-Anbindung, Seed-Skript, README, Design-Dokumentation, Changelog | + +**Etappe 1 gesamt: 43 min** (18:09 – 18:52) + +--- + +## Gesamtübersicht + +| Etappe | Version | Dauer | +|---|---|---| +| 1 — Gerüst, Branding, Docker, Schema, Auth | 0.1.0 | 43 min | + +**Bisher gesamt: 43 min** diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e13bc55 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Florian Wilde + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9d9d3f0 --- /dev/null +++ b/README.md @@ -0,0 +1,198 @@ +

+ Flimmer +

+ +

+ Serien und Filme tracken — selbst gehostet, ohne fremde Konten.
+ Episodenfortschritt, eigene Universen mit mehreren Reihenfolgen, Statistiken + und Benachrichtigungen, wenn es weitergeht. +

+ +--- + +**Flimmer** ist ein selbst hostbarer Tracker für Serien und Filme — benannt nach +der Flimmerkiste und dem warmen Flimmern, das ein Bildschirm im dunklen Zimmer +verbreitet. Metadaten kommen von [TMDB](https://www.themoviedb.org/), die Daten +bleiben auf deinem Server. + +## Was Flimmer kann + +- **Tracking** — Serien und Filme mit Status (Schaue gerade, Pausiert, + Abgeschlossen, Abgebrochen, Watchlist), Episodenfortschritt einzeln oder + staffelweise, „+1 Episode"-Knopf, Rewatch-Zählung, Bewertung, Notizen, Tags. +- **Universen** — MCU, Star Wars, Wizarding World … beliebige Filme *und* Serien + in einem Universum bündeln, mit mehreren Reihenfolgen (Erscheinung, + Story-Chronologie, Einsteiger-Route) und Gesamtfortschritt. +- **Metadaten von TMDB** — Suche, Poster, Staffeln und Episoden, offizielle + Collections, Streaming-Verfügbarkeit in deiner Region. +- **Benachrichtigungen** — bei neuen Episoden und Releases, per E-Mail, ntfy, + Gotify oder Webhook (Discord/Slack-kompatibel), pro Nutzer einstellbar. +- **Mehrere Nutzer** — jede Person hat ihre eigene Bibliothek; Universen lassen + sich teilen. Der erste registrierte Zugang wird Administrator. +- **REST-API und PWA** — dokumentierte Schnittstelle mit eigenen API-Schlüsseln, + installierbar auf dem Startbildschirm. + +## Schnellstart + +Voraussetzungen: Docker und Docker Compose. + +```bash +git clone https://git.wilde-server.de/florian.wilde/flimmer.git +cd flimmer +cp .env.example .env +``` + +In der `.env` mindestens diese drei Werte setzen: + +```dotenv +POSTGRES_PASSWORD=ein-langes-zufaelliges-passwort +AUTH_SECRET=noch-ein-langes-zufaelliges-geheimnis +APP_URL=https://flimmer.example.com +``` + +Geheimnisse erzeugen: + +```bash +node -e "console.log(require('crypto').randomBytes(32).toString('hex'))" +``` + +Dann starten: + +```bash +docker compose up -d +``` + +Flimmer läuft auf . Der **erste** Zugang, der sich +registriert, wird automatisch Administrator — lege ihn also gleich an. Danach +lässt sich die Registrierung in der Verwaltung schließen. + +### TMDB-Schlüssel + +Ohne TMDB findet die Suche keine Metadaten. Der Schlüssel ist kostenlos: + +1. Konto auf [themoviedb.org](https://www.themoviedb.org/signup) anlegen +2. Unter *Einstellungen → API* einen Schlüssel beantragen +3. In die `.env` eintragen und `docker compose up -d` erneut ausführen: + +```dotenv +TMDB_API_KEY=dein-schluessel +TMDB_REGION=DE +TMDB_LANGUAGE=de-DE +``` + +## Betrieb hinter einem Reverse Proxy + +`APP_URL` muss auf die öffentliche Adresse zeigen — daraus werden Links in +Benachrichtigungen und der OIDC-Rücksprung gebildet. Als Healthcheck eignet +sich `/api/health`; der Endpunkt prüft auch die Datenbankverbindung. + +Beispiel für Caddy: + +```caddyfile +flimmer.example.com { + reverse_proxy flimmer:3000 +} +``` + +## Aktualisieren + +```bash +cd flimmer +git pull +docker compose build +docker compose up -d +``` + +Datenbankmigrationen laufen automatisch beim Start des Containers — ein eigener +Handgriff ist nicht nötig. **Vor** einem Update ein Backup zu ziehen ist +trotzdem eine gute Angewohnheit. + +## Backup + +Alles, was zählt, steckt in der Datenbank; das Volume `flimmer-data` enthält +nur den Bild-Cache und lässt sich jederzeit neu aufbauen. + +```bash +# Sicherung +docker compose exec -T db pg_dump -U flimmer -d flimmer --clean --if-exists \ + | gzip > flimmer-$(date +%F).sql.gz + +# Rückspielen +gunzip -c flimmer-2026-09-01.sql.gz \ + | docker compose exec -T db psql -U flimmer -d flimmer +``` + +Für einen nächtlichen Lauf genügt ein Cron-Eintrag mit demselben Befehl. +Wer zusätzlich den Bild-Cache sichern will: + +```bash +docker run --rm -v flimmer_flimmer-data:/data -v "$PWD":/backup alpine \ + tar czf /backup/flimmer-data.tar.gz -C /data . +``` + +## Konfiguration + +Sämtliche Einstellungen laufen über Umgebungsvariablen; die vollständige Liste +mit Erklärungen steht in [`.env.example`](.env.example). Die wichtigsten: + +| Variable | Bedeutung | +|---|---| +| `APP_URL` | Öffentliche Adresse der Instanz | +| `AUTH_SECRET` | Geheimnis für Sitzungen — mindestens 32 Zeichen | +| `TMDB_API_KEY` | TMDB-Schlüssel für Metadaten | +| `TMDB_REGION` | Region für die Streaming-Verfügbarkeit (Standard `DE`) | +| `ALLOW_REGISTRATION` | Selbstregistrierung bei der Erstinbetriebnahme | +| `ENABLE_SCHEDULER` | Eingebauter Hintergrundlauf für Sync und Benachrichtigungen | +| `SMTP_*` | E-Mail-Versand | +| `OIDC_*` | Optionale SSO-Anbindung (Authelia, Keycloak, Authentik …) | + +## Entwicklung + +```bash +npm install +docker compose -f docker-compose.dev.yml up -d # nur PostgreSQL +cp .env.example .env # DATABASE_URL auf localhost:5439 +npm run db:migrate +npm run db:seed # Demo-Konten +npm run dev +``` + +| Befehl | Wirkung | +|---|---| +| `npm run dev` | Entwicklungsserver | +| `npm run build` | Produktionsbuild | +| `npm run typecheck` | TypeScript prüfen | +| `npm run db:migrate` | Migration erzeugen und anwenden | +| `npm run db:studio` | Prisma Studio | +| `npm run db:seed` | Beispieldaten | +| `npm run icons` | Favicon und PWA-Icons aus dem SVG-Logo neu erzeugen | + +Aufbau des Projekts: + +``` +src/ + app/ Routen (App Router), API-Endpunkte + components/ Wiederverwendbare Bausteine + lib/ Serverseitige Logik: DB, Auth, TMDB, Benachrichtigungen + i18n/ Oberflächentexte +prisma/ Schema, Migrationen, Seed +public/brand/ Logo in allen Varianten +docker/ Entrypoint des Containers +docs/ Anleitung, Design-Dokumentation +``` + +## Technik + +Next.js (App Router) mit TypeScript, PostgreSQL über Prisma, Tailwind CSS. +Warum Next und nicht SvelteKit: Oberfläche, REST-API und Hintergrundläufe +stecken in **einem** Deployment, Server Components halten den Datenbankzugriff +serverseitig, und der `standalone`-Build ergibt ein schlankes Image ohne +Build-Werkzeuge. Für ein selbst gehostetes Werkzeug zählt vor allem, dass ein +einziger Container genügt. + +## Lizenz + +MIT — siehe [LICENSE](LICENSE). + +Metadaten stammen von TMDB. Flimmer wird von TMDB weder betrieben noch +unterstützt. diff --git a/docs/DESIGN.md b/docs/DESIGN.md new file mode 100644 index 0000000..86d8109 --- /dev/null +++ b/docs/DESIGN.md @@ -0,0 +1,122 @@ +# Flimmer — Design-Sprache + +Diese Datei hält fest, warum die Oberfläche aussieht, wie sie aussieht, und +welche Werte dabei gelten. Sie ist die Referenz für alles, was später dazukommt. + +## Idee + +Der Name kommt von der **Flimmerkiste** und vom warmen Flimmern eines +Bildschirms im abgedunkelten Zimmer. Genau das trägt die Gestaltung: ein sehr +dunkler, blauvioletter Raum, in den ein warmes Licht fällt. Alles Farbige in +der Oberfläche ist dieses Licht — es gibt keine zweite, konkurrierende +Signalfarbe. + +## Marke + +| Variante | Datei | Einsatz | +|---|---|---| +| Bildmarke | `public/brand/flimmer-icon.svg` | App-Icon, Favicon, Avatare | +| Bildmarke + Wortmarke | `public/brand/flimmer-logo.svg` | Header, Login, README | +| Monochrom | `public/brand/flimmer-mono.svg` | Druck, E-Mail-Footer, Prägung | +| Maskable | `public/brand/flimmer-icon-maskable.svg` | Android-Startbildschirm | +| Wortmarke allein | `public/brand/flimmer-wordmark.svg` | Sonderfälle | + +Die Bildmarke ist ein abgerundetes Bildschirm-Rechteck mit weichem, warmem +Glühen und einem Play-Dreieck; der angedeutete Standfuß macht daraus die +Flimmerkiste. Die **Wortmarke ist aus Pfaden konstruiert** (geometrische, leicht +gerundete Sans, Versalhöhe 90, x-Höhe 54, Strichstärke 15, runde Abschlüsse) — +sie braucht damit keine installierte Schrift und sieht überall identisch aus. + +Im UI liegt die Marke als React-Komponente vor +(`src/components/brand/FlimmerLogo.tsx`). Die Verläufe stehen einmalig in +`` im Root-Layout; alle Instanzen referenzieren sie. Rasterdateien +(Favicon, PWA-Icons, OG-Bild) sind reine Ableitungen und entstehen mit +`npm run icons`. + +## Farbwelt + +Die Signaturfarbe ist kein einzelner Ton, sondern ein **Verlauf von Bernstein +nach Magenta**. Er trägt Buttons, Fortschrittsbalken, aktive Navigation und das +Glühen des Logos. + +### Dunkel (Standard) + +| Rolle | Wert | Kontrast auf Grund | +|---|---|---| +| Grund | `#0c0a14` | — | +| Karte | `#171424` | — | +| Rahmen | `#2e2745` | 1,4:1 (dekorativ) | +| Text | `#f4f1fa` | **17,0:1** | +| Text gedämpft | `#aca5c2` | **7,7:1** | +| Text zurückhaltend | `#7c7594` | **4,6:1** | +| Bernstein | `#ffb454` | **11,3:1** | +| Magenta | `#ff4d9d` | **6,0:1** | +| Text auf dem Verlauf | `#1a1024` | min. **5,5:1** (am Magenta-Ende) | + +### Hell + +| Rolle | Wert | Kontrast auf Grund | +|---|---|---| +| Grund | `#faf7f5` (warmgrau) | — | +| Karte | `#ffffff` | — | +| Text | `#1b1524` | **16,2:1** | +| Text gedämpft | `#5b5268` | **6,7:1** | +| Text zurückhaltend | `#766c84` | **4,6:1** | +| Akzent als Text | `#8a4b00` | **6,4:1** | +| Akzent-Alternative | `#b01262` | **6,4:1** | +| Text auf dem Verlauf | `#23122c` | min. **6,1:1** | + +Damit erfüllt jede Text-/Hintergrund-Kombination **WCAG AA**. + +### Zwei Verläufe, nicht einer + +Der vollfarbige Verlauf funktioniert im Dunkeln überall — auf hellem Grund +verschwindet sein Bernstein-Ende jedoch. Deshalb gibt es zwei Tokens: + +- `--fl-gradient` — Flächen (Buttons, Fortschritt, Glühen). In beiden Themes + vollfarbig, weil darauf immer dunkler Text (`--fl-on-accent`) sitzt. +- `--fl-gradient-ink` — **Text** und feine Linien. Im Dunkeln identisch, im + Hellen abgedunkelt auf `#8a4b00 → #b01262`, damit AA gilt. + +Analog dazu die Logo-Stops `--fl-brand-1/2/3`: im Hellen tiefer angesetzt +(`#c26a00 → #c9186f`), damit die Wortmarke auf warmem Weiß lesbar bleibt, ohne +die Bewegung von Bernstein nach Magenta aufzugeben. + +## Tokens + +Alle Werte liegen als CSS-Variablen `--fl-*` in `src/app/globals.css` und werden +über `@theme inline` an Tailwind durchgereicht. Ein Theme-Wechsel setzt nur das +Attribut `data-theme` am ``-Element; ein Inline-Skript im Layout tut das, +bevor der erste Pixel gemalt wird, damit nichts aufblitzt. + +Ein zusätzliches Theme braucht daher genau einen neuen Selektor-Block mit +denselben Variablennamen — keine Änderung an Komponenten. + +## Bausteine + +| Klasse | Zweck | +|---|---| +| `.fl-card` | Karte: halbtransparent, weicher Rahmen, Rückenunschärfe | +| `.fl-poster-card` | Posterkachel mit sanftem Aufglimmen beim Hover | +| `.fl-btn` + `.fl-btn-primary` / `.fl-btn-ghost` | Schaltflächen | +| `.fl-input` | Eingabefelder samt Fokusring im Magenta | +| `.fl-progress` | Fortschrittsbalken im Signaturverlauf | +| `.fl-glimmer` | Mikro-Animation beim Abhaken einer Episode | + +## Bewegung + +Ruhig und kurz: 200–420 ms, `cubic-bezier(0.22, 1, 0.36, 1)`. Keine harten +Blitze — beim Abhaken einer Episode glimmt die Zeile einmal warm auf und +verklingt. `prefers-reduced-motion: reduce` schaltet sämtliche Übergänge ab. + +## Typografie + +**Outfit** — geometrisch, leicht gerundet, passt zur Wortmarke. Wird beim Bauen +heruntergeladen und mit ausgeliefert; die laufende Instanz fragt nie bei Google +an. Rückfallkette: Inter, dann System-Sans. + +## Grundhaltung + +Posterlastig und filmisch: großzügige Poster, abgerundete Ecken, weiche +Verläufe statt harter Linien. Farbe ist knapp und bedeutet etwas — der Verlauf +markiert, was gerade dran ist. Der Rest bleibt im Dunkeln. diff --git a/prisma/seed.ts b/prisma/seed.ts new file mode 100644 index 0000000..08877f6 --- /dev/null +++ b/prisma/seed.ts @@ -0,0 +1,75 @@ +/** + * Beispieldaten für die Entwicklung. + * + * npm run db:seed + * + * Das Skript ist idempotent: mehrfaches Ausführen legt nichts doppelt an. + * Es fasst ausschließlich die Demo-Konten und deren Daten an — eine echte + * Instanz nimmt dadurch keinen Schaden, sollte es versehentlich laufen. + */ +import { PrismaPg } from "@prisma/adapter-pg"; +import bcrypt from "bcryptjs"; +import { PrismaClient } from "../src/generated/prisma/client"; + +try { + process.loadEnvFile(".env"); +} catch { + // Werte kommen aus der Umgebung. +} + +const prisma = new PrismaClient({ + adapter: new PrismaPg({ connectionString: process.env.DATABASE_URL }), +}); + +const DEMO_PASSWORD = "flimmer-demo-2026"; + +async function seedUsers() { + const passwordHash = await bcrypt.hash(DEMO_PASSWORD, 12); + + const admin = await prisma.user.upsert({ + where: { email: "demo@flimmer.local" }, + update: {}, + create: { + email: "demo@flimmer.local", + name: "Demo Nutzer", + passwordHash, + role: "ADMIN", + region: "DE", + publicProfile: true, + profileSlug: "demo", + }, + }); + + const friend = await prisma.user.upsert({ + where: { email: "gast@flimmer.local" }, + update: {}, + create: { + email: "gast@flimmer.local", + name: "Gast Nutzerin", + passwordHash, + role: "USER", + region: "DE", + }, + }); + + return { admin, friend }; +} + +async function main() { + console.log("Seed: lege Demo-Konten an ..."); + const { admin, friend } = await seedUsers(); + + console.log(""); + console.log("Fertig. Anmelden mit:"); + console.log(` ${admin.email} / ${DEMO_PASSWORD} (Administrator)`); + console.log(` ${friend.email} / ${DEMO_PASSWORD}`); +} + +main() + .catch((error) => { + console.error(error); + process.exit(1); + }) + .finally(async () => { + await prisma.$disconnect(); + }); diff --git a/releases/v0.1.0.md b/releases/v0.1.0.md new file mode 100644 index 0000000..01b8211 --- /dev/null +++ b/releases/v0.1.0.md @@ -0,0 +1,38 @@ +# Flimmer 0.1.0 + +Erste lauffähige Etappe: Gerüst, Marke, Datenmodell und Anmeldung. + +### Hinzugefügt + +- **Projektgerüst** mit Next.js 16 (App Router), TypeScript, Tailwind CSS v4 + und `standalone`-Build für schlanke Container. +- **Marke Flimmer**: Logo als SVG in drei Varianten (Bildmarke, Bildmarke mit + Wortmarke, monochrom) plus Maskable-Variante. Die Wortmarke ist aus Pfaden + konstruiert und braucht keine installierte Schrift. +- **Icon-Generator** (`npm run icons`): erzeugt Favicon (SVG und ICO), + PWA-Icons in sieben Größen, Maskable-Icons, Apple-Touch-Icon und OG-Bild + aus den SVG-Quellen. +- **Design-Tokens** als CSS-Variablen, über `@theme inline` an Tailwind + angebunden. Dunkles Standard-Theme und heller Modus mit Umschalter + (Dunkel / Hell / System), ohne Aufblitzen beim Laden. Alle Farbkombinationen + erfüllen WCAG AA; getrennte Verläufe für Flächen und Text sorgen dafür, dass + auch der Signaturverlauf im hellen Modus lesbar bleibt. +- **Datenmodell** (Prisma, PostgreSQL) für Konten, Katalog (Titel, Staffeln, + Episoden, Streamingdienste), persönliches Tracking, Universen mit + Reihenfolgen sowie Benachrichtigungen und Hintergrundläufe. +- **Authentifizierung**: Registrierung und Anmeldung mit E-Mail und Passwort + (bcrypt), Sitzungen als opake Token in der Datenbank mit httpOnly-Cookie. + Der erste registrierte Zugang wird automatisch Administrator; die + Registrierung lässt sich instanzweit abschalten. +- **Optionales SSO** über OIDC (Authorization Code mit PKCE) für Authelia, + Keycloak, Authentik und Verwandte — per Umgebungsvariablen aktivierbar, + mit Zuordnung zu vorhandenen Konten über die E-Mail-Adresse. +- **API-Schlüssel** je Nutzer als Grundlage für die spätere REST-API. +- **Docker-Compose-Setup** für den Selbstbetrieb (App und PostgreSQL, + persistente Volumes, Healthcheck) samt Entrypoint, der ausstehende + Migrationen beim Start einspielt. +- **Healthcheck** unter `/api/health`, der auch die Datenbank prüft. +- **PWA-Manifest** mit allen Icon-Größen. +- **Oberflächentexte** auf Deutsch, gebündelt in `src/i18n` und so aufgebaut, + dass weitere Sprachen als zusätzliche Datei dazukommen können. +- **Seed-Skript** mit Demo-Konten sowie README und Design-Dokumentation. diff --git a/scripts/shot.mjs b/scripts/shot.mjs new file mode 100644 index 0000000..d57ff8e --- /dev/null +++ b/scripts/shot.mjs @@ -0,0 +1,21 @@ +/** + * Schnelles Einzelbild einer Seite — Werkzeug für die Entwicklung. + * node scripts/shot.mjs [breite] [hoehe] [theme] + */ +import { chromium } from "playwright"; + +const [, , url, out, w = "1440", h = "900", theme = "dark"] = process.argv; + +const browser = await chromium.launch(); +const page = await browser.newPage({ + viewport: { width: Number(w), height: Number(h) }, + deviceScaleFactor: 2, +}); +await page.addInitScript((mode) => { + localStorage.setItem("flimmer-theme", mode); +}, theme); +await page.goto(url, { waitUntil: "networkidle" }); +await page.waitForTimeout(600); +await page.screenshot({ path: out }); +await browser.close(); +console.log("ok", out);