5.6 KiB
5.6 KiB
Novela 2.0 - Technical Status (Develop)
Scope
This document describes the current technical status of the develop codebase.
It is the primary technical reference for the current implementation.
Architecture
- Stack: FastAPI, Jinja2 templates, plain JavaScript, PostgreSQL 16, Docker.
- Startup lifecycle (
main.py):init_pool()run_migrations()start_backup_scheduler()- mount routers
- Shutdown lifecycle:
stop_backup_scheduler()close_pool()
- Source-of-truth rule: files on disk are authoritative, the database is an index/cache.
Router Status
routers/library.py
GET /libraryGET /api/libraryPOST /library/rescanPOST /library/import(EPUB/PDF/CBR/CBZ)DELETE /library/file/{filename}GET /library/cover/{filename}GET /library/cover-cached/{filename}POST /library/cover/{filename}(EPUB)POST /library/want-to-read/{filename}POST /library/archive/{filename}POST /library/new/mark-reviewed(bulkneeds_review=false)GET /homeGET /api/homeGET /statsGET /api/statsGET /library/list(compat)
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.
/api/home returns:
continue_readingshorts_unreadnovels_unreadshorts_readnovels_read
/api/stats returns totals plus chart/history data for stats.html:
reads_by_month,reads_by_dow,reads_by_hourgenre_counts,publisher_counts,fav_genre,fav_publishertop_books,history
Home sections exclude series books via:
COALESCE(series, '') = ''filename NOT LIKE '%/Series/%'
Home read sections are ordered oldest-first:
shorts_read:ORDER BY MAX(read_at) ASCnovels_read:ORDER BY MAX(read_at) ASC
routers/reader.py
- EPUB serving/chapters/images
- Reader page + book detail
- Metadata patch (
PATCH /library/book/{filename}) - Progress read/write/delete
- Mark-as-read
- PDF render endpoint
- CBR/CBZ page endpoint
- Genres endpoint
routers/editor.py
- Editor page
- Chapter get/save
- Chapter add
- Chapter delete
routers/grabber.py
- Grabber page + convert/debug flows
- SSE events
- Credential management for scraper sites
- Credentials manager UI (
/credentials-manager)
routers/backup.py
GET /backupGET/POST/DELETE /api/backup/credentialsGET /api/backup/healthGET /api/backup/statusGET /api/backup/historyPOST /api/backup/run
Backup & Security
- Dropbox token is stored encrypted-at-rest in
credentials(site='dropbox'). - Dropbox backup root is stored encrypted in
credentials(site='dropbox_backup_root'). - Retention (
snapshots to keep) is stored encrypted incredentials(site='dropbox_backup_retention'). - Backup schedule (
enabled+interval_hours) is stored encrypted incredentials(site='dropbox_backup_schedule'). - Encryption uses
NOVELA_MASTER_KEY(Fernet).
Implementation details:
- Versioned backups with deduplication:
- file objects in Dropbox:
library_objects/{sha256_prefix}/{sha256} - snapshots in Dropbox:
library_snapshots/snapshot-YYYYMMDD-HHMMSS.json
- file objects in Dropbox:
- Each run creates a new snapshot version and uploads only missing objects.
- Retention removes older snapshots above the configured limit.
- Orphan object pruning removes objects no longer referenced by retained snapshots.
- Local manifest cache (
config/backup_manifest.json) speeds up change detection. - Database backup is done via
pg_dumpto Dropboxpostgres/. POST /api/backup/runalways starts a background task and returns immediately.- Scheduler runs in the background (
start_backup_scheduler) and triggers on interval when enabled. - Concurrency guard: only one backup can run at a time.
- After container restart/crash, stale
runninglogs are auto-marked as interrupted/error.
Environment
stack/novela.env should include at least:
POSTGRES_DBPOSTGRES_USERPOSTGRES_PASSWORDNOVELA_MASTER_KEYCONFIG_DIR
Dropbox settings are managed via the web UI on /backup.
UI Notes
- Library import accepts EPUB/PDF/CBR/CBZ.
- Home supports the same import formats.
- Home includes search.
- Home header/dropzone alignment matches Library (search top-right, dropzone below).
Newview supportsGridandListmode.- Bulk selection +
Remove from Newworks only inListmode. Listmode has a column visibility filter with columns:- Publisher
- Author
- Series
- Volume
- Title
- Has cover
- Updated
- Genres
- Sub-genres
- Tags
- Status
Listmode supports multi-select withShift+clickrange selection on checkboxes.Gridmode shows no selection checkboxes or bulk actions.- Backup page supports:
- manual run and dry-run
- Dropbox root settings
- snapshot retention count
- scheduled backup (on/off + interval in hours)
- status + history overview
Known Conventions
- Book deletion flow: delete file, prune empty directories, then
DELETE FROM library(cascade removes child rows). - Cover strategy:
- EPUB: cover from file + cache
- PDF/CBR: thumbnail via cover cache
Performance Notes
- Library load is optimized for large datasets:
list_library_json()uses pre-aggregation forreading_sessions.has_cached_coveris provided directly via SQL join instead of full cache fetch.
- Additional migration indexes:
idx_library_sort_coalesceidx_library_needs_reviewidx_library_archivedidx_reading_sessions_filename_readatidx_book_tags_filename_tag