docs: README, Design-Dokumentation, Changelog und Seed

README mit Installation, Update-Weg und Backup-Anleitung; docs/DESIGN.md
hält Marke, Farbwerte samt gemessener Kontraste und die Bausteine fest.
Changelog nach Keep a Changelog, Release-Notes zusätzlich unter releases/.
This commit is contained in:
Florian Wilde
2026-09-01 18:46:49 +02:00
parent 63d47b4ead
commit 2e8e4df6cf
9 changed files with 555 additions and 2 deletions
+50
View File
@@ -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
+10
View File
@@ -83,3 +83,13 @@ Statistiken, Benachrichtigungen, REST-API, PWA. Oberflächensprache **Deutsch**.
## Fortschritt ## Fortschritt
- Stand: **Etappe 1 läuft** (Start 2026-09-01 18:09) - Stand: **Etappe 1 läuft** (Start 2026-09-01 18:09)
<!-- BEGIN:nextjs-agent-rules -->
# 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.
<!-- END:nextjs-agent-rules -->
+20 -2
View File
@@ -1,7 +1,6 @@
# DEVLOG — Entwicklungszeiterfassung Flimmer # DEVLOG — Entwicklungszeiterfassung Flimmer
Alle Zeiten per `date`-Befehl erfasst (Europe/Berlin), nicht geschätzt. 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 | | # | 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**
+21
View File
@@ -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.
+198
View File
@@ -0,0 +1,198 @@
<p align="center">
<img src="public/brand/flimmer-logo.svg" alt="Flimmer" width="380">
</p>
<p align="center">
<b>Serien und Filme tracken — selbst gehostet, ohne fremde Konten.</b><br>
Episodenfortschritt, eigene Universen mit mehreren Reihenfolgen, Statistiken
und Benachrichtigungen, wenn es weitergeht.
</p>
---
**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 <http://localhost:3000>. 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.
+122
View File
@@ -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
`<BrandDefs />` 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 `<html>`-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.
+75
View File
@@ -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();
});
+38
View File
@@ -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.
+21
View File
@@ -0,0 +1,21 @@
/**
* Schnelles Einzelbild einer Seite — Werkzeug für die Entwicklung.
* node scripts/shot.mjs <url> <ziel.png> [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);