# Agent-Friendly Design Specification: ShopWave (E-commerce)

> Generated by Agentify · 2025-03-20

## Table of Contents
- [1. Executive Summary](#1-executive-summary)
- [2. Semantic HTML](#2-semantic-html)
- [3. ARIA Patterns](#3-aria-patterns)
- [4. Naming Conventions](#4-naming-conventions)
- [5. Structured Data](#5-structured-data)
- [6. Form Patterns](#6-form-patterns)

> Truncated example showing expected depth for the first 6 sections.

---

## 1. Executive Summary

ShopWave is a Next.js e-commerce platform. Agent-friendliness is critical because:
- **Price comparison agents** need reliable product data extraction
- **Shopping assistants** need to navigate, filter, and add to cart
- **SEO crawlers** need structured data for rich results
- **Automated testing** needs stable selectors surviving redesigns

Target: improve from D (55) to A (90+).

---

## 2. Semantic HTML

### 2.1 Page Structure (P0)

```html
<body>
  <a href="#main-content" class="skip-link">Skip to content</a>
  <header data-testid="site-header">
    <nav aria-label="Main navigation" data-testid="main-nav">...</nav>
  </header>
  <nav aria-label="Breadcrumb" data-testid="breadcrumb">...</nav>
  <main id="main-content" data-testid="main-content">
    <h1>Page Title</h1>
  </main>
  <aside data-testid="sidebar">...</aside>
  <footer data-testid="site-footer">
    <nav aria-label="Footer navigation" data-testid="footer-nav">...</nav>
  </footer>
</body>
```

### 2.2 Product Card (P0)

```jsx
<article data-testid="product-card" data-entity-type="product" data-entity-id={product.slug}>
  <a href={`/products/${product.slug}`} data-testid="product-link">
    <img src={product.image} alt={product.name} data-testid="product-image" />
    <h2 data-testid="product-name">{product.name}</h2>
  </a>
  <p data-testid="product-price">
    <data value={product.price}>{formatPrice(product.price)}</data>
  </p>
  <button data-testid="add-to-cart-btn" data-action="add-to-cart"
          aria-label={`Add ${product.name} to cart`}
          onClick={() => addToCart(product.id)}>
    Add to Cart
  </button>
</article>
```

---

## 3. ARIA Patterns

### 3.1 Cart Button (P0)

```jsx
<button data-testid="cart-toggle"
        aria-label={`Shopping cart, ${itemCount} items`}
        aria-expanded={isCartOpen ? "true" : "false"}
        aria-controls="cart-dropdown">
  <CartIcon aria-hidden="true" />
  <span data-testid="cart-count" aria-hidden="true">{itemCount}</span>
</button>
```

### 3.2 Product Filters (P0)

```jsx
<aside aria-label="Product filters" data-testid="filter-panel">
  <fieldset data-testid="filter-price">
    <legend>Price Range</legend>
    <label htmlFor="price-min">Minimum price</label>
    <input id="price-min" type="number" name="priceMin" data-testid="price-min-input" />
    <label htmlFor="price-max">Maximum price</label>
    <input id="price-max" type="number" name="priceMax" data-testid="price-max-input" />
  </fieldset>
  <div aria-live="polite" data-testid="filter-results-count">
    {resultCount} products found
  </div>
</aside>
```

### 3.3 Quantity Selector (P1)

```jsx
<div role="group" aria-labelledby="qty-label" data-testid="quantity-selector">
  <span id="qty-label">Quantity</span>
  <button aria-label="Decrease quantity" data-testid="qty-decrease"
          onClick={() => setQty(qty - 1)} disabled={qty <= 1}>−</button>
  <input type="number" value={qty} min="1" max="99"
         aria-label="Quantity" data-testid="qty-input" />
  <button aria-label="Increase quantity" data-testid="qty-increase"
          onClick={() => setQty(qty + 1)}>+</button>
</div>
```

---

## 4. Naming Conventions

### 4.1 data-testid Scheme (P0)

Format: `{component}-{element}-{type}`

| Element | data-testid |
|---------|-------------|
| Product card | `product-card` |
| Product title | `product-name` |
| Add to cart | `add-to-cart-btn` |
| Cart item row | `cart-item` |
| Cart remove | `cart-item-remove-btn` |
| Checkout form | `checkout-form` |
| Email input | `email-input` |
| Search input | `search-input` |

### 4.2 Entity Attributes (P1)

```jsx
<article data-entity-type="product" data-entity-id="wireless-headphones-pro">
```

---

## 5. Structured Data

### 5.1 Product Page (P0)

```json
{
  "@context": "https://schema.org",
  "@type": "Product",
  "name": "Wireless Headphones Pro",
  "image": "https://shopwave.com/images/whp.jpg",
  "sku": "WHP-001",
  "brand": { "@type": "Brand", "name": "ShopWave Audio" },
  "offers": {
    "@type": "Offer",
    "price": "149.99",
    "priceCurrency": "USD",
    "availability": "https://schema.org/InStock"
  },
  "aggregateRating": {
    "@type": "AggregateRating",
    "ratingValue": "4.5",
    "reviewCount": "128"
  }
}
```

### 5.2 Breadcrumbs (P1)

```json
{
  "@context": "https://schema.org",
  "@type": "BreadcrumbList",
  "itemListElement": [
    { "@type": "ListItem", "position": 1, "name": "Home", "item": "https://shopwave.com" },
    { "@type": "ListItem", "position": 2, "name": "Electronics", "item": "https://shopwave.com/electronics" },
    { "@type": "ListItem", "position": 3, "name": "Headphones" }
  ]
}
```

### 5.3 Homepage (P1)

```json
{
  "@context": "https://schema.org",
  "@type": "WebSite",
  "name": "ShopWave",
  "url": "https://shopwave.com",
  "potentialAction": {
    "@type": "SearchAction",
    "target": "https://shopwave.com/search?q={search_term_string}",
    "query-input": "required name=search_term_string"
  }
}
```

---

## 6. Form Patterns

### 6.1 Checkout Form (P0)

```jsx
<form data-testid="checkout-form" onSubmit={handleCheckout}>
  <fieldset>
    <legend>Contact Information</legend>
    <label htmlFor="checkout-email">Email address</label>
    <input id="checkout-email" type="email" name="email"
           autoComplete="email" required data-testid="checkout-email-input"
           aria-describedby={emailError ? "email-error" : undefined}
           aria-invalid={emailError ? "true" : undefined} />
    {emailError && (
      <span id="email-error" role="alert" data-testid="email-error">{emailError}</span>
    )}
  </fieldset>
  <fieldset>
    <legend>Shipping Address</legend>
    <label htmlFor="checkout-street">Street address</label>
    <input id="checkout-street" type="text" name="street"
           autoComplete="street-address" required data-testid="checkout-street-input" />
    <label htmlFor="checkout-city">City</label>
    <input id="checkout-city" type="text" name="city"
           autoComplete="address-level2" required data-testid="checkout-city-input" />
    <label htmlFor="checkout-zip">ZIP code</label>
    <input id="checkout-zip" type="text" name="zip" inputMode="numeric"
           autoComplete="postal-code" required data-testid="checkout-zip-input" />
  </fieldset>
  <button type="submit" data-testid="checkout-submit-btn" data-action="place-order">
    Place Order
  </button>
</form>
```
