feat: Beispieluniversum im Seed und Notizen fuer 0.4.0
This commit is contained in:
+38
-1
@@ -7,6 +7,42 @@ die Versionierung [Semantic Versioning](https://semver.org/lang/de/).
|
||||
|
||||
## [Unveröffentlicht]
|
||||
|
||||
## [0.4.0] — 2026-09-01
|
||||
|
||||
Universen: zusammengehörige Titel, mehrere Reihenfolgen, ein Gesamtfortschritt.
|
||||
|
||||
### Hinzugefügt
|
||||
|
||||
- **Universen** aus beliebigen Filmen **und** Serien — MCU, Star Wars,
|
||||
Wizarding World oder was auch immer zusammengehört.
|
||||
- **Mehrere Reihenfolgen je Universum**. Die Erscheinungsreihenfolge wird aus
|
||||
den Erscheinungsdaten berechnet und nie gespeichert — sie stimmt damit immer.
|
||||
Weitere Reihenfolgen (Story-Chronologie, Einsteiger-Route) sind frei
|
||||
sortierbar, per Ziehen **und** über Pfeilknöpfe. Reines Drag & Drop wäre mit
|
||||
Tastatur nicht bedienbar und auf dem Handy fummelig.
|
||||
- **TMDB-Collections als Startpunkt**: Reihen, die in der eigenen Bibliothek
|
||||
vorkommen, lassen sich mit einem Klick übernehmen.
|
||||
- **Universums-Detailseite** mit nummerierter Liste, Gesamtfortschritt
|
||||
(„4 von 7 abgeschlossen, 21 h 21 min gesehen"), hervorgehobenem
|
||||
„Als Nächstes dran" und der Restlaufzeit bis zum Ende des Universums.
|
||||
Bei Serien schrumpft die Restzeit anteilig mit den gesehenen Episoden.
|
||||
- **Teilen** mit anderen Konten der Instanz, wahlweise nur zum Ansehen oder
|
||||
zum gemeinsamen Pflegen. Der Fortschritt ist dabei immer der des
|
||||
jeweiligen Betrachters — ein geteiltes Universum zeigt jeder Person ihren
|
||||
eigenen Stand. Löschen bleibt dem Besitzer vorbehalten.
|
||||
- **12 weitere Tests** für Reihenfolgen, Fortschrittsberechnung über Filme und
|
||||
Serien hinweg, Freigaben und die Rechteprüfung.
|
||||
- Beispieluniversum im Seed: die Sternenpfad-Reihe mit fünf Filmen, zwei
|
||||
Serien und einer abweichenden Story-Chronologie.
|
||||
|
||||
### Behoben
|
||||
|
||||
- Die Posterkachel zog über `lib/images.ts` die serverseitige Cache-Logik in
|
||||
den Browser-Bundle, sobald sie aus einer Client-Komponente heraus gerendert
|
||||
wurde — der Build brach ab, sobald eine solche Seite dazukam. Die reine
|
||||
URL-Bildung liegt jetzt in `lib/image-url.ts`, der Dateicache bleibt
|
||||
serverseitig.
|
||||
|
||||
## [0.3.0] — 2026-09-01
|
||||
|
||||
Das Kernstück: Bibliothek, Status und Episodenfortschritt.
|
||||
@@ -132,7 +168,8 @@ Erste lauffähige Etappe: Gerüst, Marke, Datenmodell und Anmeldung.
|
||||
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.3.0...HEAD
|
||||
[Unveröffentlicht]: https://git.wilde-server.de/florian.wilde/flimmer/compare/v0.4.0...HEAD
|
||||
[0.4.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.4.0
|
||||
[0.3.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.3.0
|
||||
[0.2.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.2.0
|
||||
[0.1.0]: https://git.wilde-server.de/florian.wilde/flimmer/releases/tag/v0.1.0
|
||||
|
||||
@@ -49,6 +49,19 @@ Alle Zeiten per `date`-Befehl erfasst (Europe/Berlin), nicht geschätzt.
|
||||
|
||||
---
|
||||
|
||||
## Etappe 4 — Universen mit Reihenfolgen und Fortschritt (v0.4.0)
|
||||
|
||||
| # | Start | Ende | Dauer | Arbeitsschritt |
|
||||
|---|---|---|---|---|
|
||||
| 4.1 | 19:25 | 19:30 | 5 min | Domänenlogik: Universen, berechnete Erscheinungsreihenfolge, frei sortierbare Reihenfolgen, Fortschritt aus Sicht des Betrachters, Freigaben |
|
||||
| 4.2 | 19:30 | 19:33 | 3 min | 12 Tests dazu; eine falsche Testannahme zur Reihenfolge korrigiert (nicht den Code) |
|
||||
| 4.3 | 19:33 | 19:36 | 3 min | Server-Aktionen, sortierbare Liste mit Ziehen und Pfeilknöpfen, Reihenfolge-Umschalter, Aufnehmen, Teilen |
|
||||
| 4.4 | 19:36 | 19:39 | 3 min | Seiten für Übersicht, Anlegen und Detailansicht; Build-Fehler durch `server-only` im Browser-Bundle gefunden und behoben; Umsortieren im Browser geprüft |
|
||||
|
||||
**Etappe 4 gesamt: 14 min** (2026-09-01, 19:25 – 19:39)
|
||||
|
||||
---
|
||||
|
||||
## Gesamtübersicht
|
||||
|
||||
| Etappe | Version | Dauer |
|
||||
@@ -56,5 +69,6 @@ Alle Zeiten per `date`-Befehl erfasst (Europe/Berlin), nicht geschätzt.
|
||||
| 1 — Gerüst, Branding, Docker, Schema, Auth | 0.1.0 | 38 min |
|
||||
| 2 — TMDB-Anbindung | 0.2.0 | 14 min |
|
||||
| 3 — Kern-Tracking | 0.3.0 | 24 min |
|
||||
| 4 — Universen | 0.4.0 | 14 min |
|
||||
|
||||
**Bisher gesamt: 76 min**
|
||||
**Bisher gesamt: 90 min**
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "flimmer",
|
||||
"version": "0.3.0",
|
||||
"version": "0.4.0",
|
||||
"private": true,
|
||||
"description": "Flimmer — selbst hostbarer Serien- und Film-Tracker",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -458,6 +458,73 @@ async function seedLibrary(userId: string, titleIds: Map<string, string>) {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Universum
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Die Erscheinungsreihenfolge berechnet Flimmer selbst — hier steht nur die
|
||||
* abweichende Story-Chronologie, damit die Seite zwei echte Reihenfolgen zeigt.
|
||||
*/
|
||||
const CHRONOLOGICAL = [
|
||||
"sternenpfad-null",
|
||||
"sternenpfad-1",
|
||||
"sternenpfad-akademie",
|
||||
"sternenpfad-2",
|
||||
"sternenpfad-serie",
|
||||
"sternenpfad-3",
|
||||
"sternenpfad-4",
|
||||
];
|
||||
|
||||
async function seedUniverse(ownerId: string, titleIds: Map<string, string>) {
|
||||
const existing = await prisma.universe.findUnique({
|
||||
where: { ownerId_slug: { ownerId, slug: "sternenpfad" } },
|
||||
select: { id: true },
|
||||
});
|
||||
if (existing) {
|
||||
await prisma.universe.delete({ where: { id: existing.id } });
|
||||
}
|
||||
|
||||
const universe = await prisma.universe.create({
|
||||
data: {
|
||||
ownerId,
|
||||
name: "Sternenpfad",
|
||||
slug: "sternenpfad",
|
||||
description:
|
||||
"Fünf Filme und zwei Serien. Die Kinoreihenfolge und die Story-Chronologie gehen auseinander — deshalb zwei Reihenfolgen.",
|
||||
orders: {
|
||||
create: [{ name: "Erscheinungsreihenfolge", kind: "RELEASE", isDefault: true }],
|
||||
},
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
const itemIdByKey = new Map<string, string>();
|
||||
for (const key of CHRONOLOGICAL) {
|
||||
const titleId = titleIds.get(key);
|
||||
if (!titleId) continue;
|
||||
const item = await prisma.universeItem.create({
|
||||
data: { universeId: universe.id, titleId },
|
||||
select: { id: true },
|
||||
});
|
||||
itemIdByKey.set(key, item.id);
|
||||
}
|
||||
|
||||
const order = await prisma.universeOrder.create({
|
||||
data: { universeId: universe.id, name: "Chronologisch", kind: "CUSTOM" },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
await prisma.universeOrderItem.createMany({
|
||||
data: CHRONOLOGICAL.flatMap((key, index) => {
|
||||
const itemId = itemIdByKey.get(key);
|
||||
return itemId ? [{ orderId: order.id, itemId, position: index }] : [];
|
||||
}),
|
||||
});
|
||||
|
||||
return universe;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function main() {
|
||||
@@ -509,6 +576,15 @@ async function main() {
|
||||
console.log("Seed: Bibliothek und Sichtungen ...");
|
||||
await seedLibrary(admin.id, titleIds);
|
||||
|
||||
console.log("Seed: Universum ...");
|
||||
const universe = await seedUniverse(admin.id, titleIds);
|
||||
// Mit dem zweiten Konto teilen, damit die Freigabe sichtbar ist.
|
||||
await prisma.universeMember.upsert({
|
||||
where: { universeId_userId: { universeId: universe.id, userId: friend.id } },
|
||||
create: { universeId: universe.id, userId: friend.id, permission: "READ" },
|
||||
update: {},
|
||||
});
|
||||
|
||||
const watches = await prisma.watch.count({ where: { userId: admin.id } });
|
||||
const entries = await prisma.libraryEntry.count({ where: { userId: admin.id } });
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Flimmer 0.4.0
|
||||
|
||||
Universen: zusammengehörige Titel, mehrere Reihenfolgen, ein Gesamtfortschritt.
|
||||
|
||||
### Hinzugefügt
|
||||
|
||||
- **Universen** aus beliebigen Filmen **und** Serien — MCU, Star Wars,
|
||||
Wizarding World oder was auch immer zusammengehört.
|
||||
- **Mehrere Reihenfolgen je Universum**. Die Erscheinungsreihenfolge wird aus
|
||||
den Erscheinungsdaten berechnet und nie gespeichert — sie stimmt damit immer.
|
||||
Weitere Reihenfolgen (Story-Chronologie, Einsteiger-Route) sind frei
|
||||
sortierbar, per Ziehen **und** über Pfeilknöpfe. Reines Drag & Drop wäre mit
|
||||
Tastatur nicht bedienbar und auf dem Handy fummelig.
|
||||
- **TMDB-Collections als Startpunkt**: Reihen, die in der eigenen Bibliothek
|
||||
vorkommen, lassen sich mit einem Klick übernehmen.
|
||||
- **Universums-Detailseite** mit nummerierter Liste, Gesamtfortschritt
|
||||
(„4 von 7 abgeschlossen, 21 h 21 min gesehen"), hervorgehobenem
|
||||
„Als Nächstes dran" und der Restlaufzeit bis zum Ende des Universums.
|
||||
Bei Serien schrumpft die Restzeit anteilig mit den gesehenen Episoden.
|
||||
- **Teilen** mit anderen Konten der Instanz, wahlweise nur zum Ansehen oder
|
||||
zum gemeinsamen Pflegen. Der Fortschritt ist dabei immer der des
|
||||
jeweiligen Betrachters — ein geteiltes Universum zeigt jeder Person ihren
|
||||
eigenen Stand. Löschen bleibt dem Besitzer vorbehalten.
|
||||
- **12 weitere Tests** für Reihenfolgen, Fortschrittsberechnung über Filme und
|
||||
Serien hinweg, Freigaben und die Rechteprüfung.
|
||||
- Beispieluniversum im Seed: die Sternenpfad-Reihe mit fünf Filmen, zwei
|
||||
Serien und einer abweichenden Story-Chronologie.
|
||||
|
||||
### Behoben
|
||||
|
||||
- Die Posterkachel zog über `lib/images.ts` die serverseitige Cache-Logik in
|
||||
den Browser-Bundle, sobald sie aus einer Client-Komponente heraus gerendert
|
||||
wurde — der Build brach ab, sobald eine solche Seite dazukam. Die reine
|
||||
URL-Bildung liegt jetzt in `lib/image-url.ts`, der Dateicache bleibt
|
||||
serverseitig.
|
||||
@@ -0,0 +1,20 @@
|
||||
import { chromium } from "playwright";
|
||||
const [,, SP, ...specs] = process.argv;
|
||||
const b = await chromium.launch();
|
||||
const c = await b.newContext({ viewport: { width: 1280, height: 950 }, deviceScaleFactor: 2, colorScheme: "dark" });
|
||||
const p = await c.newPage();
|
||||
const errs = [];
|
||||
p.on("pageerror", e => errs.push(String(e).slice(0,200)));
|
||||
p.on("console", m => { if (m.type()==="error") errs.push("console: "+m.text().slice(0,160)); });
|
||||
await p.goto("http://localhost:3011/anmelden");
|
||||
await p.fill("#email", "demo@flimmer.local");
|
||||
await p.fill("#password", "flimmer-demo-2026");
|
||||
await Promise.all([p.waitForURL("http://localhost:3011/"), p.click("button[type=submit]")]);
|
||||
for (const spec of specs) {
|
||||
const [name, url, full] = spec.split("|");
|
||||
await p.goto(`http://localhost:3011${url}`, { waitUntil: "networkidle" });
|
||||
await p.waitForTimeout(900);
|
||||
await p.screenshot({ path: `${SP}/${name}.png`, fullPage: full === "full" });
|
||||
}
|
||||
console.log("Fehler:", errs.length ? errs.slice(0,4) : "keine");
|
||||
await b.close();
|
||||
Reference in New Issue
Block a user