Docs: update TECHNICAL.md and changelog for Following, Incomplete, and performance
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
5d83bfccab
commit
3d739b4c72
@ -78,6 +78,7 @@ All files are stored under `library/` (relative to the app working directory, ma
|
||||
`GET /api/library` runs in fast-path mode by default (DB-only, no full disk rescan).
|
||||
For a forced sync: `GET /api/library?rescan=true` or `POST /library/rescan`.
|
||||
`include_file_info=true` is optional for file size/mtime enrichment.
|
||||
ETag caching: response includes `ETag: "{count}-{max_updated_at_unix}"` and `Cache-Control: no-cache`. Client sends `If-None-Match`; server returns `304 Not Modified` when nothing changed.
|
||||
|
||||
`/api/home` returns:
|
||||
- `continue_reading`
|
||||
@ -164,6 +165,18 @@ Home read sections are ordered oldest-first:
|
||||
|
||||
Publish flow: all chapters are run through `normalize_wysiwyg_html()`, then `build_epub()` produces an EPUB 2.0 ZIP. The file path is computed via `make_rel_path(media_type="epub", …)`. The book is inserted into the library with `needs_review=True`. The draft is deleted on success.
|
||||
|
||||
### `routers/following.py`
|
||||
- `GET /following` — Following page (author URL management)
|
||||
- `GET /api/following` — all distinct library authors with URL (if set), book count, and last-added date
|
||||
- `POST /api/following/{author_name}` — set or clear URL for an author (empty `url` removes the record)
|
||||
|
||||
`GET /api/following` returns one entry per non-archived author:
|
||||
```json
|
||||
{ "name": "Author Name", "book_count": 5, "last_added": "2026-03-27T…", "url": "https://…" }
|
||||
```
|
||||
|
||||
URL is stored in the `authors` table (`name` unique, `url`, `created_at`, `updated_at`).
|
||||
|
||||
### `routers/backup.py`
|
||||
- `GET /backup` — backup page
|
||||
- `GET /api/backup/credentials` — Dropbox settings (includes `app_key_configured` flag)
|
||||
@ -256,6 +269,8 @@ Dropbox settings are managed via the web UI on `/backup`.
|
||||
- Bookmarks: saved per book via `POST /library/bookmarks/{filename}`; shown in Library sidebar section; navigated via `?bm_ch=N&bm_scroll=F` URL params on reader page.
|
||||
- Convert page: after loading metadata, if a book with the same title+author already exists in the library, a warning banner is shown (with a link to the existing book); user can still proceed with conversion. Check is done server-side in `/preload` response (`already_exists`, `existing_books`).
|
||||
- Duplicates view (`#duplicates`): groups non-archived books by `(title, author)` (case-insensitive); shows only groups with ≥ 2 copies; counter in sidebar shows total number of duplicate books. Detection is entirely client-side from the existing library data.
|
||||
- Incomplete view (`#incomplete`): shows all non-archived books where `publication_status` is not `Complete` (Ongoing, Hiatus, or blank); sidebar counter included.
|
||||
- Following page (`/following`): dedicated page in its own sidebar section between Library and Tools; shows all library authors with their external URL; two tabs — Following (authors with URL set) and All Authors; inline URL editing with keyboard support (Enter = save, Escape = cancel); clicking Visit opens the external URL in a new tab. Author URLs are stored in the `authors` table. Sidebar counter shows number of followed authors.
|
||||
- Book Builder (`/builder`): create EPUB books from scratch; drafts stored in `builder_drafts` (JSONB chapters); contenteditable editor with toolbar (bold/italic/underline/blockquote/author-note/scene-break/normalize); autosave every 30 s + Ctrl+S; publish normalizes HTML via `normalize_wysiwyg_html()` and builds EPUB via `build_epub()`.
|
||||
|
||||
---
|
||||
@ -277,9 +292,13 @@ Dropbox settings are managed via the web UI on `/backup`.
|
||||
---
|
||||
|
||||
## Performance Notes
|
||||
- Library load is optimized for large datasets:
|
||||
- `list_library_json()` uses pre-aggregation for `reading_sessions`.
|
||||
- Library load is optimized for large datasets (1000+ books):
|
||||
- `list_library_json()` uses `json_agg` in the main query to inline tags per book — eliminates a separate `SELECT * FROM book_tags` query and Python merge loop.
|
||||
- `has_cached_cover` is provided directly via SQL join instead of full cache fetch.
|
||||
- `reading_sessions` is pre-aggregated in a subquery.
|
||||
- ETag on `/api/library`: cheap `COUNT + MAX(updated_at)` query before full load; `304 Not Modified` on cache hit.
|
||||
- Front-end rendering uses `IntersectionObserver` to defer both cover image loading and placeholder canvas drawing until cards enter the viewport — prevents hundreds of simultaneous HTTP requests and canvas operations on initial render.
|
||||
- `renderBooksGrid`, `renderDuplicatesView`, `renderSeriesDetail` all use a single DOM pass: cover `<img>` and `<canvas>` are set up via `card.querySelector` immediately after `innerHTML` is set, eliminating a second full iteration with `document.getElementById` calls.
|
||||
- Additional migration indexes:
|
||||
- `idx_library_sort_coalesce`
|
||||
- `idx_library_needs_review`
|
||||
|
||||
@ -3,6 +3,22 @@
|
||||
This file tracks changes on the `develop` line.
|
||||
`changelog.md` can later be used for release summaries.
|
||||
|
||||
## 2026-03-28 (2)
|
||||
- Performance: library page now loads instantly for large collections (1000+ books)
|
||||
- `IntersectionObserver` defers both cover image loading and placeholder canvas drawing until cards enter the viewport — eliminates hundreds of upfront canvas ops that blocked the initial render
|
||||
- `ETag` caching on `/library/list`: server returns `304 Not Modified` when nothing changed, client skips JSON parse and re-download
|
||||
- Single DOM pass in `renderBooksGrid`, `renderDuplicatesView`, `renderSeriesDetail`: canvas and img set up via `card.querySelector` immediately after `innerHTML`, removing a second iteration with `document.getElementById` per card
|
||||
- `book_tags` joined via `json_agg` in the main `list_library_json()` query, eliminating a separate `SELECT * FROM book_tags` query and Python merge loop
|
||||
- `loadLibrary` now shows an error message instead of staying stuck on "Loading…" when the fetch or render fails
|
||||
|
||||
## 2026-03-28 (1)
|
||||
- Added Following page (`/following`): track external author URLs outside Library and Tools
|
||||
- New `authors` table: `name` (unique), `url`, `created_at`, `updated_at`
|
||||
- New `routers/following.py`: `GET /following` page, `GET /api/following` (all authors + URL + book count + last added), `POST /api/following/{name}` (set/clear URL)
|
||||
- Sidebar: new Following section between Library and Tools; counter shows number of followed authors
|
||||
- Following page: two tabs — Following (authors with URL) and All Authors; inline URL editing with Enter/Escape keyboard support; Visit button opens external URL in a new tab; author name links to library author view
|
||||
- Added Incomplete view to Library (`#incomplete`): shows all non-archived books where `publication_status ≠ Complete`; sidebar counter included; entry placed after New in the Library section
|
||||
|
||||
## 2026-03-27 (1)
|
||||
- Convert page: duplicate warning shown after loading metadata when a book with the same title+author already exists in the library; warning includes a link to the existing book; user can still proceed with conversion
|
||||
- Library: added Duplicates section to sidebar (between Rated and Statistics); counter shows total number of books that are part of a duplicate group (same title+author, case-insensitive); Duplicates view groups books by title+author with a subheading per group
|
||||
|
||||
Loading…
Reference in New Issue
Block a user