yingjieli-content-store v1.0.0
subsystem yingjieli.site
capsule://quake0day/yingjieli-content-store@1.0.0
Single source of truth for all editable site content of yingjieliartist.com:
hero, bio, exhibitions, contact, and the works catalog. Backed by Cloudflare
KV (binding YL_DATA) with an in-code DEFAULT_DATA fallback for first boot.
Owns
- the schema of the site-content blob (hero, bio, exhibitions, contact, works[])
- GET /api/data (public read, 30s edge cache + stale-while-revalidate)
- PUT /api/data (admin-only full replace)
- POST /api/data?seed=1 (admin-only reset to DEFAULT_DATA)
- DEFAULT_DATA seed (used if KV is empty)
- the next-work-number helper (zero-padded 3-digit num)
Does not own
- storage of image bytes (see yingjieli-image-store; this capsule only keeps the file *reference*)
- who is allowed to write (see yingjieli-admin-auth; this capsule calls isAuthed())
- HTML rendering (see yingjieli-public-site / yingjieli-admin-ui)
AI orientation
This is the content store. Everything visible on the public site that an
admin can edit lives in one JSON blob at KV key `site:data:v1`. The blob
has a fixed top-level shape — hero, bio, exhibitions, contact, works —
and PUT validates that shape exists before writing. Do NOT introduce
additional KV keys for site content; everything goes in this one blob so
edits are atomic.
Avoid
- Sharding the content blob across multiple KV keys (breaks atomic edits).
- Reading or writing KV from anywhere outside this capsule's helpers.
- Storing raw image bytes in this blob; only filename references.
Extension points
default-dataatsite/functions/_lib/data.js:DEFAULT_DATA- The shape that ships when KV is empty. Adding a new field here is
also a contract change for the admin UI and the public site —
update both consumers in the same change. write-validatoratsite/functions/api/data.js:onRequest (PUT branch)- Currently checks presence + array-ness for `works` and `exhibitions`.
Strengthen here (do NOT push validation into the admin UI).
Provides
http_api:data-read— GET /api/data → full content JSON. Public.http_api:data-write— PUT /api/data → replace full content blob. Admin only.library:data-helpers— readData(env), writeData(env, data), nextWorkNum(works), DEFAULT_DATA.
Requires
library:auth-helpersfromyingjieli-admin-auth— isAuthed(request, env) is called for PUT and seed.env:YL_DATA— Cloudflare KV namespace binding. Provided by yingjieli-cloudflare-deploy.
Dependencies
Capsules
yingjieli-admin-auth>=1.0.0 <2.0.0
Runtime
node>=18cloudflare-pages*
Invariants (must always hold)
- The content blob always has exactly these top-level keys; PUT rejects anything missing.
- Two PUTs are linearised by KV; partial writes never appear.
- DEFAULT_DATA is what an empty KV returns — there is no other fallback path.
- Image filenames in `works[].file` reference keys served by yingjieli-image-store or static /images/.
Glossary
works- ordered list of artwork records (num, file, title, year, w, h, gallery?)
hero- the featured artwork pointer shown on the homepage
seed- admin-triggered reset of the KV blob back to DEFAULT_DATA