| name | verify-photo |
| description | Drive photo.elianiva.com the way a visitor and the owner do — public gallery and /admin in the browser. Use for verifying UI or image delivery changes in this repo. |
Verify photo.elianiva.com
Scripted way to launch this repo, drive it as a visitor and as the single admin in the browser, and capture proof. No mocks — the real gallery, upload, and edit flows against the shared remote D1/R2. External boundaries already isolated in prod: Cloudflare Access on /admin* and /api/admin* plus in-worker JWT verification (ADR 0007). Verified locally with ACCESS_TEAM_DOMAIN unset so the admin surface runs unauthenticated by design.
Launch
Primary verification instance is the Alchemy dev server at http://localhost:5173 (pnpm dev). Data hits the shared remote D1/R2 (Alchemy remote()), so only one instance at a time. For local HTTPS with a stable hostname, use pnpm dev:local (portless → http://localhost:5173).
pnpm install
pnpm dev
curl -sSf http://localhost:5173/ | head -n 5
Ready when:
GET / on http://localhost:5173 returns 200 with <!doctype html> containing the Foldkit app shell (data-foldkit-app)
Teardown is killing the single pnpm dev process you started. Never pkill -f vite by name breadth — kill the PID you recorded.
kill $DEV_PID
Build-only verification (no server needed):
pnpm typecheck
pnpm test
pnpm build
All three run via turbo (build depends on ^build). pnpm build emits packages/web/dist/ with client chunks foldkit and effect split via manualChunks.
Ports and env:
- Dev URL
http://localhost:5173 (Alchemy dev: { port: 5173, strictPort: true }). Override with BASE=http://localhost:5173 for scripts.
- Optional local HTTPS:
pnpm dev:local → http://localhost:5173 via portless (portless.json appPort: 5173).
- Local dev needs no
ACCESS_TEAM_DOMAIN and no ACCESS_ALLOWED_EMAILS — blank means unauthenticated. Non-dev stages fail closed without both secrets.
- No
.env required for local verification. R2 photo-elianiva-originals and D1 photo-elianiva are remote by default.
If http://localhost:5173 is unreachable or D1 unreachable, stop. Fix the base before writing the skill patch.
Doctor
One read-only check. Run before first drive, after any failed drive, and on every fresh dev session. Do not drive when doctor is red.
.cursor/skills/verify-photo/scripts/doctor.sh
curl -sSf http://localhost:5173/ | grep -q 'data-foldkit-app'
Doctor passes when:
GET / on http://localhost:5173 is 200 and contains the Foldkit app shell
pnpm typecheck is green on the changed scope (full turbo typecheck for release gates)
Doctor failure caused by skill drift (wrong URL) is drift. Fix the skill and retry once before calling the run blocked. A healthy process with a wedged UI state still needs a reset: hard-reload the page or restart the dev server, do not continue driving the stale state.
Drive
Harness: agent-browser for every user path. No RPC probes — verify what the user sees. Prefer stable ARIA roles/names over coordinates.
UI handles that actually exist in this repo:
- Gallery photos by title text or
photoWithTags.id derived aria-label
- Admin header: link
photo.elianiva.com, button Upload photos, toggle buttons with aria-label "2 columns" through "6 columns" and aria-pressed
- Tag filter:
TagManager chips labeled by tag.label, token activeSlug selects one tag
- Edit sheet: fields
title, slug, takenAt, caption, location, camera, lens via draft combo Multi (Foldkit defineMessageUnion)
- Upload dialog:
FileDrop + Multi combo for tag ids + takenAt input, queue rows by QueueItem.id (${name}:${size})
- Lightbox:
selectedId controls mount; keyboard Escape, ArrowLeft, ArrowRight via admin/subscriptions.ts while selectedId !== null
Generic recipes:
Visitor gallery (public):
BASE="${BASE:-http://localhost:5173}"
npx agent-browser open "$BASE/"
npx agent-browser snapshot
npx agent-browser click --role link --name "<photo title>"
npx agent-browser press --key "Escape"
Admin surface (local dev, unauthenticated):
BASE="${BASE:-http://localhost:5173}"
npx agent-browser open "$BASE/admin"
npx agent-browser click --role button --name "Upload photos"
npx agent-browser click --role button --name "Kyoto"
npx agent-browser click --role button --name "Start uploads"
Every feature file in features/ pairs each user action with one literal command and the observable result. Treat quoted names and flags as literal.
Evidence
Capture the action and the resulting state, not just the final screen. Verify side effects alongside what is visible. Mocks only where prod already isolates (Access).
Locations (proof survives cleanup):
.cursor/skills/verify-photo/artifacts/<feature-id>/ — ARIA snapshots (*.aria.txt), screenshots (*.png), curl transcripts where needed
- Each artifact names the feature ID and entry point used
Standards:
- UI proof: ARIA snapshot plus screenshot with app identity visible (
photo.elianiva.com / Elianiva header). npx agent-browser snapshot > .cursor/skills/verify-photo/artifacts/<id>/page.aria.txt and npx agent-browser screenshot .cursor/skills/verify-photo/artifacts/<id>/page.png
- Mutation proof: drive the write in the UI, then read back via a second UI view (re-open the sheet, reload the grid, or open the lightbox) — a toast alone is insufficient.
- Image proof: open the photo's lightbox and assert the
<img src> points at /api/image/<r2Key> and loads (alt text / network 200); headers cache-control: public, max-age=31536000, immutable are exercised implicitly via the proxy.
- Never assert a skipped entry point as verified through a different path. Report unreachable with the attempted command and the missing precondition.
Cleanup
Kill only what you started. Keep proof.
kill $DEV_PID
rm -f /tmp/verify-sample.jpg
Helpers clean residue after every failed iteration too. Do not remove artifacts/. Final teardown runs after the last drive of the run including any re-proofs of harness fixes.
Helpers
Every helper is executable and its invocation is shown in this body.
scripts/doctor.sh — .cursor/skills/verify-photo/scripts/doctor.sh — read-only health check (http://localhost:5173 + Foldkit shell)
scripts/capture.sh — .cursor/skills/verify-photo/scripts/capture.sh gallery-browse — ARIA + screenshot capture via agent-browser into artifacts/<id>/
scripts/rpc.sh — optional low-level RPC helper (defaults to http://localhost:5173)
See features/README.md for the indexed feature map. Keep it honest — a proof that drives one convenient entry point is incomplete when the map lists others.