# Product Page Conversion Upgrade - Web Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Turn the buyer item detail page into a fuller, trust-building, conversion-focused product page. The page should help shoppers evaluate the exact resale item, trust the seller, understand shipping/returns, and continue shopping if this item is not the right fit.

**Primary route:** `web/src/app/(buyer)/items/[id]/page.tsx` and `web/src/app/(buyer)/items/[id]/item-detail-client.tsx`.

**Companion API plan:** `alqove-api/api/docs/superpowers/plans/2026-07-06-product-page-conversion-api-plan.md`. Tasks marked "API dependent" should consume fields introduced there.

**Current state observed on 2026-07-06:**
- The detail page has a two-column layout: gallery left, product info and CTAs right.
- `ItemGallery` supports thumbnails and a main image, but the fallback is a large empty "No image" panel.
- `ItemDetailData` already includes `description`, `price`, `original_retail`, `condition`, `brand`, `size`, `colors`, `measurements`, leaf `category`, `store`, `images`, `view_count`, `save_count`, `created_at`, and `updated_at`.
- "More from this store" already exists via `useItemSearch`, filtered by `storeId`, then rendered with `ItemGrid`.
- Store rating is queried client-side via `useStoreRatingSummary`.
- The public catalog endpoint is Typesense-backed, so similar-items recommendations can initially reuse the existing browse/search query.

**Implementation update on 2026-07-06:**
- Phase 1/1b product-page conversion work is implemented through the buy box, compact purchase bar, full category breadcrumbs, details grid, condition confidence card, improved gallery empty state, seller trust card, and shipping/returns card.
- The item detail page now consumes enriched `GET /v1/items/{item}` fields: `category_path`, nested `store.average_rating`, `store.review_count`, `store.rating_breakdown`, and `store.policies`.
- The item detail page no longer needs `useStoreRatingSummary` for seller trust when the enriched item payload is present, but keeps top-level rating fallbacks for older responses.
- OpenAPI was synced from the API repo and `packages/types/src/generated.ts` was regenerated.
- Verified commands: `npm run test --workspace=web -- product-buy-box product-purchase-bar product-detail-grid condition-confidence-card item-gallery seller-trust-card shipping-returns-card item-detail-client`, `npm run typecheck`, direct `npm exec --workspace=web tsc -- --noEmit --pretty false`, and `npm run build:web`.

**Implementation update after recommendation rails:**
- `RecommendationRail` is implemented as a reusable presentational wrapper around `ItemGrid`.
- Product detail now renders two continuation rails:
  - `More from {store.name}` using `store_id`.
  - `Similar items` using category slug plus optional brand and size filters.
- Rails exclude the current item and the similar rail also excludes items already shown in the store rail.
- Empty rails collapse; loading rails show the existing `ItemGrid` skeletons.
- Verified commands: `npm run test --workspace=web -- recommendation-rail item-detail-client product-buy-box product-purchase-bar product-detail-grid condition-confidence-card item-gallery seller-trust-card shipping-returns-card`, `npm run typecheck`, direct `npm exec --workspace=web tsc -- --noEmit --pretty false`, and `npm run build:web`.

**Architecture:** Keep `page.tsx` as the server component that fetches the item and emits product JSON-LD. Keep commerce interactions in `item-detail-client.tsx`. Split large UI sections into colocated or shared components only when they are independently testable or reused: gallery/lightbox, sticky buy box, item details grid, trust/policy card, recommendation rails. Prefer server-rendered data for first paint where available; use TanStack Query for related/recommended rows and authenticated cart/save actions.

**Tech Stack:** Next.js 16 App Router, React 19, TypeScript, TanStack Query, Tailwind v4, shadcn/ui primitives, `@alqove/api-client`, `@alqove/types`, Vitest + Testing Library, Playwright for visual/responsive checks.

**Branch:** `feature/product-page-conversion` off `main`.

**Commands:**
```bash
npm run dev:web
npm run test --workspace=web
npm run typecheck --workspaces
npm run lint --workspaces --if-present
npm run build:web
```

**Design principles:**
- The product page should answer buyer doubts before asking for money.
- Photos, condition, measurements, shipping, returns, and seller trust are conversion-critical.
- Avoid marketing-page composition. This is a marketplace product detail workflow.
- Keep the buy path obvious and stable while the user scrolls.
- Do not make the page feel full by adding generic copy. Prefer useful commerce details and continuation paths.

