apiVersion: capsule.dev/v0.1
kind: Capsule
name: yingjieli-content-store
version: 1.0.0
type: subsystem
domain: yingjieli.site
maintainers:
- name: Quake
email: [email protected]
purpose:
summary: |
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.
The DEFAULT_DATA value is injected at reconstruct time from site-data.json,
so the same capsule can power any artist's portfolio.
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)
- the next-work-number helper (zero-padded 3-digit num)
does_not_own:
- storage of image bytes (see yingjieli-image-store)
- who is allowed to write (see yingjieli-admin-auth)
- the values inside DEFAULT_DATA (those come from site-data.json at reconstruct)
interfaces:
provides:
- kind: http_api
name: data-read
entrypoint: src/api/data.js
description: GET /api/data → full content JSON. Public.
- kind: http_api
name: data-write
entrypoint: src/api/data.js
description: PUT /api/data → replace full content blob. Admin only.
- kind: library
name: data-helpers
entrypoint: src/_lib/data.js
description: readData, writeData, nextWorkNum, DEFAULT_DATA.
requires:
- kind: library
name: auth-helpers
from_capsule: yingjieli-admin-auth
description: isAuthed(request, env) is called for PUT and seed.
- kind: env
name: YL_DATA
description: Cloudflare KV namespace binding.
dependencies:
capsules:
- name: yingjieli-admin-auth
version: ">=1.0.0 <2.0.0"
runtime:
- node: ">=18"
- cloudflare-pages: "*"
agent:
summary_for_ai: |
Single source of truth for editable content. 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.
avoid:
- Sharding the content blob across multiple KV keys.
- Reading or writing KV from anywhere outside this capsule's helpers.
- Storing raw image bytes in this blob; only filename references.
verification:
health_checks:
- id: data-lib-syntax-valid
command: node --check src/_lib/data.js
- id: data-api-syntax-valid
command: node --check src/api/data.js
invariants:
- The content blob always has exactly these top-level keys; PUT rejects anything missing.
- 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."
compatibility:
tested_with:
- capsule: yingjieli-admin-auth
versions: ">=1.0.0 <2.0.0"
x-reconstruct:
install: install.json
notes: |
DEFAULT_DATA is templated. install.json's data_injections directive tells
the reconstructor to replace `/* @CAPSULE_DATA */ {}` in the generated
_lib/data.js with the JSON contents of the data input (e.g. site-data.json).