capsule AI-native Unix-like composition layer

capsule.yaml

2,730 bytes · 88 lines · capsule://quake0day/[email protected] raw on github

apiVersion: capsule.dev/v0.1
kind: Capsule

name: yingjieli-admin-ui
version: 1.0.0
type: subsystem
domain: yingjieli.site

maintainers:
  - name: Quake
    email: [email protected]

purpose:
  summary: |
    Password-protected single-page admin panel for editing all site
    content: hero, bio, exhibitions, contact, and the works catalogue
    (with client-side image resize before upload).
  owns:
    - admin/index.html (admin SPA shell)
    - admin/admin.js (login flow, editors, client-side image resize, save)
    - admin/admin.css (admin-only styling)
    - the editing UX (what fields are exposed, save semantics)
  does_not_own:
    - session validation (calls /api/auth, lets the server decide)
    - content schema (consumes the shape returned by /api/data)
    - image upload mechanics (POSTs to /api/upload; doesn't talk to R2)

interfaces:
  provides:
    - kind: http_api
      name: admin-root
      entrypoint: src/admin/index.html

  requires:
    - kind: http_api
      name: auth-login
      from_capsule: yingjieli-admin-auth
    - kind: http_api
      name: auth-status
      from_capsule: yingjieli-admin-auth
    - kind: http_api
      name: data-read
      from_capsule: yingjieli-content-store
    - kind: http_api
      name: data-write
      from_capsule: yingjieli-content-store
    - kind: http_api
      name: image-upload
      from_capsule: yingjieli-image-store

dependencies:
  capsules:
    - name: yingjieli-admin-auth
      version: ">=1.0.0 <2.0.0"
    - name: yingjieli-content-store
      version: ">=1.0.0 <2.0.0"
    - name: yingjieli-image-store
      version: ">=1.0.0 <2.0.0"
  runtime:
    - cloudflare-pages: "*"

agent:
  summary_for_ai: |
    Single-page admin protected by password login. On load calls GET
    /api/auth — if not authenticated, shows login box; otherwise the
    editor. Every save is a full PUT /api/data with the entire blob
    (no partial updates). Images are resized client-side BEFORE upload.

  avoid:
    - Sending partial updates (the API only accepts full-blob PUT).
    - Decoding the yl_admin cookie or reading SESSION_SECRET in the browser.
    - Letting the user pick the final image filename — the server generates it.

verification:
  health_checks:
    - id: admin-html-present
      command: node -e "require('fs').statSync('src/admin/index.html')"
    - id: admin-js-present
      command: node -e "require('fs').statSync('src/admin/admin.js')"

  invariants:
    - The admin UI never bundles ADMIN_PASSWORD or SESSION_SECRET into client code.
    - The admin UI calls /api/auth GET before showing the editor.
    - Saving from the admin UI always replaces the full content blob, never partial.

x-reconstruct:
  install: install.json