---

## File structure overview

**Likely modify:**
```
web/src/app/(buyer)/items/[id]/item-detail-client.tsx
web/src/app/(buyer)/items/[id]/page.tsx
web/src/components/item-gallery.tsx
web/src/components/item-card.tsx
web/src/lib/seo.ts
packages/types/src/index.ts
packages/api-client/src/endpoints/items.ts
```

**Likely create:**
```
web/src/app/(buyer)/items/[id]/product-breadcrumbs.tsx
web/src/app/(buyer)/items/[id]/product-buy-box.tsx
web/src/app/(buyer)/items/[id]/product-detail-grid.tsx
web/src/app/(buyer)/items/[id]/condition-confidence-card.tsx
web/src/app/(buyer)/items/[id]/shipping-returns-card.tsx
web/src/app/(buyer)/items/[id]/seller-trust-card.tsx
web/src/app/(buyer)/items/[id]/recommendation-rail.tsx
web/src/app/(buyer)/items/[id]/__tests__/*.test.tsx
```

**Optional later:**
```
web/src/lib/queries/use-recently-viewed.ts
web/src/components/product-lightbox.tsx
web/e2e/product-page.spec.ts
```

---

## Task 1 - Restructure the item detail page skeleton

**Goal:** Establish a product-page layout that can support richer content without becoming a long loose stack.

- [x] **Step 1 (baseline):** Read `item-detail-client.tsx`, `ItemGallery`, `ItemGrid`, and existing tests under `web/src/app/(buyer)/items/[id]/__tests__`. Record any current assumptions in the test file or plan notes before changing behavior. _(Baseline focused test passed before edits: `npm run test --workspace=web -- item-detail-client`.)_
- [x] **Step 2:** Split the current right-side detail panel into a `ProductBuyBox` component. Props should be explicit and typed from `ItemDetailData`, not broad `any` objects.
- [x] **Step 3:** Keep the full buy box in normal page flow and show a compact fixed purchase bar once the buy box reaches the header area during scroll. _(Supersedes the original sticky-buy-box idea; the sticky full panel took too much page space while scrolling, and waiting for the full box to leave view was too late on short pages.)_
- [x] **Step 4:** Add a compact top breadcrumb row above the main product grid. Initial implementation can use `Home / category.name / item.title`; after the API companion plan exposes `category_path`, upgrade to the full path.
- [x] **Step 5:** Preserve the current `Add to Cart` mutation behavior and toast behavior. Component tests must still assert success and error toasts.
- [ ] **Step 6:** Verify desktop and mobile layout does not overlap with the buyer header/footer and that the sticky panel does not obscure lower content. _(Compile/live checks passed: focused tests, workspace typecheck scripts, `npm run build:web`, and a live `/items/{id}` HTTP 200. Manual/Playwright visual QA still pending.)_

**Acceptance criteria:**
- The page still loads with the existing `ItemDetailData`.
- Add-to-cart behavior is unchanged.
- Sticky buy box works on desktop and becomes normal flow on mobile.
- Tests cover the extracted buy box or the page-level behavior.

---

## Task 2 - Build a stronger buy box

**Goal:** Make the conversion area answer the core "can I trust this and what happens if I buy?" questions.

- [x] **Step 1:** In `ProductBuyBox`, show price, original retail if present, and savings when `original_retail > price`.
- [x] **Step 2:** Add an availability line: "Only 1 available" for active resale items. Keep it data-light for v1; if inventory is later modeled, wire it to real quantity.
- [x] **Step 3:** Add compact reassurance rows below CTAs:
  - Ships from `{store.city}, {store.state}`
  - Refund protection / "Not as described? You're covered."
  - Secure checkout
- [x] **Step 4 (API dependent):** Replace static shipping text with store settings from the API companion plan: processing days, flat shipping rate, free shipping threshold, return window, and policy text. _(The buy box shows summary facts; `ShippingReturnsCard` shows the detailed policy.)_
- [x] **Step 5:** Add iconography with lucide-react where appropriate: cart, heart, truck, shield/check, rotate/refresh. Do not use emoji in the production UI for these trust rows.
- [x] **Step 6:** On mobile, consider a bottom sticky CTA once the main CTA scrolls off screen. Keep it simple: price + Add to Cart. _(Decision: keep the compact fixed top purchase bar introduced in Task 1 instead of adding a second bottom bar.)_

