Landing Pages — Hub Package Pages

mandatory

Estrutura, meta tags Open Graph + Twitter Card, e composição da OG image para páginas de pacote individual no Koder Hub (`hub.koder.dev/apps/{slug}`, `/skills/{slug}`, `/bundles/{slug}`). Garante que sharing via WhatsApp/Facebook/Twitter/etc. mostre ícone + nome + descrição do pacote, não thumbnail genérico.

Spec — Hub Package Pages (Open Graph + Social Sharing)

*tatus:*Normative *pplies to:*Every package page rendered by the Koder Hub web client at https://hub.koder.dev/apps/{slug} (and equivalent under future kpkg.type paths: /skills/{slug}, /bundles/{slug}). *rigin:*Bug observed on 20260429 — sharing a Koder Hub package page via WhatsApp showed the generic Store thumbnail instead of the package's own icon, name and description, because the SPA serves a static OG-tagged index.html for every route.


1. Requirement

*very Hub package page MUST be discoverable to social-media scrapers*— WhatsApp, Facebook, Twitter/X, LinkedIn, Telegram, Slack, iMessage, Discord — with *ackage-specific*Open Graph metadata that yields a rich preview containing:

  1. The package's *con*(the same SVG/PNG master used by the package itself, scaled to OG dimensions).
  2. The package's *ame*(name field in the package's kpkg.toml / Hub catalog entry).
  3. The package's *rief description*(description field, ≤200 chars).

Static SPA-served OG tags are *nsufficient*and violate this spec.

2. Implementation Contract

The Hub backend (products/dev/hub/depot/, currently products/dev/store/depot/) MUST handle package page URLs as follows:

2.1 Routing

The web server intercepts GET requests to /apps/{slug}, /skills/{slug}, /bundles/{slug}. For these routes:

  • If the request comes from a *craper user-agent*(regex covering

    facebookexternalhit, whatsapp, twitterbot, linkedinbot, slackbot, telegrambot, discordbot, applebot, redditbot, pinterest, skypeuripreview), or

  • If the query string contains ?og=1 (manual override for testing), or
  • *lways*(preferred — avoids fragile UA sniffing and benefits humans whose browsers prefetch links),

the server returns a server-rendered HTML shell that contains the *omplete OG/Twitter Card meta block*for the specific package, followed by the SPA hydration script.

The hydrated SPA then takes over for interactive use as before. Result: humans see the same SPA UX, scrapers see correct meta.

2.2 Required meta tags per package page

<!-- Open Graph -->
<meta property="og:type"        content="website">
<meta property="og:site_name"   content="Koder Hub">
<meta property="og:url"         content="https://hub.koder.dev/apps/{slug}">
<meta property="og:title"       content="{name} — Koder Hub">
<meta property="og:description" content="{description}">
<meta property="og:image"       content="https://hub.koder.dev/apps/{slug}/og-image.png">
<meta property="og:image:width"  content="1200">
<meta property="og:image:height" content="630">
<meta property="og:image:alt"   content="{name} — {short_tagline}">

<!-- Twitter / X -->
<meta name="twitter:card"        content="summary_large_image">
<meta name="twitter:title"       content="{name} — Koder Hub">
<meta name="twitter:description" content="{description}">
<meta name="twitter:image"       content="https://hub.koder.dev/apps/{slug}/og-image.png">

<!-- Canonical + page <title>/<meta name="description"> as usual -->
<title>{name} — Koder Hub</title>
<meta name="description" content="{description}">
<link rel="canonical" href="https://hub.koder.dev/apps/{slug}">

2.3 OG image generation

Each package page exposes /apps/{slug}/og-image.png (and equivalent for skills, bundles). The image is *ynamically composed*by the Hub backend with the following layout (1200×630):

  • Left third (400×630): the package's icon, centered, with subtle drop

    shadow and the Hub's accent gradient as background. Icon is the master SVG rasterized to ~360×360 (transparent background preserved).

  • Right two-thirds (800×630): the package's name (large, bold, brand

    font), description (medium, two lines max with ellipsis), and the Koder Hub wordmark + URL in the bottom-right corner.

The composer reads from the catalog entry (no need to fetch the kpkg artifact). Cache the rendered PNG on first request, invalidate on package version bump.

Reference implementation lives in products/dev/hub/depot/handlers/og_image.go (to be created; see ticket).

2.4 Fallback

If the catalog entry is missing icon, name, or description (data integrity failure), serve the generic Hub OG image (hub.koder.dev/og-image.png) with og:title="{slug} — Koder Hub" and a placeholder description, AND emit a backend warning to the audit log so the gap can be fixed.

3. Validation

  • Manual: curl -sA "WhatsApp/2.0" https://hub.koder.dev/apps/koder-talk | grep -E 'og:|twitter:' returns the package-specific block.
  • Automated: a regression test (per policies/regression-tests.kmd) hits the

    endpoint with each of the listed scraper user-agents AND with a regular browser UA, asserting that all required meta tags are present and that the image URL resolves to a non-empty PNG of the correct dimensions.

  • The /k-housekeep audit MUST flag any package in the Hub catalog whose

    page does not return correct OG meta when probed.

4. Coverage of Existing Pages

This spec applies retroactively. When the Hub backend gains the renderer (see ticket), every existing package in the registry is automatically covered without per-package work — the renderer reads from catalog data.

5. Non-Goals

  • Marketing landing pages (<product>.koder.dev/about, etc.) — covered by

    landing-pages/products.kmd. This spec is for the *atalog*pages on the Hub itself, not for product landing pages.

  • Per-package custom OG art. The composer renders a uniform layout for

    every package; allowing custom OG images is a future concern and would open the door to inconsistent shareability.

  • landing-pages/products.kmd — OG conventions for product landing pages

    (1200×630 image, Twitter Card summarylargeimage, etc.)

  • landing-pages/catalog.kmd — top-level catalog page (hub.koder.dev)

    metadata

  • hub-RFC-006-unification-and-rename.md — Hub naming, supersedes "Store"

    references in any future spec text

  • Bug origin: shared a package page via WhatsApp on 20260429; preview

    showed generic Koder Hub thumbnail instead of package-specific.

Source: ../home/koder/dev/koder/meta/docs/stack/specs/landing-pages/packages.kmd