katheryn-website/backlog/tasks/task-12 - Fix-store-page-im...

4.2 KiB

id title status assignee created_date updated_date labels dependencies priority
TASK-12 Fix store page images blocked by Cloudflare Access Done
2026-02-13 20:03 2026-02-13 22:01
bug
store
infrastructure
high

Description

Store page images not loading because Directus CMS (katheryn-cms.jeffemmett.com) is behind Cloudflare Access (Zero Trust). The Next.js image optimizer gets a 302 redirect to a login page instead of the actual image. Also the artwork detail page was a client component making browser-side API calls to Directus, which were also blocked.

Acceptance Criteria

  • #1 Store listing page images load correctly
  • #2 Artwork detail page images load correctly
  • #3 Detail page data fetching happens server-side (not browser)
  • #4 Cart functionality still works on detail page

Implementation Notes

Root Cause

Directus CMS (katheryn-cms.jeffemmett.com) is behind Cloudflare Access (Zero Trust). The Next.js image optimizer gets a 302 redirect to a Cloudflare login page instead of the actual image. Additionally, Next.js has SSRF protection that blocks fetching from private IPs (Docker internal network resolves to 192.168.x.x).

Fix Applied (commits 41d784e2523a30)

Solution: API Route Proxy

Created /api/assets/[id] route that proxies Directus assets server-side:

  • Browser fetches /api/assets/[id]?width=...&format=webp (same-origin)
  • API route fetches from DIRECTUS_INTERNAL_URL (http://katheryn-cms:8055) on Docker internal network
  • Bypasses Cloudflare Access (internal network) and SSRF protection (same-origin URL)
  • Directus handles image transformations (width, quality, format)
  • Response cached with Cache-Control: public, max-age=31536000, immutable

Other changes

  • getAssetUrl() now returns /api/assets/[id]?params (local path, no token needed)
  • Directus SDK client uses DIRECTUS_INTERNAL_URL for server-side API calls
  • Store detail page converted from client to server component
  • Added images.localPatterns for /api/assets/** in next.config.ts
  • Added /app/.next/cache as tmpfs for read-only container

Files changed

  • frontend/src/app/api/assets/[id]/route.ts - NEW: asset proxy API route
  • frontend/src/lib/directus.ts - simplified getAssetUrl, internal SDK URL
  • frontend/next.config.ts - localPatterns config
  • frontend/Dockerfile - cleaned up unnecessary build args
  • frontend/docker-compose.yml - cache tmpfs, cleaned up env vars
  • frontend/src/app/store/[slug]/page.tsx - server component
  • frontend/src/app/store/[slug]/artwork-detail-client.tsx - NEW: client component

Automatic Inventory Management (da77476)

After fixing images, also fixed store data filtering:

  • Store was showing 656 items (all artworks with any USD/GBP price)
  • Investigated Directus data: 2,324 total artworks, 639 with USD price (imported catalog), only 19 with GBP price (real store items)
  • USD-only items are imported historical catalog data (missing images, dimensions, creation dates, internal notes)
  • Added forSale filter to getArtworks() using compound Directus _and filter
  • Store-ready criteria: name (not empty) + image (uploaded) + price_gbp (> 0) + status published
  • Artworks auto-appear when fields populated, auto-move to sold section on status change
  • Related works on detail page also filtered to store-ready items only

Commits: 9489418, 4744709, da77476

2026-02-13: Additional fix — removed search: '' from localPatterns in next.config.ts. This was blocking Next.js image optimizer from accepting /api/assets URLs with query params (width, quality, format), returning 400 "url parameter is not allowed". Commit 09567ce, deployed to staging.

Session 2026-02-13: Fixed PayPal MULTI_CURRENCY_ORDER error (hardcoded GBP throughout checkout). Added PayPal client ID as Docker build arg. Added custom favicons across all deployed sites: KT monogram (katheryn-staging), no-dollar symbol (nofi.lol), retro gamepad (games.jeffemmett.com), CT monogram (cynthia-poetry). Added katheryn-website to auto-deploy webhook. All four sites rebuilt and deployed.