> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hiveku.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Storefront Scaffolding

> What the AI agent generates when you ask for a Shopify storefront — pages, components, JSON-LD, sitemap, and the env vars wired in at deploy time.

Once a Shopify connection is active, the AI agent can scaffold the entire storefront in one prompt. This page covers what gets generated and how the pieces fit together.

## The one-prompt flow

> "Build me a shop based on my Shopify products."

The agent calls `shopify_scaffold_product-detail-route`. That single call writes a working storefront with:

* `/products` — server-rendered product list
* `/products/[handle]` — server-rendered product detail with full Product JSON-LD (including `aggregateRating` populated from reviews when present)
* `/cart` — cart page with line edit, qty change, remove
* `/api/cart` — cart route handler (Storefront API mutations)
* `/api/revalidate` — signed-token cache invalidation endpoint
* `/api/shopify-products` — server-side products fetch for client components that can't read server-only env vars
* `<CartProvider>` + `<CartDrawer>` + `<CartButton>` + `<ProductVariantPicker>` components
* The CRO defaults bundle (free shipping, urgency, recently viewed, trust badges)
* `<ProductReviews>` server component on the PDP
* `/account/write-review` — review submission page (linked from workflow review-request emails)

## What ships in HTML on first byte

The wedge over Lovable / Bolt / v0 is what the page looks like before any client JavaScript runs. View-source on a deployed `/products/<handle>` shows:

* Product title, description (server-rendered)
* Price + compare-at-price
* Image with width/height attributes (for CLS)
* Stock urgency badge ("Only N left") when inventory is low
* A full `<script type="application/ld+json">` block with the Product schema:

```json theme={null}
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Single-Origin Coffee Bag",
  "description": "...",
  "sku": "COFFEE-001-12OZ",
  "brand": { "@type": "Brand", "name": "Roastline" },
  "image": ["https://cdn.shopify.com/..."],
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": 4.7,
    "reviewCount": 23,
    "bestRating": 5,
    "worstRating": 1
  },
  "offers": {
    "@type": "Offer",
    "priceCurrency": "USD",
    "price": "18.00",
    "availability": "https://schema.org/InStock",
    "url": "/products/single-origin-coffee-bag"
  }
}
```

Plus a `BreadcrumbList` JSON-LD. Both are picked up by Google's rich-snippet scanner and by AI search crawlers like ChatGPT and Perplexity that don't run JS.

<Note>
  `aggregateRating` only renders when at least one approved review exists. Google's structured-data validator flags ratings with `reviewCount: 0` as invalid markup, so we skip it for products with no reviews yet.
</Note>

## File layout the scaffolder writes

Hiveku project (greenfield, default `@/*` → `./src/*` alias):

```
app/
├── products/
│   ├── page.tsx                    # list
│   └── [handle]/page.tsx           # detail (with JSON-LD)
├── cart/
│   └── page.tsx                    # cart page
├── api/
│   ├── cart/route.ts               # cart mutations
│   ├── revalidate/route.ts         # cache invalidation
│   └── shopify-products/route.ts   # client-component fetch helper
└── account/
    └── write-review/page.tsx       # review submission

src/
├── lib/shopify/
│   └── storefront-client.ts        # Storefront API client + cart fragment + types
└── components/
    ├── cart/
    │   ├── CartContext.tsx         # CartProvider, CartDrawer, CartButton, useCart
    │   └── ProductVariantPicker.tsx # variant + selling-plan picker
    └── cro/
        ├── FreeShippingBar.tsx
        ├── StockUrgency.tsx
        ├── RecentlyViewed.tsx
        ├── TrustBadges.tsx
        └── ProductReviews.tsx
```

For non-greenfield projects (e.g. `@/*` → `./*` with no src/ wrapper), the scaffolder rewrites `src/components/...` paths to `components/...` automatically. See [Retrofitting](/integrations/shopify/retrofitting) for the full alias-aware behavior.

## The cart contract

Cart state follows a deliberate model:

* **Server is the source of truth** for cart contents. Storefront API holds the canonical cart object.
* **Cookie holds the cart id** — `HttpOnly`, set by the route handler on every mutation.
* **`<CartProvider>` holds local UI state** (open/close drawer, last-fetched cart, loading flag).
* **No client-side reconciliation** — every mutation re-renders with whatever Shopify returned.

This avoids the classic stale-cart-vs-actual-cart drift. The drawer always shows what Shopify thinks the cart contains.

## Layout integration

Cart-bearing scaffolds (`cart`, `product-detail-route`, `subscriptions`) require `<CartProvider>` to wrap the app. The scaffolder response includes `needsLayoutWrapper: true` when this hasn't been done yet.

The AI agent should add this to your root `app/layout.tsx`:

```tsx theme={null}
import { CartProvider, CartDrawer } from '@/components/cart/CartContext'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <CartProvider>
          {children}
          <CartDrawer />
        </CartProvider>
      </body>
    </html>
  )
}
```

Without this wrapper, `useCart()` throws and the variant picker crashes on first render.

## Available scaffold features

The AI agent can scaffold any of these on demand. Most users only need `product-detail-route` (the all-in-one); the narrower scaffolds exist for projects with custom PDPs that want to layer specific pieces in.

