capsule AI-native Unix-like composition layer

capsule.yaml

3,418 bytes · 99 lines · capsule://quake0day/[email protected] raw on github

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).