Skip to content

Latest commit

 

History

History
34 lines (23 loc) · 6.57 KB

File metadata and controls

34 lines (23 loc) · 6.57 KB

Loose ends

State as of 2026-07-08: all 9 kickoff build-order steps complete and committed; SPEC e2e test plan passed 10/10 against real Neon + Cloudinary + Stripe test mode. See docs/VERIFIED.md for the current-docs facts the implementation relies on.

Post-v1 changes (2026-07-08, same day): design system applied; storefront images migrated from next/image to next-cloudinary's CldImage via src/components/PreviewImage.tsx; sharp removed (dimensions now from Cloudinary's upload response); powered-by footer, favicon, cart badge, purchase-clears-cart. See docs/ARCHITECTURE.md + the next-cloudinary section in docs/VERIFIED.md.

Video support added 2026-07-09: the Photos collection ("Media" in the admin) now also accepts video/*. Videos upload as type: authenticated video Originals (NOT private — the private + strict-mode model did not prove a reliable fit for video delivery when tested 2026-07-09 in this environment; authenticated requires a signature on the original and every derived asset regardless of strict-mode config) with eager-generated watermarked derived assets delivered via signed URLs (5s e_preview clip + six so_<N>p stills — see src/lib/cloudinary/README.md and videoTransformations.ts); tags are manual (built-in auto_video_details is dialogue-only, rejected for silent footage); /api/cloudinary/notify flips previewReady when async eager generation completes. The video_preview/video_still named transformations were created in the Cloudinary environment via the Admin API the same day.

Photoset support added 2026-07-09 (later same day): new photosets (title/price/manual tags, join view) + photosetImages (upload, belongs-to photoset, isPreview, no price, no AI) collections; folder ingestion via pnpm payload run scripts/ingest-photoset.ts <folder> "<title>" <priceCents> [tags] (first 4 members flagged preview); members are private images under unshutter/sets/<setId>/<filename-slug> (filename in public_id = readable zip entries; note this makes public_ids guessable — see the accepted-trade-off note below); purchase delivers ONE signed ~10-min zip via generate_archive (buildPhotosetZipUrl.ts); cart/checkout/Orders gained a photoset dimension (CartItem.kind, metadata.photosetIds, Orders photosets rel); deleting a set cascade-deletes members + their Cloudinary assets. Migration history was consolidated the same day into a single 20260709_145911_initial covering the full schema (photos incl. video fields, photosets, orders) — a demo deploy against a fresh database needs exactly one migration, no incremental chain.

Pending

  • Video webhook in dev — Cloudinary can't POST eager_notification_url to localhost, so previewReady never flips automatically in dev: tick the checkbox in the admin once the derived assets exist (or tunnel via ngrok/cloudflared and point NEXT_PUBLIC_SERVER_URL at it).

  • Short videose_preview:duration_5 needs a source longer than ~5s; uploading a shorter clip likely fails eager generation (upload succeeds, previewReady stays false). Surface in admin docs if it bites.

  • Photoset previews are all-visible-if-guessed (accepted, not a bug) — Strict Transformations allowlists t_preview account-wide, so a watermarked low-res rendition of every set member (not just the isPreview ones) is publicly derivable by guessing its public_id. Verified 2026-07-09. Decision: fine to leave — only the full-res original is truly gated. To harden later, upload members as type: authenticated and sign only curated previews. Details in src/lib/cloudinary/README.md (security note).

  • Design system — applied 2026-07-08: src/styles/ sheets imported in (store)/layout.tsx, page-scoping classes added (unshutter-gallery/unshutter-cart/unshutter-download — the sheet's element-only selectors collided across pages sharing the section>ul>li skeleton), height: auto added so aspect-ratio beats next/image's height attribute, photo-page grid placement pinned (image col 1, text col 2). All five views verified in-browser incl. mobile.

  • README.md — rewritten 2026-07-08, modeled on kickoff-cards' README: showcase framing (Cloudinary alongside agent-first platforms), demo beats, quick start incl. Cloudinary console requirements, docs index. Placeholder clone URL (cloudinary-devs/unshutter) — fix when the repo gets a real remote. No LICENSE file exists yet despite the MIT claim (package.json also says MIT) — add one.

  • Stripe CLI — not installed on this machine. STRIPE_WEBHOOK_SECRET in .env is a locally generated value used to sign simulated webhook deliveries during e2e. When the CLI is installed: stripe listen --forward-to localhost:3000/api/stripe/webhook and put its whsec_… in .env. No code change needed.

  • Production migrations — initial migration generated (src/migrations/) and a ci script (payload migrate && pnpm build) exists for clean-database deploys. The demo deployment deliberately does NOT use it: it shares the dev Neon database (schema already pushed, demo data kept), and payload migrate against a push-managed db warns "data loss will occur" — verified 2026-07-08. Demo Vercel build command is plain pnpm build; schema changes reach prod by running dev locally against the shared db. Use pnpm run ci only when deploying against a fresh database.

  • Admin thumbnail 500s — two benign 500s per photo save in dev logs: Payload's /api/photos/file/<name> preview endpoint can't serve bytes because disableLocalStorage: true (by design; Originals live only in Cloudinary). Cosmetic; could be silenced with admin.thumbnailURL pointing at buildPreviewUrl.

  • Port 3000 collision — an unrelated Docker container (Rails welcome app) occupies 3000 on this machine; Next dev auto-binds 3001, but Stripe redirect URLs come from NEXT_PUBLIC_SERVER_URL=http://localhost:3000. Free the port or change the env var when testing checkout locally.

SPEC stretch items (explicitly out of v1)

  • Email receipts/download links (Resend) — webhook already has email + session id; sendDownloadEmail() slots in there.
  • License tiers (entitlement becomes photo+tier, tier caps w_ in signed URL).
  • Galleries/collections taxonomy (Payload relationship field).
  • OG generative fill (b_gen_fill) for awkward aspect ratios — og named transformation is currently plain w_1200,h_630,c_auto,g_auto.

Demo data in place

  • 3 seeded Photos (ids 1–3, Cloudinary unshutter/originals/1..3) and 1 Order (id 4).
  • Admin user admin@example.com — password was reported in the 2026-07-08 build session (change it or reset via DB if lost).