**Acceptance criteria:**
- CTA area is visually stronger but not noisy.
- The user can see price, availability, shipping origin, and buyer protection before scrolling.
- Button labels do not wrap or overflow on common mobile widths.

---

## Task 3 - Add item details and condition confidence

**Goal:** Make the product feel inspectable, especially for resale where buyers need confidence about size, condition, and measurements.

- [x] **Step 1:** Create `ProductDetailGrid` under the page folder. Render available fields only, with stable two-column desktop layout and one-column mobile layout.
- [x] **Step 2:** Include these fields when present:
  - Brand
  - Size
  - Condition
  - Color(s)
  - Category
  - Measurements
  - Listed date from `created_at`
  - Item ID, shortened for display but copyable in full if useful
- [x] **Step 3:** Create `ConditionConfidenceCard`. Map current condition codes to buyer-friendly labels and descriptions:
  - `NWT`: New with tags
  - `NWOT`: New without tags
  - `EUC`: Excellent used condition
  - `GUC`: Good used condition
  - `Fair`: Fair condition
  - `Poor`: Poor condition
- [x] **Step 4:** Add placeholders for future "flaws noted" and "inspection notes" fields, but do not display empty headings.
- [x] **Step 5:** Move the long description into a structured "Description" section below the buy box/grid area if it reads better there.

**Acceptance criteria:**
- Product details remain useful when optional fields are missing.
- Condition is explained in plain language.
- Tests cover rendering with complete data and sparse data.

---

## Task 4 - Upgrade the media experience

**Goal:** Prevent the product page from feeling barren when images exist, and make missing images look intentional instead of broken.

- [x] **Step 1:** Improve `ItemGallery` fallback. Replace the giant "No image" panel with a designed empty state that uses a neutral product-photo placeholder, compact text, and stable aspect ratio.
- [x] **Step 2:** Add image count and active image state when multiple images exist. _(Implemented as counted main-image alt text and selected thumbnail state; a visible counter can still be added with the lightbox.)_
- [x] **Step 3:** Add click-to-zoom/lightbox for the main image. Use existing dialog primitives if present. _(Main image is now a `cursor-zoom-in` button opening a Radix `Dialog` with the large image, prev/next controls, an `n / total` counter, and ArrowLeft/ArrowRight keyboard nav. Escape + focus trap come from the primitive. Covered by new `item-gallery` lightbox tests.)_
- [x] **Step 4:** Make the thumbnail rail scrollable and keyboard accessible. Include selected state and `aria-label`s.
- [x] **Step 5:** Use `next/image` only if configured safely for local media URLs. Otherwise keep `img` but document why.
- [ ] **Step 6 (data/QA):** Add or seed sample item images locally so the page can be reviewed with realistic media. Coordinate with the API plan if seeders need to attach images.

**Acceptance criteria:**
- Multiple images are easy to browse.
- Missing-image products no longer dominate the page with empty space.
- Lightbox works with keyboard and escape close.
- Gallery tests cover empty, single-image, and multi-image states.

---

## Task 5 - Build seller trust and policy sections

**Goal:** Make seller credibility and fulfillment expectations visible on the page.

- [x] **Step 1:** Replace the current basic seller block with `SellerTrustCard`.
- [x] **Step 2:** Show store name, city/state, verification indicator, rating summary, review count, and `View Store`.
- [x] **Step 3 (API dependent):** Add processing days, return window, shipping rate, and free shipping threshold from the enriched item response.
- [x] **Step 4:** Keep `useStoreRatingSummary` only if the detail response does not yet include the needed review fields. Prefer the server-fetched item response when the API plan lands.
- [x] **Step 5:** Add a `ShippingReturnsCard` near the buy box or below details. Avoid duplicating the exact same facts in two places; the buy box can show the summary and this card can show details.
- [x] **Step 6:** If store has no reviews, render "No reviews yet" without making the seller look risky.

**Acceptance criteria:**
- Seller trust is more than a name badge.
- Policy details are visible before the recommendation rows.
- Page still works before the API companion fields are available.

---

## Task 6 - Recommendation rails

**Goal:** Product pages should not dead-end. If the item is not right, continue the shopping session.

