- EBook.is_read (Migration) + neuer /books/<id>/read/-Endpoint zum Togglen
- book_list liefert is_read und has_highlights (Existenz einer Highlights-Zeile)
- Reader öffnet die Notizen-Sidebar automatisch, wenn das Buch bereits
Markierungen/Notizen hat, statt sie hinter dem manuellen Toggle zu verstecken
- Buch-Übersicht: Download-Button für Notizen/Markierungen direkt aus der Liste
(ohne den Reader zu öffnen), "Als gelesen markieren" mit Bestätigungsdialog,
Filter "Gelesene Bücher anzeigen" (standardmäßig aus)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
When a book fails to open, a '!' button appears next to it in the list.
Clicking it prompts for the original file; the file is re-encrypted with
the current key and replaces the broken ciphertext on the server while
keeping all metadata, progress, highlights and bookmarks intact.
- Add POST /books/<pk>/replace-data/ endpoint (updates data only)
- Add _evictCachedBook() to clear IndexedDB cache for a single book
- Replace complex client-side re-encryption on password change with a
simple confirm() warning that books will need to be re-uploaded
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The encryption key is PBKDF2-derived from the login password. Changing
the password without migrating the key would make all books undecryptable
on the next login.
- Add POST /books/<pk>/rekey/ endpoint to replace a book's ciphertexts
- Password change form is now JS-driven: before submitting to the server,
derives the old key, verifies it matches localStorage, derives the new
key, re-encrypts all books (data + meta) and their highlights/bookmarks,
updates localStorage, then submits the Django form
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>