Universen: Standardreihenfolge festlegen können #4

Closed
opened 2026-09-01 21:01:00 +00:00 by florian.wilde · 4 comments
Owner

Worum es geht

Ein Universum kann mehrere Reihenfolgen haben. Welche beim Öffnen erscheint, lässt sich aber nicht bestimmen — es ist immer die Erscheinungsreihenfolge. Wer sich eine Story-Chronologie oder eine Einsteiger-Route gebaut hat, muss sie bei jedem Aufruf erst anklicken.

Gerade bei Universen wie Sternenpfad ist die selbst gebaute Reihenfolge ja der eigentliche Grund, warum man sie angelegt hat.

Was schon da ist

Das Datenmodell trägt die Information bereits, und sie wird auch ausgewertet:

  • UniverseOrder.isDefault (prisma/schema.prisma:445)
  • getUniverse() wählt die aktive Reihenfolge in dieser Rangfolge (src/lib/universes.ts:400):
    1. die per URL angeforderte (?reihenfolge=…)
    2. die mit isDefault
    3. die erste

Gesetzt wird isDefault allerdings nur an einer Stelle: beim Anlegen des Universums für die automatisch erzeugte Erscheinungsreihenfolge (src/lib/universes.ts:94). createOrder() setzt es nie, und es gibt keine Funktion, keine Server-Aktion und keinen Knopf, um es zu ändern.

Es fehlt also nur der Weg dorthin, nicht das Fundament.

Zu entscheiden: geteilt oder persönlich?

Reihenfolgen gehören dem Universum und sind bei geteilten Universen für alle sichtbar. Die Standardreihenfolge kann man auf zwei Arten verstehen:

a) Eigenschaft des Universums (Empfehlung). Wer Schreibrecht hat, legt sie fest; sie gilt für alle. Passt dazu, dass die Reihenfolgen selbst auch geteilt sind, und ist mit einem Feld erledigt, das es schon gibt.

b) Vorliebe je Person. Jede Person hat ihre eigene. Ehrlicher bei geteilten Universen, kostet aber eine zusätzliche Tabelle und wirft die Frage auf, was gilt, wenn jemand nie etwas ausgewählt hat.

Vorschlag: (a), und als leichte persönliche Ergänzung merkt sich der Browser die zuletzt gewählte Reihenfolge je Universum. Wer bewusst umschaltet, landet beim nächsten Mal wieder dort, ohne dass das für andere etwas ändert. Die URL schlägt weiterhin alles.

Umzusetzen

  • setDefaultOrder(userId, orderId) in src/lib/universes.ts, mit requireWrite
  • Invariante: je Universum genau ein isDefault. Das Setzen muss in einer Transaktion das alte zurücksetzen, sonst gibt es zwei und find() entscheidet nach Zufall der Sortierung.
  • Server-Aktion und Knopf in OrderTabs (src/components/universes/UniverseTools.tsx) — etwa ein „Als Standard" neben der aktiven Reihenfolge, und ein Häkchen an der, die es schon ist
  • Über die REST-API mitnehmen

Randfall, der heute noch nicht auffällt