| Scaffold feature       | Files                                            | Use when                                                                              |
| ---------------------- | ------------------------------------------------ | ------------------------------------------------------------------------------------- |
| `product-detail-route` | All of the above                                 | "Build me a shop." Default for greenfield.                                            |
| `cart`                 | Cart route + components only                     | You have product pages but no cart yet                                                |
| `customer-account`     | `/account/login` + callback + dashboard + orders | Add sign-in + order history                                                           |
| `subscriptions`        | `/account/subscriptions` + actions               | Customer self-service for subs ([Subscriptions](/integrations/shopify/subscriptions)) |
| `reviews`              | Standalone reviews bundle                        | Custom PDP that needs reviews layered in                                              |
| `sitemap`              | `app/sitemap.ts`                                 | SEO — paginated product + collection URLs                                             |
| `storefront-client`    | Just the lib                                     | You're building everything else manually                                              |
| `revalidate-route`     | Just the cache invalidation route                | Same as above                                                                         |

Use AI prompts like:

> "Scaffold the customer account flow for my Shopify store."
> "Add subscriptions to my product pages."
> "Generate a sitemap for my Shopify products."

The agent calls the right tool and reports back what files landed.

## Idempotency

Every scaffolder is idempotent — running the same scaffold twice doesn't overwrite existing files. The response separates `written` (files newly created) from `skipped` (files that already existed). To force overwrite, the AI agent can pass `overwrite: true` when explicitly asked to upgrade a file.

## Env vars wired automatically at deploy

When you deploy a project with a Shopify connection, Hiveku injects:

| Env var                                          | Used by                                              | Public?                                                                       |
| ------------------------------------------------ | ---------------------------------------------------- | ----------------------------------------------------------------------------- |
| `SHOPIFY_SHOP_DOMAIN`                            | Server-side queries                                  | No                                                                            |
| `NEXT_PUBLIC_SHOPIFY_SHOP_DOMAIN`                | Client cart helpers                                  | Yes                                                                           |
| `NEXT_PUBLIC_SHOPIFY_STOREFRONT_TOKEN`           | Storefront GraphQL from client + server              | Yes (per Shopify's design — Storefront tokens are shop-scoped + rate-limited) |
| `SHOPIFY_ADMIN_TOKEN`                            | Server-only Admin GraphQL                            | **No — server only**                                                          |
| `SHOPIFY_API_VERSION`                            | All Shopify API calls                                | No                                                                            |
| `SHOPIFY_REVALIDATION_TOKEN`                     | Webhook → site cache invalidation HMAC               | No                                                                            |
| `NEXT_PUBLIC_SHOPIFY_CONNECTION_ID`              | `<ProductReviews>` (scopes the public reviews fetch) | Yes                                                                           |
| `NEXT_PUBLIC_SHOPIFY_CRO_*`                      | CRO bundle components                                | Yes                                                                           |
| `NEXT_PUBLIC_SHOPIFY_SUBS_*`                     | Subscriptions UI                                     | Yes                                                                           |
| `NEXT_PUBLIC_SHOPIFY_CUSTOMER_ACCOUNT_CLIENT_ID` | Customer Account OAuth                               | Yes                                                                           |
| `SHOPIFY_CUSTOMER_ACCOUNT_REDIRECT_URI`          | Server-side OAuth callback                           | No                                                                            |

You don't have to manage any of this manually. Connect → deploy → it's wired.

## Cache invalidation flow

When inventory or product data changes in Shopify:

<Steps>
  <Step title="Shopify fires a webhook">
    `products/update`, `products/delete`, `collections/update`, etc.
  </Step>

  <Step title="Hiveku verifies + dispatches">
    The webhook receiver at `/api/webhooks/shopify` verifies HMAC, looks up the connection, and finds every deployed site rendering this shop's catalog.
  </Step>

  <Step title="Hiveku calls each site at `/api/revalidate?tag=shopify-products&token=...`">
    Signed-token RPC. The user's site receives it and calls Next.js `revalidateTag('shopify-products')`, which invalidates ISR'd product pages.
  </Step>

  <Step title="Next request to the page re-fetches from Shopify">
    Stale → fresh, in seconds.
  </Step>
</Steps>

You can also force a manual bust with the AI tool `shopify_admin_invalidate_cache` ("My catalog looks stale").

## What's next

<CardGroup cols={2}>
  <Card title="CRO defaults bundle" icon="bolt" href="/integrations/shopify/cro-bundle">
    Free shipping, urgency, recently viewed, trust badges, cart upsell.
  </Card>

  <Card title="Reviews" icon="star" href="/integrations/shopify/reviews">
    First-party headless reviews + JSON-LD `aggregateRating`.
  </Card>

  <Card title="Subscriptions" icon="rotate" href="/integrations/shopify/subscriptions">
    Subscribe-and-save with customer self-service.
  </Card>

  <Card title="Retrofitting an existing project" icon="arrow-up-from-square" href="/integrations/shopify/retrofitting">
    Compat check + dry-run + alias-aware paths.
  </Card>
</CardGroup>
