Projekt: Online Novel Lib
Komponente: Frontend (Kotlin Multiplatform)
Stand: 23.09.2026
Basis: anforderungen-frontend.md (vollständige fachliche/technische Anforderungen), abgeglichen gegen den tatsächlichen Stand von api/openapi.yaml und iterationplan-backend.md nach der Vertragsbereinigung vom 22.09.2026.
Plattform-Änderung nach Iteration 0. Die ursprüngliche Iteration 0 (siehe specs/progress-frontend/iteration-0.md) zielte auf Android, iOS und Desktop. Auf Wunsch wurde das Desktop-Target durch ein Web-Target (Compose Multiplatform for Web, Kotlin/Wasm) ersetzt, bevor eine der Fach-Iterationen begonnen wurde: Web bietet denselben schnellen, emulatorlosen Blick ins UI wie Desktop, läuft aber im Browser ohne separates natives Artefakt. desktopApp wurde aus dem Projekt entfernt; alle folgenden Verweise auf die „drei Zielplattformen” meinen ab hier Android, iOS und Web.
Android ist die primäre Zielplattform. Es steht aktuell kein Mac zur Verfügung, daher wird in jeder Iteration zuerst auf Android real verifiziert (siehe anforderungen-frontend.md, Abschnitt 2). Web dient als sekundäre, ebenfalls im Dev-Setup sofort lauffähige Plattform. iOS-Code entsteht parallel im gemeinsamen commonMain und muss kompilieren, eine Laufzeitverifikation auf Simulator/Gerät ist jedoch erst möglich, sobald ein Mac verfügbar ist – „Definition of Done” je Iteration unterscheidet deshalb zwischen den auf Android/Web tatsächlich nachgewiesenen Kriterien und dem für iOS nur zugesicherten Kompilieren.
Dieses Dokument gliedert die in anforderungen-frontend.md beschriebenen Anforderungen in aufeinander aufbauende Iterationsstufen, die jeweils als eigenständiges, auf allen drei Zielplattformen (Android, iOS, Web) lauffähiges Inkrement entwickelt werden können. Die Reihenfolge orientiert sich an derselben Logik wie im Backend-Iterationsplan (iterationplan-backend.md): zuerst ein Multiplatform-Grundgerüst, dann Auth, dann die Kernlese-/Autorenfunktionen, danach Bibliothek/Sync, Offline-Robustheit, Moderation/Admin und zuletzt UX-Politur. Jede Iteration setzt voraus, dass die fachlich passende Backend-Iteration bereits existiert oder parallel entsteht; die jeweilige Abhängigkeit ist pro Stufe vermerkt.
Warum dieses Dokument überarbeitet wurde. Die vorherige Fassung war gegen den Vertragsstand vor der Bereinigung vom 22.09.2026 geschrieben (u. a. slug-/chapterNumber-basiertes Routing, ein ChapterDetail mit eingebettetem content, den Pfad /users/me/... statt /user/me/..., sowie become-author statt des in Iteration 4.5 eingeführten RoleRequest-Flows). Da der Backend-Teil inzwischen bis einschließlich Iteration 4.5 abgeschlossen ist (siehe iterationplan-backend.md) und dabei mehrere dieser Vertragsdetails bewusst geändert wurden, war der alte Frontend-Plan an genau den Stellen falsch, an denen ein Frontend-Entwickler ihn am ehesten wörtlich nehmen würde. Die folgenden Punkte sind die tatsächlich verbindliche Grundlage (Quelle: api/openapi.yaml):
id adressiert, nicht über slug/chapterNumber. Wer nur einen Slug (geteilter Link) oder eine Kapitelnummer kennt, löst sie über GET /novels/slug/{novelSlug} bzw. GET /novels/{novelId}/chapters/number/{chapterNumber} auf – beide liefern direkt die vollständige Ressource, kein zweiter Roundtrip nötig.Novel ein (ohne description), ein Einzelabruf liefert ein flaches NovelDetail mit den Novel-Feldern, description und authors. Eine Detailseite muss also immer GET /novels/{novelId} (bzw. GET /novels/slug/{novelSlug}) separat aufrufen, auch wenn der Nutzer aus einer Liste kommt, in der das Novel schon einmal (schlank) geladen wurde.NovelDetail.authors und die Autorenverwaltungsantworten verwenden NovelAuthor mit eingebettetem authorRef. Zum Hinzufügen sucht der Client zuerst über GET /users?username=... und sendet danach AddNovelAuthorRequest.userId; der alte username-basierte Request ist nicht mehr gültig.ChapterDetail trägt keinen Text mehr. GET/POST/PATCH auf ein Kapitel liefern nur Metadaten (inkl. previousChapter/nextChapter und der eingebetteten NovelReference mit chapterCount). Der eigentliche Lesetext kommt ausschließlich über die Seiten-Endpunkte (GET .../chapters/{chapterId}/parts bzw. .../parts/{partNumber}) – siehe Iteration 2.4./user/me/... (Singular „user”), nicht /users/me/....become-author. „Autor werden” ruft POST /user/me/role-requests auf (aktuell sofort automatisch genehmigt); der bisherige POST /user/me/become-author existiert nicht mehr.PUT (nicht POST), multipart, idempotent, mit optionalem If-Match-Header aus einem zuvor gelesenen ETag.userId, kein Fallback auf username.Die aus anforderungen-frontend.md, Abschnitt 14 bekannten „Offenen Punkte” (Web-Target, OAuth-/Social-Login-UI, vollständiger Offline-Download ganzer Novels, Kommentare/Bewertungen, Push-Benachrichtigungen, „Passwort vergessen”) sind bewusst in keiner der folgenden Iterationen enthalten und bilden weiterhin einen späteren Backlog nach Abschluss von Iteration 7.
| # | Titel | Kernziel | Passende Backend-Iteration | Backend-Status |
|---|---|---|---|---|
| 0 | Projekt-Grundgerüst & Multiplatform-Setup | Lauffähige App auf Android/iOS/Web mit Verbindungstest zum Backend | 0 | abgeschlossen |
| 1 | Auth & Session-Handling | Registrierung, Login, sicherer Token-Speicher, Auto-Refresh | 1 | abgeschlossen |
| 2.1 | Katalog (Entdecken) | Novels durchsuchen, filtern, paginieren | 3 | abgeschlossen |
| 2.2 | Startseite | Startseite als App-Einstieg mit app-weiter oberer Navigationsleiste (Suche, Profil/Login-Avatar) auf allen Screens | – | – |
| 2.3 | Novel-Detail | Volle Novel-Ansicht inkl. Synopse, Autorenliste, Kapitelliste | 3 | abgeschlossen |
| 2.4 | Leseansicht (Reader inkl. Kapitel-Seiten) | Kapitel seitenweise lesen, Kapitel-/Seiten-Navigation, Reader-Settings | 2.5, 3, 3.5 | abgeschlossen |
| 3.1 | Rollen-Selbstantrag (“Autor werden”) | Autorenrolle per Self-Service beantragen und wirksam werden lassen | 4.5 | abgeschlossen |
| 3.2 | Autoren-Dashboard & Novel-Verwaltung | Eigene Novels anlegen/bearbeiten/löschen, Cover verwalten | 2, 2.5 | abgeschlossen |
| 3.3 | Kapitelverwaltung & Co-Autoren | Kapitelliste sortieren, Co-Autoren hinzufügen/entfernen | 2 | abgeschlossen |
| 3.4 | Kapitel-Editor | Kapitel schreiben, als Entwurf speichern, veröffentlichen | 2 | abgeschlossen |
| 4 | Bibliothek & geräteübergreifender Lesefortschritt | Eigene Bibliothek, seiten-genaue Fortschritts-Sync | 4 | abgeschlossen |
| 5 | Offline-Caching & Netzwerk-Robustheit | Lokales Caching, Wiederholung bei transienten Fehlern | 7 (optional/parallel) | offen |
| 6 | Melden & Admin-Bereich | Reporting-UI, permission-gesteuerter Admin-Bereich | 5, 6 | offen – blockiert |
| 7 | Profil/Einstellungen & UX-Politur | Profilscreen, Web-Layout, Performance-Feinschliff | 7, 8 | teilweise offen |
Warum 2 und 3 in Unteriterationen aufgeteilt sind. Die ursprünglich einstufigen Iterationen 2 („Katalog, Novel-Detail & Leseansicht”) und 3 („Autoren-Dashboard, Kapitel-Editor & Rollen-Selbstantrag”) bündelten jeweils mehrere, fachlich unabhängig abnehmbare Features in einem einzigen Inkrement und waren dadurch für eine einzelne Iteration zu groß. Beide sind daher entlang der einzelnen Features in kleinere Unteriterationen (2.1–2.4 bzw. 3.1–3.4) aufgebrochen worden, die jeweils für sich lauffähig, testbar und abnehmbar sind, aber in der angegebenen Reihenfolge aufeinander aufbauen. Backend-seitig ändert sich dadurch nichts: Alle Unteriterationen einer Elterniteration nutzen weiterhin denselben, bereits abgeschlossenen Vertragsumfang.
Anders als der ursprüngliche Plan nahelegte, sind die Backend-Iterationen für die Stufen 0–4 inzwischen vollständig abgeschlossen (siehe iterationplan-backend.md, Stand 22.09.2026) – das Frontend kann diese Stufen also gegen einen fertigen, stabilen Vertrag bauen, ohne auf parallele Backend-Arbeit zu warten. Iteration 5 hat keine harte Backend-Abhängigkeit: Offline-Caching und Retry-Verhalten sind reine Client-Themen; Backend-Iteration 7 (HA-Härtung) macht die dabei simulierten transienten Fehler nur plausibler testbar, ist aber keine Voraussetzung. Iteration 6 ist dagegen wirklich blockiert: Weder Report- noch Admin-Endpunkte (POST /reports, GET/PATCH /admin/reports/{id}, GET /admin/users, PATCH /admin/users/{id}/roles, PATCH /admin/users/{id}/status) existieren aktuell in api/openapi.yaml – sie sind erst für Backend-Iteration 5/6 vorgesehen und dort noch nicht umgesetzt. Iteration 6 kann daher frühestens begonnen werden, sobald die entsprechende Backend-Iteration den Vertrag um diese Operationen erweitert hat; bis dahin sollte sie nicht vorgezogen werden (kein Mock-Backend für einen noch gar nicht feststehenden Vertrag).
Ziel: Ein leeres, aber auf allen drei Zielplattformen startbares KMP-Projekt existiert und kann das lokale Backend erreichen.
Enthaltene Anforderungen (Bezug auf anforderungen-frontend.md):
commonMain, androidMain, iosMain, wasmJsMain mit klarer Trennung von gemeinsamem und plattformspezifischem Code.api/openapi.yaml aus dem Backend-Repository (Copy-Task oder Raw-URL genügt zum Start, ein Git-Submodule ist eine spätere Option) und Generierung des Ktor-Clients per openapi-generator (kotlin, library=multiplatform, ohne zusätzlich gesetztes serializationLibrary – sonst doppelte @Serializable-Annotation und Kompilierfehler, siehe Backend-README).wasmJsBrowserDevelopmentRun, plattformabhängige Basis-URLs für das lokal laufende Backend (http://localhost:8080/api/v1 für Web/iOS-Simulator, http://10.0.2.2:8080/api/v1 für Android-Emulator). Das Backend muss CORS für die Origin des Web-Dev-Servers erlauben, sonst blockt der Browser alle Requests.Abgrenzung: Keine echten Fach-Screens; ein einfacher Test-Screen genügt, um die Ktor-Verbindung zum Backend zu verifizieren. Noch keine tatsächliche Nutzung des generierten API-Clients für einen Fach-Endpunkt – nur der Nachweis, dass Generierung und Grund-Setup funktionieren.
Definition of Done:
./gradlew :shared:compileIosMainKotlinMetadata); eine Laufzeitverifikation auf dem iOS-Simulator ist mangels verfügbarem Mac vertagt und wird nachgeholt, sobald einer verfügbar ist./actuator/health-Endpoint des lokalen Backends auf und zeigt dessen Status an.api/openapi.yaml lässt sich lokal ein kompilierbarer Ktor-Client erzeugen; ein triviale generierte Operation (z. B. GET /system/ping) lässt sich aus commonMain heraus aufrufen.commonMain enthält bereits den Großteil des Codes (Netzwerk-Client, Screen), plattformspezifische Module nur die jeweiligen Einstiegspunkte.Abhängigkeiten: Backend-Iteration 0.
Ziel: Nutzer können sich registrieren, einloggen und bleiben über sicher gespeicherte Tokens eingeloggt.
Enthaltene Anforderungen:
POST /auth/register: E-Mail, Benutzername, Passwort), Login (POST /auth/login), Logout (POST /auth/logout), automatisches Halten der Session. Beide Auth-Endpunkte liefern ein TokenPair (kurzlebiger Access Token, langlebiger Refresh Token).multiplatform-settings mit verschlüsseltem Backend je Plattform, wo verfügbar (Android: EncryptedSharedPreferences/DataStore; iOS: Keychain; Web: localStorage, ohne OS-Schlüsselbund – das im Web unvermeidbar höhere XSS-Risiko für den Token ist bewusst hinzunehmen und ggf. gesondert zu dokumentieren).POST /auth/refresh erneuert. Wichtig: der Backend-Refresh rotiert – der präsentierte Refresh Token wird verbraucht, ein bereits verbrauchter Token gilt als Leak-Indikator und widerruft die gesamte Sitzung (siehe Backend-README, Abschnitt „Authentication”); der Client muss also nach jedem Refresh zuverlässig das neue Token-Paar persistieren, bevor er es verwendet, und darf nie ein altes Refresh-Token doppelt einsetzen (z. B. bei parallelen Requests, die gleichzeitig einen Refresh auslösen – hier ist ein Mutex/Single-Flight-Refresh nötig). Schlägt auch der Refresh fehl, erfolgt die Rückführung zum Login.GET /user/me, liefert UserProfile mit roles und permissions), noch ohne differenzierte UI-Verzweigung.Abgrenzung: „Passwort vergessen” und Social Login sind ausdrücklich nicht enthalten (Abschnitt 6, 14).
Definition of Done:
Abhängigkeiten: Iteration 0 (Frontend), Backend-Iteration 1 (Auth-Endpunkte).
Ziel: Leser können veröffentlichte Novels durchsuchen, filtern und in einer Ergebnisliste überblicken.
Enthaltene Anforderungen:
GET /novels, paginiert (page/size), filterbar nach genre, status (nur PublicNovelStatus: ONGOING/COMPLETED/HIATUS – DRAFT ist bewusst kein gültiger Filterwert, da Entwürfe ohnehin nie im Katalog erscheinen), ageRating und authorId, durchsuchbar per search (Titel). Jeder Eintrag ist die schlanke Novel (Cover, Titel, Status, Genres, Altersfreigabe, Content Warnings – ohne Beschreibung).StateFlow-Patterns für diese Iterationsreihe, hier am Katalog-Screen.Abgrenzung: Noch keine Detailansicht (Iteration 2.3) – ein Tap/Klick auf einen Katalogeintrag darf vorerst auch nur ein Platzhalter-Ziel oder eine unverlinkte Karte sein. Kein Melden-Button (Iteration 6).
Definition of Done:
Abhängigkeiten: Iteration 1, Backend-Iteration 3 (Katalog-Endpunkt) – bereits abgeschlossen.
Ziel: Die App hat einen einheitlichen Einstiegspunkt: eine Startseite, die unabhängig vom Login-Status als erste Seite erscheint und über eine obere Navigationsleiste den Zugang zu Katalog und Profil/Login bündelt.
Enthaltene Anforderungen:
startDestination der Navigation und wird sowohl eingeloggt als auch ausgeloggt direkt angezeigt – kein erzwungener Login vor dem ersten Screen.TopAppBar, die app-weit auf jedem Screen angezeigt wird (nicht nur auf der Startseite) – technisch als einzelne, oberhalb des NavHost gehaltene Scaffold-Leiste umgesetzt, statt pro Screen dupliziert zu werden. Sie enthält zwei Bedienelemente:
UserProfile bereits bekannten Daten); bei ausgeloggtem Nutzer führt es zum Login-Screen aus Iteration 1."< Zurück"-Buttons auf Login/Register/Profil (siehe Iteration-2.2-Fortschrittsbericht) bleiben trotz der jetzt globalen Top-Bar bestehen, da die Top-Bar selbst keine Zurück-Navigation anbietet.Abgrenzung: Kein vollständiger Profilscreen mit Bearbeitungsfunktionen (Iteration 7) – der über den Avatar erreichte Platzhalter zeigt nur die bereits geladenen Profildaten und einen Logout. Keine weiteren Startseiten-Inhalte (z. B. Empfehlungen, „Weiterlesen”-Kacheln) – diese sind nicht Teil dieser Iteration und ergeben sich erst mit Bibliothek/Fortschritt aus Iteration 4.
Definition of Done:
Abhängigkeiten: Iteration 1 (Login-Status/Profil), Iteration 2.1 (Katalog als Suchziel).
Ziel: Leser können zu einem Novel die volle Detailansicht inklusive Synopse und Autorenliste aufrufen – sowohl aus dem Katalog heraus als auch über einen geteilten Slug-Link.
Enthaltene Anforderungen:
GET /novels/{novelId} liefert ein flaches NovelDetail (volle Synopse und authors zusätzlich zu allen Novel-Feldern). Ein geteilter Link kennt typischerweise nur den slug – dafür zuerst GET /novels/slug/{novelSlug} aufrufen, das liefert direkt das vollständige NovelDetail inkl. id für alle Folgeaufrufe. „Zur Bibliothek hinzufügen”-Button vorbereitet (volle Funktion folgt in Iteration 4).GET /novels/{novelId}/chapters, bereits in Lesereihenfolge mit berechneter chapterNumber; jeder Eintrag (Chapter) trägt zusätzlich partCount (Anzahl Leseseiten) und accessLevel. In dieser Iteration werden die Einträge nur angezeigt (Navigation zum eigentlichen Lesen folgt in Iteration 2.4).Abgrenzung: Kapitel lassen sich noch nicht öffnen/lesen (Iteration 2.4); „Zur Bibliothek hinzufügen” löst noch keinen echten Request aus (Iteration 4); kein Melden-Button (Iteration 6).
Definition of Done:
accessLevel-Kennzeichnung).slug-Link erreichbar, ohne vorherigen Katalog-Aufruf.Abhängigkeiten: Iteration 2.1, Backend-Iteration 3 (Novel-Detail-/Autoren-Endpunkte) – bereits abgeschlossen.
Ziel: Leser können ein Kapitel öffnen und komfortabel lesen – inklusive langer, serverseitig in mehrere Seiten zerlegter Kapitel.
Enthaltene Anforderungen:
GET /novels/{novelId}/chapters/{chapterId} liefert die Kapitel-Metadaten (ChapterDetail: chapter, novel als NovelReference mit chapterCount, wordCount, previousChapter/nextChapter) – aber keinen Text. Der Lesetext kommt über die Seiten-Endpunkte: entweder GET .../chapters/{chapterId}/parts (alle Seiten auf einmal) oder GET .../chapters/{chapterId}/parts/{partNumber} (eine einzelne Seite mit partCount). Die Leseansicht braucht also zwei Navigationsebenen: vorwärts/rückwärts zwischen Kapiteln (previousChapter/nextChapter) und vorwärts/rückwärts zwischen Seiten innerhalb eines mehrseitigen Kapitels (1..partCount), inkl. sinnvollem Übergang (letzte Seite „weiter” → erste Seite des nächsten Kapitels). Eine gemeinsam genutzte Kapitelnummer/Kapitel-ID-Auflösung über GET /novels/{novelId}/chapters/number/{chapterNumber} wird nur für den seltenen Fall gebraucht, dass ein Client nur die Nummer kennt (z. B. „Kapitel 5” aus einem alten Bookmark).accessLevel=PREMIUM-Kapiteln (z. B. Schloss-Icon) ohne Kauf-/Bezahllogik.Abgrenzung: „Weiterlesen” springt noch nicht an eine serverseitig gespeicherte Position (folgt mit der Bibliothek in Iteration 4); kein Melden-Button (Iteration 6); keine Autoren-seitige Kontrolle über die Seitengrenzen (rein serverseitig, siehe Backend Abschnitt 4.4).
Definition of Done:
partCount > 1) zusätzlich zur Kapitel-Navigation.Abhängigkeiten: Iteration 2.3, Backend-Iteration 3 (Lese-Endpunkte), 2.5 (Kapitelinhalt aus dem Objekt-Speicher) und 3.5 (Kapitel-Seiten) – alle drei sind bereits abgeschlossen.
Ziel: Nutzer ohne NOVEL_CREATE können die Autorenrolle per Self-Service beantragen, und eine erteilte Berechtigung wirkt sich sichtbar auf die App aus.
Enthaltene Anforderungen:
NOVEL_CREATE (aus den beim Login geladenen permissions, siehe Iteration 1) sehen den Einstiegspunkt „Meine Novels”, andere den Einstiegspunkt „Autor werden”. Der „Meine Novels”-Bereich selbst kann in dieser Iteration noch ein leerer Platzhalter sein (Inhalt folgt in Iteration 3.2).POST /user/me/role-requests stellt den Antrag; er wird aktuell serverseitig sofort automatisch genehmigt. GET /user/me/role-requests liefert die eigenen Anträge samt Status (PENDING/APPROVED/REJECTED) – nützlich für einen kurzen „Antrag wird bearbeitet”-Zustand, auch wenn er in dieser Ausbaustufe praktisch sofort in APPROVED übergeht. Nach einem genehmigten Antrag muss die App die Permissions neu laden (nächster Login/Refresh, siehe Iteration 1), bevor NOVEL_CREATE in der UI wirkt.Abgrenzung: Kein Admin-Genehmigungsschritt für den Rollen-Antrag (Backend-Backlog, siehe anforderungen-backend.md Abschnitt 15). Der „Meine Novels”-Bereich bleibt inhaltlich leer.
Definition of Done:
NOVEL_CREATE kann über „Autor werden” einen Rollen-Antrag stellen und sieht nach erneutem Login/Refresh den Einstiegspunkt „Meine Novels” statt „Autor werden”.Abhängigkeiten: Iteration 1, Backend-Iteration 4.5 (Rollen-Selbstantrag) – bereits abgeschlossen.
Ziel: Nutzer mit NOVEL_CREATE können eigene Novels anlegen, bearbeiten, löschen und mit einem Cover versehen.
Enthaltene Anforderungen:
GET /user/me/novels (liefert – anders als der öffentliche Katalog – auch eigene DRAFT-Novels, paginiert; die Kapitelverwaltung pro Novel folgt in Iteration 3.3/3.4). Neues Novel anlegen über POST /novels (CreateNovelRequest: title, description, ageRating Pflicht, genres/contentWarnings optional); Bearbeiten über PATCH /novels/{novelId} (UpdateNovelRequest, jedes Feld optional inkl. status); Löschen über DELETE /novels/{novelId} (Soft Delete).coverImageUrl ist kein beschreibbares Feld in CreateNovelRequest/UpdateNovelRequest mehr, sondern wird ausschließlich über PUT /novels/{novelId}/cover gesetzt (multipart-Upload, image/png/image/jpeg/image/webp, max. 5 MiB, idempotent) bzw. DELETE /novels/{novelId}/cover entfernt. Ein einfacher Datei-Picker reicht; der ETag-Header der letzten GET/PUT-Antwort sollte gespeichert und optional als If-Match mitgeschickt werden, um eine zwischenzeitliche Änderung (z. B. durch einen Co-Autor) mit 412 statt eines stillen Überschreibens zu erkennen. Ein 409 (paralleler Schreibzugriff ohne If-Match) sollte als „bitte erneut versuchen” behandelt werden.Abgrenzung: Kein Freigabe-Workflow vor der Veröffentlichung (Backend-Backlog). Kapitelverwaltung (Sortierung, Co-Autoren, Editor) folgt in 3.3/3.4 – der status-Wechsel eines Novels selbst (z. B. auf COMPLETED) ist zwar über PATCH /novels/{novelId} schon möglich, ein sinnvoller Veröffentlichungs-Workflow ergibt aber erst mit vorhandenen Kapiteln Sinn.
Definition of Done:
NOVEL_CREATE kann im Autoren-Dashboard (GET /user/me/novels) ein Novel anlegen, bearbeiten, löschen sowie ein Cover hochladen, ersetzen und entfernen.Abhängigkeiten: Iteration 3.1, Backend-Iteration 2 (Novel-Verwaltung) und 2.5 (Cover-Upload) – bereits abgeschlossen.
Ziel: Autoren können die Kapitelreihenfolge eines eigenen Novels pflegen und weitere Autoren daran beteiligen.
Enthaltene Anforderungen:
PUT /novels/{novelId}/chapters/{chapterId}/position mit { afterChapterId } (null = an den Anfang, sonst die id des neuen Vorgänger-Kapitels). Das Frontend meldet nur den neuen Nachbarn; chapterNumber kommt bei jedem folgenden GET automatisch neu berechnet vom Server. Diese Liste zeigt auch Entwurfs-Kapitel (die im öffentlichen Katalog/Reader nicht sichtbar wären).NovelDetail.authors/der Verwaltungsantwort, Nutzer-Suche über GET /users?username=..., Hinzufügen über POST /novels/{novelId}/authors (AddNovelAuthorRequest: { userId }), Entfernen über DELETE /novels/{novelId}/authors/{userId}.Abgrenzung: Das Erstellen/Bearbeiten des eigentlichen Kapitelinhalts ist Iteration 3.4; hier geht es nur um Reihenfolge und Autorenzuordnung einer bereits (leeren oder befüllten) Kapitelstruktur.
Definition of Done:
GET.userId entfernt werden.Abhängigkeiten: Iteration 3.2, Backend-Iteration 2 (Kapitel-Verwaltung) – bereits abgeschlossen.
Ziel: Autoren können Kapitelinhalte schreiben, als Entwurf sichern und veröffentlichen.
Enthaltene Anforderungen:
CreateChapterRequest/UpdateChapterRequest: title, chapterContent, optional status/accessLevel), Speichern-als-Entwurf (status=DRAFT) und Veröffentlichen (status=PUBLISHED), Live-/Vorschau-Ansicht. Ein neues Kapitel wird über POST /novels/{novelId}/chapters immer ans Ende angehängt (Neusortierung danach separat per Drag & Drop aus Iteration 3.3). Die Seitenzerlegung (ChapterPart, siehe Iteration 2.3) ist eine reine Server-Berechnung aus chapterContent – der Editor selbst kennt keine Seiten und muss keine anzeigen.Abgrenzung: Kein Freigabe-Workflow vor der Veröffentlichung (Backend-Backlog).
Definition of Done:
NOVEL_CREATE kann für ein eigenes Novel ein neues Kapitel schreiben, als Entwurf speichern oder veröffentlichen sowie ein bestehendes Kapitel bearbeiten.Abhängigkeiten: Iteration 3.3, Backend-Iteration 2 (Kapitel-Verwaltung) – bereits abgeschlossen.
Ziel: Nutzer können ihre Bibliothek verwalten und auf jedem Gerät an der zuletzt gelesenen Seite weiterlesen.
Enthaltene Anforderungen:
GET /user/me/library/novels, paginiert, optional nach readingStatus filterbar (READING/COMPLETED/PLAN_TO_READ/DROPPED). Jeder Eintrag (LibraryEntry) bettet die schlanke Novel ein und liefert den optionalen zusammengesetzten lastBookMark mit Kapitel-ID, berechneter Kapitelnummer/-titel, Seite und Positionsmarker. Ein DRAFT-Novel kann nie in dieser Liste erscheinen, auch nicht das eigene – eigene Entwürfe verwaltet der Nutzer stattdessen über das Autoren-Dashboard aus Iteration 3 (GET /user/me/novels).PUT /user/me/library/{novelId} (Upsert; UpsertLibraryEntryRequest.readingStatus optional, Default READING). Entfernen: DELETE /user/me/library/{novelId}.GET /user/me/library/{novelId} und springt anhand von lastBookMark zu Kapitel, Seite und Positionsmarker. Existiert noch kein Eintrag (404) oder kein Bookmark, beginnt „Weiterlesen” wie ein normaler Lesestart bei Kapitel 1, Seite 1.PUT /user/me/library/{novelId}/progress mit UpdateReadingProgressRequest (chapterId, partNumber – die gelesene Seite, bei einseitigen Kapiteln immer 1 –, position, clientUpdatedAt). Dieser Aufruf ist selbst ein Upsert (legt den LibraryEntry bei Bedarf mit readingStatus=READING an, ein vorheriges PUT /user/me/library/{novelId} ist nicht nötig). Senden beim Verlassen eines Kapitels/einer Seite sowie periodisch während des Lesens (z. B. alle 30 s). Das Backend wendet Last-Write-Wins über clientUpdatedAt gegen das gespeicherte updatedAt an; ein verworfenes (veraltetes) Update ist kein Fehler, sondern liefert den unveränderten Eintrag zurück – das Frontend darf ein solches 200 also nicht fälschlich als „mein Update hat gewonnen” interpretieren, sondern sollte bei Bedarf den zurückgelieferten Stand übernehmen.position-Marker (Positionsmetrik innerhalb einer Seite, z. B. Absatzindex oder Scroll-Prozentwert) ist eine reine Frontend-Entscheidung und muss vor der Implementierung festgelegt werden (siehe Backend Abschnitt 7: „die genaue Metrik wird zusammen mit dem Frontend festgelegt”).Abgrenzung: Die Zwischenspeicherung ausstehender Updates bei fehlender Verbindung ist Teil von Iteration 5; hier wird zunächst der Online-Fall abgedeckt.
Definition of Done:
clientUpdatedAt) zeigen clientseitig nachweislich das korrekte Last-Write-Wins-Ergebnis.Abhängigkeiten: Iteration 2.4 (Kapitel-Seiten müssen lesbar sein, um Fortschritt seitengenau festzumachen), Backend-Iteration 4 (Bibliotheks-/Fortschritts-Endpunkte) – bereits abgeschlossen.
Ziel: Die App bleibt bei instabiler oder fehlender Verbindung nutzbar und verliert keine Fortschritts-Updates.
Enthaltene Anforderungen:
UpdateReadingProgressRequest-Payloads werden bei fehlender Verbindung lokal vorgehalten (inkl. ihres clientUpdatedAt) und bei Wiederverbindung automatisch nachgereicht, in der Reihenfolge ihrer Entstehung.code-Felds von ProblemDetail (nicht der für Menschen gedachten title/detail-Texte), tolerant gegenüber unbekannten code-Werten, die additiv ergänzt werden dürfen; einheitliche, verständliche Fehleranzeige bei endgültigem Fehlschlag. 429/RATE_LIMIT_EXCEEDED ist im Vertrag auf jeder Operation dokumentiert (aktuell serverseitig nicht durchgesetzt, aber der Client sollte den Fall trotzdem wie einen regulären transienten Fehler behandeln, statt ihn zu ignorieren).Abgrenzung: Kein vollständiger Offline-Download ganzer Novels (Abschnitt 14, spätere Erweiterung) – nur bereits besuchte Kapitel-Seiten bleiben zwischengespeichert.
Definition of Done:
clientUpdatedAt.Abhängigkeiten: Iteration 4. Keine harte Backend-Abhängigkeit; Backend-Iteration 7 (HA-Härtung, noch offen) macht die dabei simulierten Fehlerbilder nur realistischer nachstellbar.
Status: blockiert. Die dafür nötigen Backend-Endpunkte existieren noch nicht in api/openapi.yaml – POST /reports, GET/PATCH /admin/reports/{id}, GET /admin/users, PATCH /admin/users/{id}/roles, PATCH /admin/users/{id}/status sind für Backend-Iteration 5 bzw. 6 vorgesehen (siehe iterationplan-backend.md), beide dort noch nicht begonnen. Diese Iteration kann frühestens gestartet werden, sobald der Vertrag um die entsprechenden Operationen erweitert wurde – contract-first bedeutet hier ausdrücklich, dass es vor einer Vertragsänderung nichts zu generieren und damit nichts Verbindliches zu implementieren gibt. Die folgende Beschreibung ist der geplante Umfang, nicht bereits umsetzbar.
Ziel: Nutzer können Inhalte/Accounts melden; berechtigte Nutzer sehen einen granular nach Permission gesteuerten Admin-Bereich.
Enthaltene Anforderungen:
USER_MANAGE) und Rollenzuweisung (ROLE_MANAGE), Novel-/Kapitel-Übersicht mit Entfernen-Möglichkeit (NOVEL_EDIT_ANY/CHAPTER_EDIT_ANY, bereits über die bestehenden DELETE-Endpunkte aus Iteration 3.2/3.3 nutzbar), Moderationswarteschlange (REPORT_REVIEW) mit Ablehnen/Aktion-vermerken.Abgrenzung: Keine UI zum Anlegen neuer Rollen oder Permission-Bündel (Backend-Backlog).
Definition of Done (sobald entsperrt):
REPORT_REVIEW sieht nur die Moderationswarteschlange; ein Nutzer mit zusätzlichen Permissions sieht die entsprechend weiteren Admin-Teilbereiche, jeweils unabhängig voneinander ein-/ausgeblendet.Abhängigkeiten: Iterationen 3.2/3.3 (die dort eingeführten DELETE-Endpunkte für Novel/Kapitel werden für den Admin-Bereich wiederverwendet), Backend-Iterationen 5 und 6 (beide noch offen).
Ziel: Die App wirkt auf allen Plattformen rund, performant und ist vollständig testbar.
Enthaltene Anforderungen:
PATCH /user/me (UpdateProfileRequest) – Anzeigename ändern (displayName, leerer String löscht ihn), Benutzername ändern, E-Mail ändern (erfordert currentPassword), Passwort ändern (erfordert currentPassword; widerruft serverseitig alle Refresh Tokens, die App muss den Nutzer danach also aktiv neu einloggen lassen statt einen jetzt ungültigen Refresh Token weiterzuverwenden), Logout, App-weites Farbschema.ChapterPart-Seite), skalierbare Schriftgröße, Unit-Tests für commonMain-Logik, ergänzende UI-Tests für plattformspezifische Teile.Abgrenzung: Keine grundlegend neue visuelle Gestaltung (Farbschema/Typografie sind laut Anforderungsdokument ein separater Design-Schritt).
Definition of Done:
commonMain verfügt über eine Basis-Testabdeckung; mindestens ein UI-Test pro Plattform ist vorhanden.Abhängigkeiten: Iterationen 2.1–2.4, 3.1–3.4, 4 und 5 (Politur setzt auf den bestehenden Screens auf; Iteration 6 ist wegen der Backend-Blockade ausdrücklich keine Voraussetzung). Backend-Iteration 7/8 (AWS-Readiness) betrifft primär Deployment-Konfiguration und hat keine unmittelbare Auswirkung auf diese Frontend-Stufe.
Die folgenden, in anforderungen-frontend.md (Abschnitt 14) genannten Themen bleiben bewusst außerhalb dieses Iterationsplans und werden erst nach Abschluss von Iteration 7 priorisiert: Web-Target (Compose Multiplatform for Web/Wasm), OAuth-/Social-Login-UI, vollständiger Offline-Download ganzer Novels, Kommentare und Bewertungen zu Novels/Kapiteln, Push-Benachrichtigungen bei neuen Kapiteln abonnierter Novels, „Passwort vergessen”-Flow.
Dieser Plan ist bewusst so geschnitten, dass jede Frontend-Iteration auf einer bestimmten Backend-Iteration aufsetzt (siehe Tabelle in Abschnitt 2 sowie die Abhängigkeiten je Iteration). In der Praxis können Backend und Frontend für dieselbe Funktionsgruppe parallel entwickelt werden, sobald das jeweilige API-Vertrag (Endpunkt-Signaturen, DTOs) feststeht – das Frontend muss dafür nicht auf die vollständige Fertigstellung der Backend-Iteration warten, sondern kann gegen die in api/openapi.yaml beschriebene Schnittstelle entwickeln. Für die Iterationen 0–5 ist das inzwischen ohnehin hinfällig, da der Backend-Vertrag für diesen Umfang bereits steht; einzig Iteration 6 muss auf eine tatsächliche Vertragserweiterung warten, da contract-first per Definition ausschließt, gegen einen noch nicht existierenden Vertrag zu generieren.
Da sich der Vertrag zwischen Backend-Iterationen bereits einmal rückwirkend geändert hat (Vertragsbereinigung vom 22.09.2026, siehe iterationplan-backend.md, Iteration 4), sollte dieses Dokument nach jeder künftigen Backend-Iteration, die api/openapi.yaml ändert, kurz gegen den neuen Stand geprüft werden – insbesondere vor Beginn von Iteration 6, deren Endpunkt-Namen und -Formen hier nur als aktuell wahrscheinlichste Annahme aus anforderungen-backend.md übernommen wurden, nicht aus einem bereits feststehenden Vertrag.