[Reader][Offline] IndexedDB offline book store (schema + CRUD foundation) #651

Closed
opened 2026-07-17 14:07:11 +00:00 by spikerj · 2 comments
Owner

The persistence layer for offline reading (WS-1) — the foundation the download service + offline reader build on.

BookOfflineStoreService (raw IndexedDB spikersoft-books-offline, mirroring the TrailCacheService promise-wrapped idiom):

  • Stores: manifests, pdf-files, epub-toc (keyed by bookId); epub-pages + epub-resources (single string key bookId::sub + a bookId index).
  • CRUD per store; deleteBook removes every record for a book across all five stores in one atomic transaction (via the bookId index — deliberately no compound keyPaths or IDBKeyRange, so it's portable + unit-testable); estimateUsage() (navigator.storage); isDownloaded/isCurrent (sha256 staleness).
  • The manifest is the completion marker — written last by the download service; its presence means the book is fully offline.

Fully unit-tested (round-trips for manifest/pdf/pages/resources, deleteBook isolation, staleness). Build clean.

Follow-up (PR-8c): the download service (quota preflight/persist, PDF blob GET with progress, EPUB pages batched + deduped resources, rollback on QuotaExceeded), offline reader fallback + blob-URL resource rewriting, download-button UI + profile offline-books section, auth.guard offline entry.

PR: spikersoft-angular feat/reader-offline-store.

The persistence layer for offline reading (WS-1) — the foundation the download service + offline reader build on. `BookOfflineStoreService` (raw IndexedDB `spikersoft-books-offline`, mirroring the `TrailCacheService` promise-wrapped idiom): - Stores: `manifests`, `pdf-files`, `epub-toc` (keyed by bookId); `epub-pages` + `epub-resources` (single string key `bookId::sub` + a `bookId` index). - CRUD per store; `deleteBook` removes every record for a book across all five stores in one atomic transaction (via the `bookId` index — deliberately no compound keyPaths or IDBKeyRange, so it's portable + unit-testable); `estimateUsage()` (navigator.storage); `isDownloaded`/`isCurrent` (sha256 staleness). - The manifest is the completion marker — written last by the download service; its presence means the book is fully offline. Fully unit-tested (round-trips for manifest/pdf/pages/resources, deleteBook isolation, staleness). Build clean. **Follow-up (PR-8c):** the download service (quota preflight/persist, PDF blob GET with progress, EPUB pages batched + deduped resources, rollback on QuotaExceeded), offline reader fallback + blob-URL resource rewriting, download-button UI + profile offline-books section, `auth.guard` offline entry. PR: spikersoft-angular `feat/reader-offline-store`.
Author
Owner

Resolved in spikersoft-angular PR #224 (offline store) + PR #225 (download service), both merged to master. BookOfflineStoreService (IndexedDB schema/CRUD, atomic deleteBook, sha256 staleness) + BookOfflineDownloadService (PDF/EPUB download with progress, deduped resources, manifest-last, rollback-on-QuotaExceeded). 9 unit specs green. The UI (download button + profile offline-books) and reader-read integration are the PR-8c follow-up. Closing this foundation ticket.

Resolved in spikersoft-angular PR #224 (offline store) + PR #225 (download service), both merged to `master`. BookOfflineStoreService (IndexedDB schema/CRUD, atomic deleteBook, sha256 staleness) + BookOfflineDownloadService (PDF/EPUB download with progress, deduped resources, manifest-last, rollback-on-QuotaExceeded). 9 unit specs green. The UI (download button + profile offline-books) and reader-read integration are the PR-8c follow-up. Closing this foundation ticket.
Author
Owner

Resolved in spikersoft-backend PR #362 (merged to master). All 6 sites now parse with CultureInfo.InvariantCulture + DateTimeStyles.RoundtripKind, preserving UTC Kind — phone-code expiry and ship/character DeletedAt are TZ-correct on any host. Zero behavior change on UTC servers. S6580 findings close as FIXED on next scan. Closing.

Resolved in spikersoft-backend PR #362 (merged to master). All 6 sites now parse with CultureInfo.InvariantCulture + DateTimeStyles.RoundtripKind, preserving UTC Kind — phone-code expiry and ship/character DeletedAt are TZ-correct on any host. Zero behavior change on UTC servers. S6580 findings close as FIXED on next scan. Closing.
Sign in to join this conversation.