Memory Appendix
Og Image Per Page Routes
When adding /blog/[slug], /cards/[slug], or similar shareable page types to octopus-website, ensure the corresponding /og/<section>/[slug] route handler exists
Source memory file:
feedback_og_image_per_page_routes.md· Category: Feedback / working-preference This is a verbatim dump of Claude's persistent memory for the Octopus project. Rendered inside a code block so nothing is altered.
---
name: New shareable page sections need per-page OG image routes
description: When adding /blog/[slug], /cards/[slug], or similar shareable page types to octopus-website, ensure the corresponding /og/<section>/[slug] route handler exists — page.tsx can declare OG URLs that silently 404
type: feedback
originSessionId: a1e9a8ef-0505-4d0d-ae0a-97b98d29076c
---
When adding a new `/<section>/[slug]` page type to `frontend/octopus-website/` where the pages will be shared on social/chat (cards, blog posts, product detail pages, etc.), create a matching `src/app/og/<section>/[slug]/route.tsx` that renders a per-page OG card — not just the root `opengraph-image.tsx` fallback.
**Why:** We found that `src/app/cards/[slug]/page.tsx` had been declaring:
```ts
openGraph: { images: [{ url: `${SITE_URL}/og/cards/${slug}`, ... }] }
```
…but no route handler existed at that path. Every card page was advertising a **broken 404 OG image URL**. Next.js doesn't warn; the page builds cleanly; unfurlers silently fail. Root OG image does NOT fall back in — an explicit per-page `openGraph.images` override replaces the inherited root, so pages end up worse than pages with no override at all.
**How to apply:**
When you add or review a new shareable page type in `src/app/`:
1. Check `generateMetadata` in the page — does it declare `openGraph.images` or `twitter.images`?
2. If yes, either:
- **Remove** the override (fall back to root `opengraph-image.tsx`) if a generic card is fine, OR
- **Create** the route handler at the exact URL declared, following the pattern in `src/app/og/cards/[slug]/route.tsx` (uses `@takumi-rs/image-response`, `generateStaticParams`, reads brand logo + card art as base64 data URIs at build time).
3. Add `Content-Type: image/png` to `public/_headers` for the new path (see `feedback_cloudflare_pages_extensionless_routes.md`).
4. Verify with `file out/og/<section>/<slug>` that the PNG emitted correctly after build.
**Pattern reference:** `src/app/og/cards/[slug]/route.tsx` — reads product data via `@/lib/products`, composes brand header + product art + name + category chip at 1200×630, works for PNG/SVG/WebP/JPEG card art via a `assetDataUri` helper.
**Skip this for:** legal pages, contact, FAQs, about — these rarely get shared; the inherited root card is appropriate.Notification Scope Discipline
When working on the order notification system (OrderNotifier, email/webhook fanout), keep changes strictly to notification dispatch. Don't refactor wallet refun
Repo Test Coverage
Every new function added to database/repo/ must ship with extensive tests covering happy path, error branches, and edge cases