feat: sync Meticulous profiles to coffee.fismen.no #1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/profile-sync"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Mirrors the master profile list from the Meticulous to coffee.fismen.no so the website can show every profile authored on the device, not just the per-shot snapshots embedded in shots already pulled.
GET /api/v1/profile/list, fetches images for any new/changeddisplay.imageURLs, and bulk-POSTs to a new/api/profilesendpoint. Image hashes are tracked inprofile_image_hashes.json(atomic rename) so unchanged images aren't refetched. Failure-isolated from shot sync.profilestable (UUID PK, name, author, last_changed, accent_color, image_hash, image_content_type, image_bytes, profile_json, updated_at) populated by an authenticated bulk-upsert endpoint.image_content_typeis whitelisted to jpeg/png/webp at ingest. Per-row atomic, idempotent across retries.profilestable, addsshots.profile_idcolumn + index, idempotent backfill fromJSON_EXTRACT(profile_json, '$.id')(withJSON_VALIDguard)./profilesindex (cards by shot-count desc),/profiles/{id}detail (hero image, accent stripe, variables list with type-derived units, shot list),/profiles/{id}/image/{hash}.jpeg(immutable cache because hash is in the URL — 404 on hash mismatch).?profile_id=filters the existing shot index with a chip. Profile name on shot detail now links back to the canonical profile.Spec:
docs/superpowers/specs/2026-04-25-profile-sync-design.md. Plan:docs/superpowers/plans/2026-04-25-profile-sync.md.Already deployed and verified end-to-end on coffee.fismen.no (5 profiles synced, image at `f8790296-…/image/cd02de48b620242f5c1b903cebdf03f6.jpeg` returns 29,692 bytes image/jpeg, shot detail links land on the right profile page).
Test Plan
🤖 Generated with Claude Code
Profiles currently exist on the website only as per-shot snapshots in shots.profile_json. This spec adds a master profiles table populated by the Pi forwarder (via /api/v1/profile/list and the device's image endpoint), three new UI surfaces (/profiles index, /profiles/{id} detail, profile filter on shot index), and a backfill of profile_id onto existing shots. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Plan covers schema migration, profile store layer, ingest endpoint, populating shots.profile_id, web handlers + templates for /profiles and /profiles/{id}, image serving with hash-in-URL caching, the forwarder profile-sync job, and the build-and-deploy steps for both sides. Spec adjusted in lockstep so the image URL embeds the hash — otherwise the immutable Cache-Control header would serve stale bytes after a profile-image swap. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Final-review followup: untrusted image_content_type from the forwarder was echoed verbatim by the image endpoint, so a hostile or buggy client could push text/html and turn /profiles/{id}/image/{hash}.jpeg into a same-origin HTML sink. Whitelist to image/jpeg, image/png, image/webp at ingest; reject everything else with 400. Spec text updated to match both the new check and the (correct) per-row transactional behaviour the implementation already had. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>