deleteOrder() löscht eine eigene Reihenfolge, ohne isDefault anzufassen (src/lib/universes.ts:253). Solange nur die Erscheinungsreihenfolge Standard sein kann, ist das harmlos. Sobald man eine eigene zum Standard machen kann, hinterlässt das Löschen ein Universum ohne Standard — dann greift zwar noch die dritte Stufe („die erste"), aber das ist Zufall statt Absicht. Beim Löschen muss der Standard auf die Erscheinungsreihenfolge zurückfallen.

Abnahme

  • Eine eigene Reihenfolge lässt sich zum Standard machen, die vorherige verliert die Markierung
  • Beim Öffnen des Universums erscheint diese Reihenfolge, ohne Klick
  • ?reihenfolge=… in der Adresse schlägt den Standard weiterhin
  • Wird die Standardreihenfolge gelöscht, fällt der Standard auf die Erscheinungsreihenfolge zurück
  • Nur mit Schreibrecht änderbar; Leseberechtigte sehen den Standard, können ihn aber nicht setzen
  • Es gibt zu keinem Zeitpunkt zwei Standardreihenfolgen in einem Universum (Test)

Aufwand

Klein bis mittel — eine Funktion mit Transaktion, eine Aktion, ein Knopf, zwei Tests. Das Datenmodell bleibt unangetastet.


Angelegt auf ausdrücklichen Wunsch direkt in Gitea, ohne Verknüpfung zu einem Nebula-Task.

## Worum es geht Ein Universum kann mehrere Reihenfolgen haben. Welche beim Öffnen erscheint, lässt sich aber nicht bestimmen — es ist immer die Erscheinungsreihenfolge. Wer sich eine Story-Chronologie oder eine Einsteiger-Route gebaut hat, muss sie bei jedem Aufruf erst anklicken. Gerade bei Universen wie Sternenpfad ist die selbst gebaute Reihenfolge ja der eigentliche Grund, warum man sie angelegt hat. ## Was schon da ist Das Datenmodell trägt die Information bereits, und sie wird auch ausgewertet: - `UniverseOrder.isDefault` (`prisma/schema.prisma:445`) - `getUniverse()` wählt die aktive Reihenfolge in dieser Rangfolge (`src/lib/universes.ts:400`): 1. die per URL angeforderte (`?reihenfolge=…`) 2. die mit `isDefault` 3. die erste Gesetzt wird `isDefault` allerdings nur an einer Stelle: beim Anlegen des Universums für die automatisch erzeugte Erscheinungsreihenfolge (`src/lib/universes.ts:94`). `createOrder()` setzt es nie, und es gibt keine Funktion, keine Server-Aktion und keinen Knopf, um es zu ändern. **Es fehlt also nur der Weg dorthin, nicht das Fundament.** ## Zu entscheiden: geteilt oder persönlich? Reihenfolgen gehören dem Universum und sind bei geteilten Universen für alle sichtbar. Die Standardreihenfolge kann man auf zwei Arten verstehen: **a) Eigenschaft des Universums (Empfehlung).** Wer Schreibrecht hat, legt sie fest; sie gilt für alle. Passt dazu, dass die Reihenfolgen selbst auch geteilt sind, und ist mit einem Feld erledigt, das es schon gibt. **b) Vorliebe je Person.** Jede Person hat ihre eigene. Ehrlicher bei geteilten Universen, kostet aber eine zusätzliche Tabelle und wirft die Frage auf, was gilt, wenn jemand nie etwas ausgewählt hat. Vorschlag: **(a)**, und als leichte persönliche Ergänzung merkt sich der Browser die zuletzt gewählte Reihenfolge je Universum. Wer bewusst umschaltet, landet beim nächsten Mal wieder dort, ohne dass das für andere etwas ändert. Die URL schlägt weiterhin alles. ## Umzusetzen - `setDefaultOrder(userId, orderId)` in `src/lib/universes.ts`, mit `requireWrite` - **Invariante:** je Universum genau ein `isDefault`. Das Setzen muss in einer Transaktion das alte zurücksetzen, sonst gibt es zwei und `find()` entscheidet nach Zufall der Sortierung. - Server-Aktion und Knopf in `OrderTabs` (`src/components/universes/UniverseTools.tsx`) — etwa ein „Als Standard" neben der aktiven Reihenfolge, und ein Häkchen an der, die es schon ist - Über die REST-API mitnehmen ## Randfall, der heute noch nicht auffällt `deleteOrder()` löscht eine eigene Reihenfolge, ohne `isDefault` anzufassen (`src/lib/universes.ts:253`). Solange nur die Erscheinungsreihenfolge Standard sein kann, ist das harmlos. Sobald man eine eigene zum Standard machen kann, hinterlässt das Löschen ein Universum ohne Standard — dann greift zwar noch die dritte Stufe („die erste"), aber das ist Zufall statt Absicht. Beim Löschen muss der Standard auf die Erscheinungsreihenfolge zurückfallen. ## Abnahme - [ ] Eine eigene Reihenfolge lässt sich zum Standard machen, die vorherige verliert die Markierung - [ ] Beim Öffnen des Universums erscheint diese Reihenfolge, ohne Klick - [ ] `?reihenfolge=…` in der Adresse schlägt den Standard weiterhin - [ ] Wird die Standardreihenfolge gelöscht, fällt der Standard auf die Erscheinungsreihenfolge zurück - [ ] Nur mit Schreibrecht änderbar; Leseberechtigte sehen den Standard, können ihn aber nicht setzen - [ ] Es gibt zu keinem Zeitpunkt zwei Standardreihenfolgen in einem Universum (Test) ## Aufwand Klein bis mittel — eine Funktion mit Transaktion, eine Aktion, ein Knopf, zwei Tests. Das Datenmodell bleibt unangetastet. --- *Angelegt auf ausdrücklichen Wunsch direkt in Gitea, ohne Verknüpfung zu einem Nebula-Task.*
florian.wilde added the in-arbeit label 2026-09-01 21:34:54 +00:00
florian.wilde started working 2026-09-01 21:35:02 +00:00
Author
Owner

🤖 Claude Code hat mit der Umsetzung begonnen.

  • Branch: feat/4-standardreihenfolge
  • Verstanden als: Wer Schreibrecht an einem Universum hat, bestimmt, welche Reihenfolge beim Öffnen erscheint — Variante (a) aus der Beschreibung, der Standard ist also eine Eigenschaft des Universums und gilt für alle, die es sehen.
  • Geplantes Vorgehen:
    • setDefaultOrder() mit requireWrite, das Umsetzen in einer Transaktion, damit nie zwei Standards nebeneinander stehen
    • deleteOrder() so ergänzen, dass der Standard auf die Erscheinungsreihenfolge zurückfällt, wenn die Standardreihenfolge gelöscht wird
    • Server-Aktion und Knopf „Als Standard" in den Reitern, mit Markierung an der aktuellen
    • Über die REST-API erreichbar machen, dazu Tests für die Invariante und den Rückfall

Was ich bewusst weglasse: die im Vorschlag erwähnte Browser-Erinnerung an die zuletzt gewählte Reihenfolge. Sie wäre eine dritte, unsichtbare Quelle neben URL und Standard — schwer nachzuvollziehen, wenn zwei Leute dasselbe Universum unterschiedlich sehen. Die Rangfolge bleibt damit die schlichte: URL schlägt Standard schlägt erste. Sag Bescheid, wenn du sie trotzdem willst, dann kommt sie separat.

Zeiterfassung läuft.

🤖 **Claude Code hat mit der Umsetzung begonnen.** - Branch: `feat/4-standardreihenfolge` - Verstanden als: Wer Schreibrecht an einem Universum hat, bestimmt, welche Reihenfolge beim Öffnen erscheint — Variante **(a)** aus der Beschreibung, der Standard ist also eine Eigenschaft des Universums und gilt für alle, die es sehen. - Geplantes Vorgehen: - `setDefaultOrder()` mit `requireWrite`, das Umsetzen in einer Transaktion, damit nie zwei Standards nebeneinander stehen - `deleteOrder()` so ergänzen, dass der Standard auf die Erscheinungsreihenfolge zurückfällt, wenn die Standardreihenfolge gelöscht wird - Server-Aktion und Knopf „Als Standard" in den Reitern, mit Markierung an der aktuellen - Über die REST-API erreichbar machen, dazu Tests für die Invariante und den Rückfall **Was ich bewusst weglasse:** die im Vorschlag erwähnte Browser-Erinnerung an die zuletzt gewählte Reihenfolge. Sie wäre eine dritte, unsichtbare Quelle neben URL und Standard — schwer nachzuvollziehen, wenn zwei Leute dasselbe Universum unterschiedlich sehen. Die Rangfolge bleibt damit die schlichte: URL schlägt Standard schlägt erste. Sag Bescheid, wenn du sie trotzdem willst, dann kommt sie separat. Zeiterfassung läuft.
florian.wilde worked for 14 minutes 2026-09-01 21:49:58 +00:00
florian.wilde added zu-testen and removed in-arbeit labels 2026-09-01 21:50:40 +00:00
Author
Owner

✅ Umsetzung abgeschlossen — bereit zum Testen.

Was geändert wurde

  • setDefaultOrder() mit requireWrite; Zurücksetzen und Setzen in einer Transaktion, damit nie zwei Standards nebeneinander stehen
  • deleteOrder() fängt den Rückfall ab: wird die Standardreihenfolge gelöscht, übernimmt die Erscheinungsreihenfolge
  • Knopf „Als Standard festlegen" neben den Reitern (nur mit Schreibrecht, nur wenn die aktive Reihenfolge nicht schon Standard ist); die Standardreihenfolge trägt ein Häkchen, für Screenreader steht „(Standard)" dahinter
  • PATCH /api/v1/universen/{id} samt Prüfung, dass die Reihenfolge zu diesem Universum gehört — ohne die setzte ein PATCH auf A den Standard in B
  • docs/API.md und openapi.json nachgezogen

Geänderte Dateien

  • src/lib/universes.ts
  • src/app/actions/universes.ts
  • src/components/universes/UniverseTools.tsx
  • src/app/api/v1/universen/[id]/route.ts
  • src/app/api/v1/openapi.json/route.ts
  • docs/API.md
  • tests/universes.test.ts

Geprüft

56 Tests grün (vier neue), Typecheck sauber. Klickweg und Endpunkt zusätzlich gegen einen Produktionsbau durchgespielt:

Schritt Ergebnis
Knopf klicken 200, Meldung „Standardreihenfolge gesetzt", Häkchen wandert
Universum ohne Parameter öffnen die neue Standardreihenfolge führt
?reihenfolge=… schlägt den Standard weiterhin
PATCH mit fremder Reihenfolge 404, Standard unverändert
PATCH mit eigener Reihenfolge 200, activeOrderId folgt

So testest du es

  1. git switch feat/4-standardreihenfolge
  2. npm run dev (Port 3011), ein Universum mit mehreren Reihenfolgen öffnen
  3. Eine eigene Reihenfolge anklicken → rechts erscheint „Als Standard festlegen". Klicken.
  4. Erwartet: Das Häkchen wandert auf diese Reihenfolge. Universum ohne ?reihenfolge= neu öffnen → sie führt jetzt.
  5. Gegenprobe: ?reihenfolge=<andere> in der Adresse gewinnt weiterhin.
  6. Die Standardreihenfolge löschen → das Häkchen fällt auf die Erscheinungsreihenfolge zurück.

Bewusst nicht umgesetzt: die Browser-Erinnerung an die zuletzt gewählte Reihenfolge (siehe Startkommentar). Sag Bescheid, wenn du sie doch willst.

Aufgewendete Zeit: 00:15
Pull Request: #8

Nach Freigabe: /issue-freigabe 4

✅ **Umsetzung abgeschlossen — bereit zum Testen.** <!-- claude-status branch: feat/4-standardreihenfolge pr: 8 zeit_sekunden: 896 --> **Was geändert wurde** - `setDefaultOrder()` mit `requireWrite`; Zurücksetzen und Setzen in einer Transaktion, damit nie zwei Standards nebeneinander stehen - `deleteOrder()` fängt den Rückfall ab: wird die Standardreihenfolge gelöscht, übernimmt die Erscheinungsreihenfolge - Knopf „Als Standard festlegen" neben den Reitern (nur mit Schreibrecht, nur wenn die aktive Reihenfolge nicht schon Standard ist); die Standardreihenfolge trägt ein Häkchen, für Screenreader steht „(Standard)" dahinter - `PATCH /api/v1/universen/{id}` samt Prüfung, dass die Reihenfolge zu diesem Universum gehört — ohne die setzte ein PATCH auf A den Standard in B - `docs/API.md` und `openapi.json` nachgezogen **Geänderte Dateien** - `src/lib/universes.ts` - `src/app/actions/universes.ts` - `src/components/universes/UniverseTools.tsx` - `src/app/api/v1/universen/[id]/route.ts` - `src/app/api/v1/openapi.json/route.ts` - `docs/API.md` - `tests/universes.test.ts` **Geprüft** 56 Tests grün (vier neue), Typecheck sauber. Klickweg und Endpunkt zusätzlich gegen einen Produktionsbau durchgespielt: | Schritt | Ergebnis | |---|---| | Knopf klicken | 200, Meldung „Standardreihenfolge gesetzt", Häkchen wandert | | Universum ohne Parameter öffnen | die neue Standardreihenfolge führt | | `?reihenfolge=…` | schlägt den Standard weiterhin | | `PATCH` mit fremder Reihenfolge | 404, Standard unverändert | | `PATCH` mit eigener Reihenfolge | 200, `activeOrderId` folgt | **So testest du es** 1. `git switch feat/4-standardreihenfolge` 2. `npm run dev` (Port 3011), ein Universum mit mehreren Reihenfolgen öffnen 3. Eine eigene Reihenfolge anklicken → rechts erscheint „Als Standard festlegen". Klicken. 4. Erwartet: Das Häkchen wandert auf diese Reihenfolge. Universum ohne `?reihenfolge=` neu öffnen → sie führt jetzt. 5. Gegenprobe: `?reihenfolge=<andere>` in der Adresse gewinnt weiterhin. 6. Die Standardreihenfolge löschen → das Häkchen fällt auf die Erscheinungsreihenfolge zurück. **Bewusst nicht umgesetzt:** die Browser-Erinnerung an die zuletzt gewählte Reihenfolge (siehe Startkommentar). Sag Bescheid, wenn du sie doch willst. **Aufgewendete Zeit:** 00:15 **Pull Request:** #8 Nach Freigabe: `/issue-freigabe 4`
Author
Owner

📝 Nebenbei aufgefallen — gehört nicht in diesen PR, hier festgehalten:

Klickwege lassen sich im Entwicklungsmodus nicht mit Playwright prüfen. Beim Verifizieren fiel auf, dass unter headless Chromium gegen npm run dev keine einzige Seite hydratisiert — kein Reiter, kein Knopf, nicht einmal der Theme-Umschalter im Kopf. Ursache ist der HMR-Socket: ws://127.0.0.1:3011/_next/hmr scheitert mit ERR_INVALID_HTTP_RESPONSE, und damit kommt die React-Wurzel nicht hoch. Es gibt dabei keinen Seitenfehler und keine fehlgeschlagene Anfrage — es passiert einfach nichts, was zunächst wie ein Fehler im eigenen Code aussieht.

Nachgewiesen: derselbe Klickweg gegen npm run build && npm start funktioniert vollständig.

Zwei Folgerungen:

  1. Die laufende Instanz ist nicht betroffen — dort läuft kein HMR.
  2. Wer künftig einen Klickweg automatisiert prüft, sollte das gegen einen Produktionsbau tun, nicht gegen den Entwicklungsserver. Das wäre eine gute Zeile für CLAUDE.md unter „Nützliches für spätere Arbeiten".

Formulare sind übrigens nicht betroffen (die Anmeldung funktioniert auch ohne JavaScript) — das verschleiert das Problem zusätzlich.

📝 **Nebenbei aufgefallen** — gehört nicht in diesen PR, hier festgehalten: **Klickwege lassen sich im Entwicklungsmodus nicht mit Playwright prüfen.** Beim Verifizieren fiel auf, dass unter headless Chromium gegen `npm run dev` **keine einzige Seite hydratisiert** — kein Reiter, kein Knopf, nicht einmal der Theme-Umschalter im Kopf. Ursache ist der HMR-Socket: `ws://127.0.0.1:3011/_next/hmr` scheitert mit `ERR_INVALID_HTTP_RESPONSE`, und damit kommt die React-Wurzel nicht hoch. Es gibt dabei keinen Seitenfehler und keine fehlgeschlagene Anfrage — es passiert einfach nichts, was zunächst wie ein Fehler im eigenen Code aussieht. Nachgewiesen: derselbe Klickweg gegen `npm run build && npm start` funktioniert vollständig. Zwei Folgerungen: 1. **Die laufende Instanz ist nicht betroffen** — dort läuft kein HMR. 2. Wer künftig einen Klickweg automatisiert prüft, sollte das **gegen einen Produktionsbau** tun, nicht gegen den Entwicklungsserver. Das wäre eine gute Zeile für `CLAUDE.md` unter „Nützliches für spätere Arbeiten". Formulare sind übrigens nicht betroffen (die Anmeldung funktioniert auch ohne JavaScript) — das verschleiert das Problem zusätzlich.
Author
Owner

🚀 Freigegeben und nach main übernommen.

  • Merge-Commit: 5673055
  • Pull Request: #8 (gemergt)
  • Gesamtaufwand: 00:15

Vor dem Merge noch einmal geprüft: Typecheck sauber, 56 Tests grün.

Issue wird geschlossen.

🚀 **Freigegeben und nach `main` übernommen.** <!-- claude-status merge: 56730552161d4b9fdba28423d4cd6e078f5d4f61 pr: 8 zeit_sekunden: 896 --> - Merge-Commit: `5673055` - Pull Request: #8 (gemergt) - Gesamtaufwand: 00:15 Vor dem Merge noch einmal geprüft: Typecheck sauber, 56 Tests grün. Issue wird geschlossen.
florian.wilde removed the zu-testen label 2026-09-01 21:53:49 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Total Time Spent: 14 minutes
florian.wilde
14 minutes
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: florian.wilde/flimmer#4