OctoWiki
Memory Appendix

Octopus Website

Next.js 16 static export at apex octopuscards.io — separate app from client portal, docs, backend; deployed to Cloudflare Pages

Source memory file: project_octopus_website.md · Category: Project / investigation This is a verbatim dump of Claude's persistent memory for the Octopus project. Rendered inside a code block so nothing is altered.

---
name: Octopus Website (marketing site)
description: Next.js 16 static export at apex octopuscards.io — separate app from client portal, docs, backend; deployed to Cloudflare Pages
type: project
originSessionId: a1e9a8ef-0505-4d0d-ae0a-97b98d29076c
---
`frontend/octopus-website/` is the **marketing site** served at the **apex** `https://octopuscards.io/` (NOT `app.`, `api.`, `warden.`, `docs.`). It is a separate Next.js app from:

- `frontend/client/` → client portal at `app.octopuscards.io` (Cloudflare Pages, see `project_client_portal_deploy.md`)
- Go backend → `api.octopuscards.io` / `warden.octopuscards.io` (systemd, `deploy/nginx-octopus.conf`)

## Stack

- **Next.js 16** with `output: 'export'` (static export, no runtime server).
- **Fumadocs** for `/docs/*` MDX content (same repo, same site).
- **`@takumi-rs/image-response`** for build-time OG image rendering (drop-in for `next/og`; prefer this over `next/og` to match existing conventions).
- **Tailwind v4** + custom brand palette in `src/app/global.css` (primary `#ff8426` orange, ink `#1a1c23`).
- Build: `cd frontend/octopus-website && bun run build` → outputs to `out/`.

## Hosting: Cloudflare Pages

The apex is on Cloudflare (Cloudflare NEL reporting headers, CF edge). Deployment is *not* via the `deploy/` systemd scripts — those are only for Go backend and client portal. Treat apex deploys as Cloudflare Pages builds.

**Why:** `curl -sI https://octopuscards.io/` shows Cloudflare edge signatures and `X-Content-Type-Options: nosniff`. This nosniff header has implications — see `feedback_cloudflare_pages_extensionless_routes.md`.

**How to apply:** don't assume nginx/systemd when touching the marketing site. Build artifacts in `out/` ship to Cloudflare Pages. `public/` is copied to the export root, so `public/_headers` and `public/robots.txt` are honored by Cloudflare.

## OG image conventions

- Root brand card: `src/app/opengraph-image.tsx` + `src/app/twitter-image.tsx` (file convention; Next.js auto-injects meta tags on every page that doesn't override).
- Per-doc: `src/app/og/docs/[...slug]/route.tsx` (uses `image.webp` as last slug segment → URL ends `.webp`).
- Per-card: `src/app/og/cards/[slug]/route.tsx` (extensionless URL — relies on `public/_headers` to set `Content-Type: image/png`).
- Cards page metadata at `src/app/cards/[slug]/page.tsx` already declares `openGraph.images = /og/cards/${slug}` — route must exist or the URL 404s silently.

## Assets worth knowing

- Clean raster logo: `public/apple-touch-icon.png` (27KB, transparent octopus mascot). Use this for OG images and image rendering contexts.
- **Avoid** `public/logo.svg`, `public/logo-full.svg`, `public/octopus-icon.svg`, `public/favicon.svg`, `public/octopus-bg.svg` in renderers like Takumi — despite `.svg` extensions they are ~700KB each (embedded base64 PNGs inside SVG shells), not clean vectors.
- Product/card art: `public/cards/*.{png,svg,webp,jpg}` — referenced via `product.image` path in `src/lib/products.ts`.