- [x] **Step 1:** Extract the existing related-items logic into a reusable `RecommendationRail` component.
- [x] **Step 2:** Keep "More from this store" using `storeId: [item.store.id]`, excluding the current item.
- [x] **Step 3:** Add "Similar items" using the existing browse endpoint. Start with category slug and optional brand/size/price-adjacent filters. Exclude the current item. _(Implemented with category slug plus optional brand and size; price-adjacent filters can be added later if result quality needs tightening.)_
- [x] **Step 4:** Add empty states that collapse the section entirely when no results exist. Do not show empty headings.
- [x] **Step 5:** Add skeleton states for rails while TanStack Query loads.
- [ ] **Step 6 (later):** Add "Recently viewed" using localStorage, capped to 12 item IDs. Keep it local-only until an account-level recommendation system exists.

**Acceptance criteria:**
- Product detail page has at least one continuation path when related results exist.
- Recommendation rows are not rendered empty.
- Query keys are stable and do not refetch excessively.

---

## Task 7 - SEO and structured data

**Goal:** Keep marketplace product pages search- and share-friendly after layout/data changes.

- [x] **Step 1:** Update product JSON-LD in `page.tsx` with image, brand, condition, price, availability, and seller where available. _(`buildProductJsonLd` now derives `offers.availability` from item status (non-`active` → `OutOfStock`) and emits `offers.seller` as the store `Organization` when a name is present.)_
- [x] **Step 2:** Use enriched API fields for shipping/returns in JSON-LD only if they map cleanly to schema.org. Do not invent precise delivery dates without real data. _(Deliberately omitted `shippingDetails`/delivery estimates — store policy fields don't map to schema.org without inventing precise dates. Only availability/seller/condition were added.)_
- [x] **Step 3:** Update metadata description to include brand/condition/category when present, while staying under reasonable preview length. _(When the item has no description, `generateMetadata` builds a `brand · condition · category` descriptor fallback; a real description still wins and is truncated to 160 chars.)_
- [x] **Step 4:** Ensure missing images do not produce broken Open Graph image values. _(`buildMetadata` falls back to `/og/default.jpg` when `image` is undefined, and JSON-LD `image` is `[]` when no image exists — no empty/broken URLs emitted.)_

**Acceptance criteria:**
- JSON-LD remains valid.
- Metadata generation still handles missing item data and not-found behavior.

---

## Task 8 - Testing, visual QA, and performance

**Goal:** Ensure the richer page stays reliable and responsive.

- [x] **Step 1:** Update existing `item-detail-client` tests for the new sections.
- [x] **Step 2:** Add component tests for:
  - `ProductBuyBox` _(done)_
  - `ProductDetailGrid` _(done)_
  - `ConditionConfidenceCard` _(done)_
  - `ItemGallery` _(done)_
  - `SellerTrustCard` _(done)_
  - `ShippingReturnsCard` _(done)_
  - `RecommendationRail` _(done)_
- [x] **Step 3:** Run focused web tests for the implemented product-page components. _(Full workspace test still optional before PR.)_
- [x] **Step 4:** Run `npm run typecheck --workspaces`. _(Also ran direct web `tsc --noEmit`.)_
- [x] **Step 5:** Run `npm run build:web`.
- [ ] **Step 6:** Use Playwright or screenshots to inspect at least:
  - desktop 1440x900
  - laptop 1280x800
  - mobile 390x844
- [ ] **Step 7:** Check that text does not overflow in CTA buttons, policy cards, seller card, or recommendation cards.
- [ ] **Step 8:** Confirm the page still feels fast. Avoid loading all recommendation rows before first product content paints.

**Acceptance criteria:**
- Tests and typecheck pass.
- Desktop and mobile screenshots look complete and non-overlapping.
- Product page remains usable with no images, one image, or many images.

---

## Suggested implementation order

1. Task 1 - Restructure the page skeleton.
2. Task 2 - Upgrade the buy box.
3. Task 3 - Add item details and condition confidence.
4. Task 4 - Upgrade the media experience.
5. Task 5 - Add seller trust and policy sections.
6. Task 6 - Add recommendation rails.
7. Task 7 - SEO and structured data.
8. Task 8 - Tests and visual QA.

This order gives an immediate conversion lift before deeper API work is required. API-dependent fields can be added as progressive enhancement once the companion plan lands.
