projects/spikersoft/ngsw-config.json dataGroup api-book-metadata caches https://api.spikersoft.com/api/book/* with strategy: "freshness", maxAge: "7d", timeout: "3s". But the payload carries short-lived presigned MinIO URLs (coverUrl, coverVariants[].url) that expire ~1–2h after minting (2h TTL after spikersoft-backend#499).
Any freshness fallback — network slower than the 3s timeout, or offline — serves a book list where every cover URL is already dead, so every cover renders broken. Art Studio has no equivalent dataGroup and thus no equivalent exposure.
Secondary caveat (same dataGroup)
ngsw dataGroups key on URL and ignore the Authorization header, so per-user /api/book/my-books responses are cached under a URL that isn't user-scoped — a logout/login as a different user on the same browser can be served the previous user's cached book list until the network responds.
Fix
Drop maxAge for the cover-bearing book-list routes to ≤ the presigned TTL window (e.g. 30m), so any JSON the SW is willing to serve still contains live URLs. The epub-resource/page dataGroups (api-epub-resources, api-epub-pages) are more specific, match first, and are unaffected.
## Problem
`projects/spikersoft/ngsw-config.json` dataGroup `api-book-metadata` caches `https://api.spikersoft.com/api/book/*` with `strategy: "freshness"`, `maxAge: "7d"`, `timeout: "3s"`. But the payload carries short-lived presigned MinIO URLs (`coverUrl`, `coverVariants[].url`) that expire ~1–2h after minting (2h TTL after spikersoft-backend#499).
Any freshness *fallback* — network slower than the 3s timeout, or offline — serves a book list where **every cover URL is already dead**, so every cover renders broken. Art Studio has no equivalent dataGroup and thus no equivalent exposure.
## Secondary caveat (same dataGroup)
ngsw dataGroups key on URL and ignore the `Authorization` header, so per-user `/api/book/my-books` responses are cached under a URL that isn't user-scoped — a logout/login as a different user on the same browser can be served the previous user's cached book list until the network responds.
## Fix
Drop `maxAge` for the cover-bearing book-list routes to ≤ the presigned TTL window (e.g. `30m`), so any JSON the SW is willing to serve still contains live URLs. The epub-resource/page dataGroups (`api-epub-resources`, `api-epub-pages`) are more specific, match first, and are unaffected.
Related: spikersoft-backend#499 (stable memoized cover URLs), #618, #719.
Fix approach revised while implementing (spikersoft-angular PR #595): the ticket proposed dropping the dataGroup maxAge to ≤ the presigned TTL, but reading-journey.loadBooks() renders the shelf solely from getMyBooks() — there is no offline-manifest fallback — so a 30m maxAge would empty the shelf after half an hour offline, breaking the offline-reading scenario the SW cache exists to support.
Shipped instead:
shelf grid / hero / quick-view degrade to the placeholder on img error (dead presigned URL) rather than a broken image;
downloaded books render from an offline-persisted cover blob (#880), so the books that matter offline always have covers;
backend#499 makes URLs stable-per-hour + browser-cacheable, shrinking how often the SW even needs to fall back.
Still open from this ticket: the Authorization-blind cache key (per-user /api/book/my-books cached under a non-user-scoped URL). Options are clearing SW data caches on logout or dropping the dataGroup once an offline-manifest shelf fallback exists — leaving this ticket open for that decision.
Fix approach revised while implementing (spikersoft-angular PR #595): the ticket proposed dropping the dataGroup `maxAge` to ≤ the presigned TTL, but `reading-journey.loadBooks()` renders the shelf **solely** from `getMyBooks()` — there is no offline-manifest fallback — so a 30m `maxAge` would empty the shelf after half an hour offline, breaking the offline-reading scenario the SW cache exists to support.
Shipped instead:
- shelf grid / hero / quick-view degrade to the placeholder on `img` error (dead presigned URL) rather than a broken image;
- downloaded books render from an offline-persisted cover blob (#880), so the books that matter offline always have covers;
- backend#499 makes URLs stable-per-hour + browser-cacheable, shrinking how often the SW even needs to fall back.
Still open from this ticket: the Authorization-blind cache key (per-user `/api/book/my-books` cached under a non-user-scoped URL). Options are clearing SW data caches on logout or dropping the dataGroup once an offline-manifest shelf fallback exists — leaving this ticket open for that decision.
Audited against origin/master — one narrow item left. Staying open for it.
The ticket's literal ## Fix was deliberately not implemented, and that's correct.projects/spikersoft/ngsw-config.json:86-93 still carries "maxAge": "7d". Per comment 13369, dropping it to the presigned TTL would empty the shelf offline — the cure was worse than the disease. Not a gap; recording it so nobody "fixes" it later.
Shipped instead (angular PR #595, 5ca8e589): cover-error → placeholder degrade at my-books-shelf.component.html:35,101 and book-quick-view-dialog.component.html:21, plus the offline cover blobs from #880. Backend PR #499 supplies stable memoized presigned URLs so browsers can cache covers at all.
Genuinely still open: the Authorization-blind cache key. There is no logout-time purge of the SW data cache — git grep -n 'caches\.delete\|caches\.keys' origin/master hits only art-asset-mesh-blob-cache.ts and offline-cache.service.ts, neither tied to logout, and the api-book-metadata dataGroup is still registered. So after a logout/login on a shared device, one user's cached /api/book/* responses remain servable to the next. That's the remaining work.
Audited against `origin/master` — **one narrow item left. Staying open for it.**
**The ticket's literal `## Fix` was deliberately not implemented, and that's correct.** `projects/spikersoft/ngsw-config.json:86-93` still carries `"maxAge": "7d"`. Per comment 13369, dropping it to the presigned TTL would empty the shelf offline — the cure was worse than the disease. Not a gap; recording it so nobody "fixes" it later.
**Shipped instead** (angular PR #595, `5ca8e589`): cover-error → placeholder degrade at `my-books-shelf.component.html:35,101` and `book-quick-view-dialog.component.html:21`, plus the offline cover blobs from #880. Backend PR #499 supplies stable memoized presigned URLs so browsers can cache covers at all.
**Genuinely still open: the Authorization-blind cache key.** There is no logout-time purge of the SW data cache — `git grep -n 'caches\.delete\|caches\.keys' origin/master` hits only `art-asset-mesh-blob-cache.ts` and `offline-cache.service.ts`, neither tied to logout, and the `api-book-metadata` dataGroup is still registered. So after a logout/login on a shared device, one user's cached `/api/book/*` responses remain servable to the next. That's the remaining work.
Partly addressed, with a deliberate deviation — two things remain.
spikersoft-angular#595 landed the graceful degradation: the shelf grid, continue-reading hero and quick-view dialog now fall back to the placeholder on img (error) instead of showing a broken image, and #880's offline cover blobs cover downloaded books.
Still open, per the PR's own notes and verified on master:
maxAge was NOT reduced — projects/spikersoft/ngsw-config.json:86-93 still has api-book-metadata at "maxAge": "7d". That was a deliberate call: reading-journey.loadBooks() renders the shelf solely from getMyBooks() with no offline-manifest fallback, so cutting to 30m would empty the shelf after half an hour offline — breaking exactly the case offline download exists for. Worth recording as the decision rather than an oversight.
The Authorization-blind cache key is untouched — ngsw dataGroups key on URL and ignore the Authorization header, so per-user /api/book/my-books responses are still cached under a non-user-scoped URL. A logout/login as a different user in the same browser can still be served the previous user's book list. That's the real remaining defect here.
— 2026-08-06 tracker sweep, Opus 5 Agent. Staying open.
**Partly addressed, with a deliberate deviation — two things remain.**
spikersoft-angular#595 landed the graceful degradation: the shelf grid, continue-reading hero and quick-view dialog now fall back to the placeholder on `img (error)` instead of showing a broken image, and #880's offline cover blobs cover downloaded books.
Still open, per the PR's own notes and verified on master:
1. **`maxAge` was NOT reduced** — `projects/spikersoft/ngsw-config.json:86-93` still has `api-book-metadata` at `"maxAge": "7d"`. That was a deliberate call: `reading-journey.loadBooks()` renders the shelf solely from `getMyBooks()` with no offline-manifest fallback, so cutting to 30m would empty the shelf after half an hour offline — breaking exactly the case offline download exists for. Worth recording as the decision rather than an oversight.
2. **The Authorization-blind cache key is untouched** — ngsw dataGroups key on URL and ignore the `Authorization` header, so per-user `/api/book/my-books` responses are still cached under a non-user-scoped URL. A logout/login as a different user in the same browser can still be served the previous user's book list. That's the real remaining defect here.
— 2026-08-06 tracker sweep, Opus 5 Agent. Staying open.
Verified 2026-08-07. angular@8e5a4048: #595 cover-error degrade shipped; maxAge 7d deliberately retained; no logout-time caches.delete so per-user /api/book/* stays cross-user servable
Status: Only the Authorization-blind cache key: either purge the SW data caches on logout, or drop the api-book-metadata dataGroup once an offline-manifest shelf fallback exists. Do not reduce maxAge — that is a recorded decision, not an oversight.
Closing here. Work now lives in the repo that holds the fix, so fixes #655 in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only.
— Opus 5 Agent
Migrated to **spikerj/spikersoft-angular#655** as part of the umbrella-tracker breakup.
Verified 2026-08-07. angular@8e5a4048: #595 cover-error degrade shipped; maxAge 7d deliberately retained; no logout-time caches.delete so per-user /api/book/* stays cross-user servable
Status: Only the Authorization-blind cache key: either purge the SW data caches on logout, or drop the `api-book-metadata` dataGroup once an offline-manifest shelf fallback exists. **Do not** reduce `maxAge` — that is a recorded decision, not an oversight.
Closing here. Work now lives in the repo that holds the fix, so `fixes #655` in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only.
— Opus 5 Agent
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Problem
projects/spikersoft/ngsw-config.jsondataGroupapi-book-metadatacacheshttps://api.spikersoft.com/api/book/*withstrategy: "freshness",maxAge: "7d",timeout: "3s". But the payload carries short-lived presigned MinIO URLs (coverUrl,coverVariants[].url) that expire ~1–2h after minting (2h TTL after spikersoft-backend#499).Any freshness fallback — network slower than the 3s timeout, or offline — serves a book list where every cover URL is already dead, so every cover renders broken. Art Studio has no equivalent dataGroup and thus no equivalent exposure.
Secondary caveat (same dataGroup)
ngsw dataGroups key on URL and ignore the
Authorizationheader, so per-user/api/book/my-booksresponses are cached under a URL that isn't user-scoped — a logout/login as a different user on the same browser can be served the previous user's cached book list until the network responds.Fix
Drop
maxAgefor the cover-bearing book-list routes to ≤ the presigned TTL window (e.g.30m), so any JSON the SW is willing to serve still contains live URLs. The epub-resource/page dataGroups (api-epub-resources,api-epub-pages) are more specific, match first, and are unaffected.Related: spikersoft-backend#499 (stable memoized cover URLs), #618, #719.
Fix approach revised while implementing (spikersoft-angular PR #595): the ticket proposed dropping the dataGroup
maxAgeto ≤ the presigned TTL, butreading-journey.loadBooks()renders the shelf solely fromgetMyBooks()— there is no offline-manifest fallback — so a 30mmaxAgewould empty the shelf after half an hour offline, breaking the offline-reading scenario the SW cache exists to support.Shipped instead:
imgerror (dead presigned URL) rather than a broken image;Still open from this ticket: the Authorization-blind cache key (per-user
/api/book/my-bookscached under a non-user-scoped URL). Options are clearing SW data caches on logout or dropping the dataGroup once an offline-manifest shelf fallback exists — leaving this ticket open for that decision.Audited against
origin/master— one narrow item left. Staying open for it.The ticket's literal
## Fixwas deliberately not implemented, and that's correct.projects/spikersoft/ngsw-config.json:86-93still carries"maxAge": "7d". Per comment 13369, dropping it to the presigned TTL would empty the shelf offline — the cure was worse than the disease. Not a gap; recording it so nobody "fixes" it later.Shipped instead (angular PR #595,
5ca8e589): cover-error → placeholder degrade atmy-books-shelf.component.html:35,101andbook-quick-view-dialog.component.html:21, plus the offline cover blobs from #880. Backend PR #499 supplies stable memoized presigned URLs so browsers can cache covers at all.Genuinely still open: the Authorization-blind cache key. There is no logout-time purge of the SW data cache —
git grep -n 'caches\.delete\|caches\.keys' origin/masterhits onlyart-asset-mesh-blob-cache.tsandoffline-cache.service.ts, neither tied to logout, and theapi-book-metadatadataGroup is still registered. So after a logout/login on a shared device, one user's cached/api/book/*responses remain servable to the next. That's the remaining work.Partly addressed, with a deliberate deviation — two things remain.
spikersoft-angular#595 landed the graceful degradation: the shelf grid, continue-reading hero and quick-view dialog now fall back to the placeholder on
img (error)instead of showing a broken image, and #880's offline cover blobs cover downloaded books.Still open, per the PR's own notes and verified on master:
maxAgewas NOT reduced —projects/spikersoft/ngsw-config.json:86-93still hasapi-book-metadataat"maxAge": "7d". That was a deliberate call:reading-journey.loadBooks()renders the shelf solely fromgetMyBooks()with no offline-manifest fallback, so cutting to 30m would empty the shelf after half an hour offline — breaking exactly the case offline download exists for. Worth recording as the decision rather than an oversight.Authorizationheader, so per-user/api/book/my-booksresponses are still cached under a non-user-scoped URL. A logout/login as a different user in the same browser can still be served the previous user's book list. That's the real remaining defect here.— 2026-08-06 tracker sweep, Opus 5 Agent. Staying open.
Migrated to spikerj/spikersoft-angular#655 as part of the umbrella-tracker breakup.
Verified 2026-08-07. angular@8e5a4048: #595 cover-error degrade shipped; maxAge 7d deliberately retained; no logout-time caches.delete so per-user /api/book/* stays cross-user servable
Status: Only the Authorization-blind cache key: either purge the SW data caches on logout, or drop the
api-book-metadatadataGroup once an offline-manifest shelf fallback exists. Do not reducemaxAge— that is a recorded decision, not an oversight.Closing here. Work now lives in the repo that holds the fix, so
fixes #655in a PR will auto-close it on merge. The umbrella tracker keeps cross-repo epics only.— Opus 5 Agent