Add bookshelf ISBN/paper enrichment, fix status field name collision

apps/cms/src/utils/bookshelf-covers.ts fetches book covers from Open
Library by ISBN (real image, cached into apps/site/public/covers/)
and backfills missing title/authors for papers from Semantic Scholar
by DOI/arXiv id. Wired into the sync middleware in content-sync.ts:
runs once per entry (cover_image already set means "done"), and only
on live create/update through Strapi, not during the boot-time
import (so a restart doesn't hammer external APIs).

Also renames the bookshelf `status` field to `read_status`
everywhere (schema, content/README.md, seed content, Astro zod
schema, bookshelf page, sync mapping). Strapi's content-manager API
treats a top-level `status` key as its own reserved draft/publish
parameter even with draftAndPublish disabled, so an attribute
literally named `status` silently rejected every write — caught this
while testing the enrichment hook.

Verified end-to-end: created a book by ISBN with no cover_image,
confirmed a real cover image was downloaded and cached, cover_image
was set on the entry and written to the file, and the cover/file were
both removed on delete.
This commit is contained in:
2026-08-30 18:52:39 +03:00
parent 85efb824ae
commit 62db772dad
10 changed files with 167 additions and 28 deletions
+16 -8
View File
@@ -27,14 +27,22 @@ approved plan for full rationale on each decision referenced below.
## Content pipeline
- [ ] Strapi custom provider/lifecycle hooks that read + write the same
Markdown files in `content/` (Strapi's DB stays a disposable cache)
- [ ] Verify round-trip: edit in Strapi admin → file on disk updates, and
vice versa, without drift
- [ ] Bookshelf ISBN lookup hook (Open Library / Google Books) with local
cover caching
- [ ] Bookshelf paper lookup hook (Semantic Scholar / arXiv) with local
cover/thumbnail caching
- [x] Strapi custom provider/lifecycle hooks that read + write the same
Markdown files in `content/` (Strapi's DB stays a disposable cache) —
`apps/cms/src/utils/content-{file,sync}.ts`, wired in `src/index.ts`
- [x] Verify round-trip: edit in Strapi admin → file on disk updates, and
vice versa, without drift — verified create/update/delete via the
content-manager API, plus idempotent re-import across a restart
- [x] Bookshelf ISBN lookup hook with local cover caching —
`apps/cms/src/utils/bookshelf-covers.ts` fetches from Open Library by
ISBN and caches into `apps/site/public/covers/`; verified end-to-end
(real cover downloaded, `cover_image` synced to file, cleaned up on
delete)
- [x] Bookshelf paper lookup hook — Semantic Scholar backfills title/authors
by DOI/arXiv id when missing. No cover/thumbnail: neither Semantic
Scholar nor arXiv offers a reliable image source for papers, so
`cover_image` stays manually-set for papers (or gets one later from
the OG-image pipeline below)
- [ ] OG image auto-generation extended from the legacy per-post script to
all three content types (writings, portfolio, bookshelf)
- [ ] `llms.txt` generation extended to cover all content types, not just