Admin can now upload a png/jpg event photo (SPEC §8 exception added):
- new image-upload admin field kind with live preview, uploading via
POST /api/admin/upload (fenja-only, type + 5MB validation);
- files stored under data/uploads (gitignored, BIFROST_UPLOAD_DIR
overridable) and served by GET /uploads/[file] with a traversal guard.
Reworks the /pulse event card: the greeting moved inside a taller box, the
"next gathering" label sits above the date + title, and the photo renders
as a top-right background that blends into the indigo via gradient masks.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Establishes the load-bearing type surface for the Backstage rebuild:
- src/admin/resource-types.ts — discriminated unions for Field, Column,
Filter, Action, plus the top-level Resource and ResourceGroup. Strict
per the maintainability bar: a config object missing a required key
fails TypeScript.
- src/admin/validate.ts — validateForResource() derives validation
from the field definitions (required, maxLength, multi-text min/max,
number bounds, date parse, visibleWhen-aware).
- tests/admin-validate.test.ts — 8 cases locking the validator API:
required, maxLength, visibleWhen skip & reveal, multi-text bounds,
number bounds, all-valid, form-null short-circuit.
No consumers yet. Next commit pulls these into admin.css and the
shared layout components.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>