output:
Chunk ID: 146346
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 227
Output:
app/Http/Middleware/CheckStoreRole.php
app/Http/Middleware/ResolveStore.php
app/Models/Collection.php
app/Models/Concerns/BelongsToStore.php
app/Models/Customer.php
app/Models/InventoryItem.php
app/Models/Organization.php
app/Models/Product.php
app/Models/ProductMedia.php
app/Models/ProductOption.php
app/Models/ProductOptionValue.php
app/Models/ProductVariant.php
app/Models/Scopes/StoreScope.php
app/Models/Store.php
app/Models/StoreDomain.php
app/Models/StoreSettings.php
app/Models/StoreUser.php
app/Models/User.php
app/Policies/CollectionPolicy.php
app/Policies/CustomerPolicy.php
app/Policies/DiscountPolicy.php
app/Policies/FulfillmentPolicy.php
app/Policies/OrderPolicy.php
app/Policies/PagePolicy.php
app/Policies/ProductPolicy.php
app/Policies/RefundPolicy.php
app/Policies/StorePolicy.php
app/Policies/ThemePolicy.php
app/Providers/AppServiceProvider.php
app/Providers/FortifyServiceProvider.php


output:
Chunk ID: abd10e
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 538
Output:
<?php

namespace App\Http\Middleware;

use App\Enums\StoreStatus;
use App\Models\Store;
use App\Models\StoreDomain;
use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Cache;
use Symfony\Component\HttpFoundation\Response;

class ResolveStore
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        $store = $request->is('admin*')
            ? $this->resolveAdminStore($request)
            : $this->resolveStorefrontStore($request);

        abort_unless($store, 404);

        app()->instance('current_store', $store);

        if (! $request->is('admin*') && $store->status === StoreStatus::Suspended) {
            abort(503);
        }

        if ($request->is('admin*') && $store->status === StoreStatus::Suspended && ! $request->isMethodSafe()) {
            abort(403);
        }

        return $next($request);
    }

    private function resolveStorefrontStore(Request $request): ?Store
    {
        $hostname = $request->getHost();
        $cacheKey = "store_domain:{$hostname}";

        $storeId = Cache::remember($cacheKey, now()->addMinutes(5), function () use ($hostname): ?int {
            return StoreDomain::query()
                ->where('hostname', $hostname)
                ->value('store_id');
        });

        return $storeId ? Store::query()->find($storeId) : null;
    }

    private function resolveAdminStore(Request $request): ?Store
    {
        $user = $request->user();

        if (! $user) {
            return null;
        }

        $storeId = $request->session()->get('current_store_id');

        if (! $storeId) {
            $storeId = $user->stores()->oldest('stores.id')->value('stores.id');

            if ($storeId) {
                $request->session()->put('current_store_id', $storeId);
            }
        }

        if (! $storeId || ! $user->stores()->whereKey($storeId)->exists()) {
            return null;
        }

        return Store::query()->find($storeId);
    }
}


output:
Chunk ID: fe6b2b
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 272
Output:
<?php

namespace App\Http\Middleware;

use App\Enums\StoreUserRole;
use App\Models\Store;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class CheckStoreRole
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next, string ...$roles): Response
    {
        $store = app()->bound('current_store') ? app('current_store') : null;
        $user = $request->user();

        abort_unless($store instanceof Store && $user, 403);

        $role = $user->roleForStore($store);

        if ($roles === []) {
            abort_unless($role !== null, 403);

            return $next($request);
        }

        $allowedRoles = array_filter(array_map(
            fn (string $role): ?StoreUserRole => StoreUserRole::tryFrom($role),
            $roles,
        ));

        abort_unless($role !== null && in_array($role, $allowedRoles, true), 403);

        return $next($request);
    }
}


output:
Chunk ID: ee4451
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 240
Output:
<?php

use App\Http\Middleware\CheckStoreRole;
use App\Http\Middleware\ResolveStore;
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Exceptions;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withRouting(
        web: __DIR__.'/../routes/web.php',
        commands: __DIR__.'/../routes/console.php',
        health: '/up',
    )
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->alias([
            'role.check' => CheckStoreRole::class,
            'store.resolve' => ResolveStore::class,
        ]);

        $middleware->appendToGroup('storefront', [
            ResolveStore::class,
        ]);

        $middleware->appendToGroup('admin', [
            ResolveStore::class,
            CheckStoreRole::class,
        ]);
    })
    ->withExceptions(function (Exceptions $exceptions): void {
        //
    })->create();


cmd: find app/Enums -maxdepth 1 -type f -print | sort


command: find app/Enums -maxdepth 1 -type f -print | sort

path: Enums

aggregated_output:
app/Enums/CollectionStatus.php
app/Enums/CollectionType.php
app/Enums/InventoryPolicy.php
app/Enums/MediaStatus.php
app/Enums/MediaType.php
app/Enums/ProductStatus.php
app/Enums/StoreDomainType.php
app/Enums/StoreStatus.php
app/Enums/StoreUserRole.php
app/Enums/VariantStatus.php

status: completed


output:
Chunk ID: 6bc5c4
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 70
Output:
app/Enums/CollectionStatus.php
app/Enums/CollectionType.php
app/Enums/InventoryPolicy.php
app/Enums/MediaStatus.php
app/Enums/MediaType.php
app/Enums/ProductStatus.php
app/Enums/StoreDomainType.php
app/Enums/StoreStatus.php
app/Enums/StoreUserRole.php
app/Enums/VariantStatus.php


cmd: sed -n '1,320p' specs/04-STOREFRONT-UI.md


cmd: rg -n "Products|Collections|Catalog|Product detail|Collection|Search|Admin|Storefront" specs/02-API-ROUTES.md specs/03-ADMIN-UI.md specs/04-STOREFRONT-UI.md specs/08-PLAYWRIGHT-E2E-PLAN.md


command: sed -n '1,320p' specs/04-STOREFRONT-UI.md

type: read

aggregated_output:
# 04 - Storefront UI/UX Specification

> E-commerce platform - Customer-facing storefront UI/UX requirements

---

## Conventions

| Convention | Detail |
|---|---|
| CSS Framework | Tailwind CSS v4, mobile-first design, dark mode support |
| Interactivity | Livewire v4 for all dynamic UI (cart, filters, checkout) |
| Templating | Blade templates with reusable storefront-prefixed components |
| Accessibility | WCAG 2.2 AA compliance throughout |
| Responsive | Mobile-first with progressive enhancement at small, medium, large, and extra-large breakpoints |
| Currency | All prices stored as integers (cents), formatted with locale-aware helpers |
| Images | Lazy-loaded, with proper alt text and maintained aspect ratios |

---

## Currency Formatting

All monetary amounts are stored as integers in minor units (cents) and must be formatted for display according to these rules:

| Setting | Value |
|---------|-------|
| Decimal separator | `.` (period) |
| Thousands separator | `,` (comma) |
| Currency symbol | After amount with space (e.g., `24.99 EUR`) |
| Decimal places | Always 2 |
| Free amounts | Display as `0.00 EUR` |
| Negative amounts (refunds) | Prefix with `-` (e.g., `-12.50 EUR`) |

**Helper:** Use a shared Blade component or helper (e.g., `<x-price :amount="$amount" :currency="$currency" />`) to ensure consistent formatting across all storefront pages.

**Examples:**
- 2499 cents -> `24.99 EUR`
- 0 cents -> `0.00 EUR`
- 149900 cents -> `1,499.00 EUR`

---

## 1. Theme System Architecture

### 1.1 View Organization

The storefront views are organized into the following categories:

| Category | Purpose | Views |
|---|---|---|
| Layouts | Master page shell | app (master layout) |
| Pages | Core storefront pages | home, collection, product, cart, search, page (static CMS) |
| Checkout | Purchase flow | checkout index, order confirmation |
| Account | Customer area | login, register, dashboard, orders (list + detail), addresses |
| Errors | Error states | 404, 503 |
| Components | Reusable UI elements | product-card, price, badge, quantity-selector, address-form, order-summary, breadcrumbs, pagination |

### 1.2 Layout Hierarchy

All storefront pages extend a single master layout, which provides the full page shell including header, footer, cart drawer, and global Livewire listeners. Individual page templates fill the main content section.

### 1.3 Theme Settings

Theme settings are stored in the database as JSON (keyed by theme ID). A singleton service loads and caches the active theme settings for the current store. Settings control:

- Announcement bar visibility, text, link, and background color
- Sticky header toggle
- Home page section order and visibility
- Color palette overrides (primary, secondary, accent)
- Typography scale
- Footer content and social links
- Dark mode behavior (system preference, toggle, or forced)

### 1.4 Section-Based Architecture

Each page is composed of configurable sections. Sections are Blade includes or Livewire components receiving configuration from theme settings.

| Section | Description | Used On |
|---|---|---|
| Hero | Full-width banner with heading, subheading, call-to-action | Home |
| Featured Collections | Grid of collection cards | Home |
| Featured Products | Grid of product cards (lazy-loaded) | Home |
| Newsletter | Email signup form | Home, Footer |
| Rich Text | Customizable content block | Home, Pages |

### 1.5 Blade Components

All reusable UI elements are implemented as Blade components with a storefront prefix. See Section 16 for the full component library reference.

---

## 2. Base Layout

### 2.1 Document Head

The document head includes:

| Element | Description |
|---|---|
| Character encoding | UTF-8 |
| Viewport | Width = device width, initial scale 1 |
| Meta description | Page-specific, yielded from child templates |
| Title | Page-specific title appended with the app name |
| Stylesheets | Compiled CSS via Vite |
| Scripts | Compiled JS via Vite |
| Livewire styles | Injected by Livewire |
| Language attribute | Set on the HTML element from application locale |
| Scroll behavior | Smooth scrolling enabled globally |

### 2.2 Skip Link

A visually hidden "Skip to main content" link is the first element in the body. It becomes visible on keyboard focus, positioned fixed at top-left with a clear visual treatment (solid background, shadow, focus ring). Supports dark mode.

**Accessibility:** Allows keyboard users to bypass the header navigation and jump directly to the main content area.

### 2.3 Announcement Bar

Optional, controlled by theme settings. Renders a full-width bar above the header.

| Attribute | Description |
|---|---|
| Position | Full-width, above the header |
| Background | Configurable color, defaults to dark background (light text) / inverted in dark mode |
| Text | Centered, small size, configurable content |
| Link | Optional, underlined, opens in same tab |
| Dismiss | Close button (X icon) on the right side; dismis…3336 chars truncated… | Row of icon links (Facebook, Instagram, Twitter/X, TikTok, YouTube) configured in theme settings. Each with screen reader label. Icons are 20x20, muted color with hover to full contrast |
| Copyright line | Small muted text: "(c) {year} {store name}. All rights reserved." |
| Payment method icons | Row of SVG icons for accepted payment methods (Visa, Mastercard, Amex, PayPal, etc.). Slightly reduced opacity |
| Spacing | Generous vertical padding, content constrained to max-width container with horizontal padding |
| Background | Light gray (dark: very dark gray), top border separator |

### 2.7 Cart Drawer (Livewire)

The cart drawer is always present in the layout as a global Livewire component. It listens for the "cart-updated" browser event to refresh and open. See Section 6 for full specification.

### 2.8 Dark Mode

Dark mode is implemented via Tailwind's dark variant. The behavior is controlled by theme settings:

| Mode | Implementation |
|---|---|
| System preference (default) | Follows OS-level dark mode preference automatically |
| Toggle | User-controlled toggle button in header/footer; preference stored in localStorage |
| Forced light/dark | Applied at server render time on the HTML element |

**Color Token Patterns:**

| Token | Light Mode | Dark Mode |
|---|---|---|
| Page background | White | Near-black |
| Card/section background | Light gray | Very dark gray |
| Heading text | Near-black | White |
| Body text | Medium gray | Light gray |
| Borders | Light gray | Medium-dark gray |
| Primary actions | Blue, darkens on hover | Slightly lighter blue, lightens on hover |

---

## 3. Home Page (GET /)

The home page renders sections in the order defined by theme settings. Each section can be toggled on/off and reordered. Default section order:

1. Hero Banner
2. Featured Collections
3. Featured Products
4. Newsletter Signup
5. Rich Text

### 3.1 Hero Banner Section

**Layout:** Full-width container (no max-width on the outer wrapper). Inner content constrained to standard max-width.

**Desktop (large breakpoint and above):**

```
+--------------------------------------------------------------+
|                                                               |
|  [Background Image / Gradient]                                |
|                                                               |
|       [Heading - very large, bold]                            |
|       [Subheading - medium, regular weight]                   |
|       [CTA Button - primary, large]                           |
|                                                               |
+--------------------------------------------------------------+
```

| Attribute | Description |
|---|---|
| Background | Full-width image (cover, centered) or gradient. Image set via theme settings. Semi-transparent dark overlay for text readability |
| Content | Centered vertically and horizontally, white text |
| Heading | H1 or H2 depending on context. Very large on desktop, progressively smaller on mobile. Bold, tight tracking |
| Subheading | Regular paragraph, medium size, generous top margin. Constrained to a comfortable reading width |
| CTA | Styled as primary button, large. Links to a configured collection or product |
| Height | Minimum 600px on desktop, 500px on tablet, 400px on mobile, 300px on small mobile |
| Padding | Generous vertical and horizontal padding |

**Mobile:** Same structure but stacked, with reduced font sizes and shorter minimum height. Full-bleed background image remains.

**Accessibility:**

- If background is an image, it is decorative (the content provides meaning)
- CTA button has descriptive text (e.g., "Shop the summer collection")

### 3.2 Featured Collections Section

**Layout:** Section with heading and grid of collection cards.

| Attribute | Description |
|---|---|
| Section heading | H2, large, bold, centered, with generous bottom margin |
| Grid | 2 columns on mobile, 4 columns on large screens, with gap spacing |
| Count | 2 to 4 collections, configurable in theme settings |

**Collection Card:**

```
+---------------------------+
|  [Collection Image]       |
|  3:4 aspect ratio         |
|  cover-fit, rounded       |
|                           |
|  [Title overlay at bottom]|
|  [Shop now ->]            |
+---------------------------+
```

| Element | Description |
|---|---|
| Image | 3:4 aspect ratio, cover-fit, rounded corners. Gradient overlay at bottom fading from transparent to semi-transparent dark |
| Title | White text overlaid at bottom of image, semi-bold, medium-large size |
| "Shop now" link | Small white text below title, slightly transparent, underlined. Becomes fully opaque on hover |
| Interaction | Entire card is clickable. Subtle scale-up on hover with smooth transition |

**Accessibility:**

- Each card link has the collection title as accessible name
- Images have alt text matching the collection title

### 3.3 Featured Products Section

**Livewire Component:** FeaturedProducts


command:
/bin/zsh
-lc
sed -n '1,260p' specs/03-ADMIN-UI.md

cmd: sed -n '1,260p' specs/03-ADMIN-UI.md

aggregated_output:
# 03 - Admin Panel UI/UX Specification

This document defines every view, component, and interaction for the admin panel. The admin is entirely server-rendered using Laravel 12 + Livewire v4 + Flux UI Free components + Tailwind CSS v4. There is no SPA or client-side router.

**Flux UI Free components available:** avatar, badge, brand, breadcrumbs, button, callout, checkbox, dropdown, field, heading, icon, input, modal, navbar, profile, radio, select, separator, switch, text, textarea, tooltip

Anything not covered by Flux UI Free uses plain Tailwind CSS v4 markup with Livewire directives.

---

## 1. Admin Layout Shell

The admin layout is a persistent shell that wraps every admin page. It consists of a left sidebar, a top bar, and a main content area.

### 1.1 Route Prefix

All admin routes live under `/admin` and are protected by authentication middleware plus store-scoping middleware. The store is resolved from the session or a store-selector in the top bar.

### 1.2 Sidebar Navigation

**Livewire component:** `App\Livewire\Admin\Layout\Sidebar`

**Blade view:** `resources/views/livewire/admin/layout/sidebar.blade.php`

#### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `collapsed` | `bool` | Whether the sidebar is collapsed (mobile state) |
| `currentRoute` | `string` | The current route name for active highlighting |

| Action | Behavior |
|--------|----------|
| `toggle()` | Toggles the `collapsed` state |

#### Wireframe

```
+-------------------------------+
|  [BRAND LOGO]  Platform Name  |
|-------------------------------|
|  [separator]                  |
|                               |
|  [chart-bar]    Dashboard     |
|                               |
|  PRODUCTS                     |
|  [cube]         Products      |
|  [rect-stack]   Collections   |
|  [archive-box]  Inventory     |
|                               |
|  [separator]                  |
|  ORDERS                       |
|  [shopping-bag] Orders        |
|                               |
|  [separator]                  |
|  CUSTOMERS                    |
|  [users]        Customers     |
|                               |
|  [separator]                  |
|  DISCOUNTS                    |
|  [tag]          Discounts     |
|                               |
|  [separator]                  |
|  CONTENT                      |
|  [doc-text]     Pages         |
|  [bars-3]       Navigation    |
|  [paint-brush]  Themes        |
|                               |
|  [separator]                  |
|  [chart-pie]    Analytics     |
|  [cog-6-tooth]  Settings      |
|  [squares-2x2]  Apps          |
|  [code-bracket] Developers    |
+-------------------------------+
```

#### Navigation Structure

```
Dashboard                        -> admin.dashboard
Products (group label)
  Products                       -> admin.products.index
  Collections                    -> admin.collections.index
  Inventory                      -> admin.inventory.index
Orders
  Orders                         -> admin.orders.index
Customers
  Customers                      -> admin.customers.index
Discounts
  Discounts                      -> admin.discounts.index
Content (group label)
  Pages                          -> admin.pages.index
  Navigation                     -> admin.navigation.index
  Themes                         -> admin.themes.index
Analytics                        -> admin.analytics.index
Settings                         -> admin.settings.index
Apps                             -> admin.apps.index
Developers                       -> admin.developers.index
```

Each nav item displays an icon (via Flux icon component) and a text label. The active item receives a highlighted background and bold text. All navigation links use Livewire SPA-style page transitions. Groups are visually separated with Flux separator components.

#### Flux Component Mapping

| UI Element | Flux Component |
|-----------|----------------|
| Platform logo and name | `brand` |
| Navigation icons | `icon` |
| Group dividers | `separator` |

#### Responsive Behavior

- **Desktop (lg and above):** Sidebar is always visible, fixed left, 256px wide. Main content has a left margin of 256px.
- **Mobile (below lg):** Sidebar is hidden off-screen. A hamburger button (icon: bars-3) appears in the top bar. When user clicks it, the sidebar slides in as an overlay with a semi-transparent backdrop. Clicking the backdrop or a nav item closes it.

### 1.3 Top Bar

**Livewire component:** `App\Livewire\Admin\Layout\TopBar`

**Blade view:** `resources/views/livewire/admin/layout/top-bar.blade.php`

#### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `currentStoreName` | `string` | Name of the active store |
| `stores` | `Collection` | List of stores the user has access to |
| `unreadNotificationCount` | `int` | Count of unread notifications |

| Action | Behavior |
|--------|----------|
| `switchStore(string $storeId…965 chars truncated…ng

| UI Element | Flux Component |
|-----------|----------------|
| Store selector | `dropdown` |
| Hamburger (mobile) | `button` (icon: bars-3) |
| Notification bell | `button` (icon: bell, variant: ghost) |
| Notification count | `badge` |
| User profile trigger | `profile` |
| Profile menu | `dropdown` |
| Menu divider | `separator` |

### 1.4 Main Content Area

The main content area sits to the right of the sidebar and below the top bar. Every page renders within this area.

**Breadcrumbs:** Every page includes a Flux breadcrumbs component at the top of the content area. The first item is always "Home" linking to `/admin`. Subsequent items reflect the page hierarchy. Example for product edit: Home > Products > "Blue T-Shirt".

**Layout wrapper:** The content area has consistent padding (larger on desktop, smaller on mobile) and a max-width container centered horizontally.

### 1.5 Toast Notifications

A global toast notification system lives in the layout shell. It uses Alpine.js to listen for Livewire dispatched events.

| Property | Value |
|----------|-------|
| Event name | `toast` |
| Payload | `{ type: 'success' / 'error' / 'info', message: string }` |
| Position | Top-right corner |
| Auto-dismiss | 5 seconds |
| Stacking | Supports multiple toasts |
| Styling | Rounded card, shadow, colored left border (green=success, red=error, blue=info) |

Components dispatch toasts after successful actions (e.g., "Product saved successfully.") or on errors ("Something went wrong. Please try again.").

### 1.6 Dark Mode

The admin supports dark mode via Tailwind's `dark:` variant. The mode follows the user's system preference by default. A toggle can be added in the profile dropdown later. All components and custom markup must include dark mode variants.

Dark mode preference is persisted in `localStorage` under the key `theme` with values `light` or `dark`. On page load, the stored preference is applied before first paint to avoid flash of incorrect theme. If no preference is stored, the system preference (`prefers-color-scheme`) is used as default.

---

## 2. Dashboard

**Route:** `GET /admin`

**Livewire component:** `App\Livewire\Admin\Dashboard`

**Blade view:** `resources/views/livewire/admin/dashboard.blade.php`

### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `dateRange` | `string` | Active date range preset: `today`, `last_7_days`, `last_30_days`, `custom` |
| `customStartDate` | `?string` | Custom range start (Y-m-d) |
| `customEndDate` | `?string` | Custom range end (Y-m-d) |
| `totalSales` | `int` | Total sales amount in minor units |
| `ordersCount` | `int` | Number of orders in range |
| `averageOrderValue` | `int` | Average order value in minor units |
| `visitorsCount` | `int` | Unique visitors in range |
| `salesChange` | `float` | Percentage change vs previous period |
| `ordersChange` | `float` | Percentage change vs previous period |
| `aovChange` | `float` | Percentage change vs previous period |
| `visitorsChange` | `float` | Percentage change vs previous period |
| `ordersChartData` | `array` | Array of `{date, count}` for last 30 days |
| `topProducts` | `array` | Top 5 products: `{title, units_sold, revenue}` |
| `funnelData` | `array` | Funnel steps: `{visits, add_to_cart, checkout_started, checkout_completed}` |

| Action | Behavior |
|--------|----------|
| `updatedDateRange()` | Re-fetches all KPI data for the selected range |
| `loadKpis()` | Queries aggregated order/analytics data |
| `loadChart()` | Queries daily order counts for chart |
| `loadTopProducts()` | Queries top 5 products by revenue |
| `loadFunnel()` | Queries conversion funnel data |

| Computed Property | Purpose |
|-------------------|---------|
| `formattedTotalSales` | Formatted currency string |
| `formattedAov` | Formatted currency string |

### Wireframe

```
+------------------------------------------------------------------+
| Dashboard                           [Today v] (date range picker) |
+------------------------------------------------------------------+
|                                                                    |
|  +-------------+  +-------------+  +-------------+  +----------+  |
|  | Total Sales |  | Orders      |  | Avg Order   |  | Visitors |  |
|  | $12,345     |  | 156         |  | $79.13      |  | 2,340    |  |
|  | [+12.3%] ^  |  | [+8.1%] ^  |  | [-2.1%] v  |  | [+5%] ^  |  |
|  +-------------+  +-------------+  +-------------+  +----------+  |
|                                                                    |
|  +--------------------------------------------------------------+  |
|  | Orders over time                                              |  |
|  |  [line/bar chart - daily order counts for selected range]     |  |
|  +--------------------------------------------------------------+  |
|                                                                    |
|  +------------------------------+  +----------------------------+  |


output:
Chunk ID: d24bf5
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2742
Output:
# 03 - Admin Panel UI/UX Specification

This document defines every view, component, and interaction for the admin panel. The admin is entirely server-rendered using Laravel 12 + Livewire v4 + Flux UI Free components + Tailwind CSS v4. There is no SPA or client-side router.

**Flux UI Free components available:** avatar, badge, brand, breadcrumbs, button, callout, checkbox, dropdown, field, heading, icon, input, modal, navbar, profile, radio, select, separator, switch, text, textarea, tooltip

Anything not covered by Flux UI Free uses plain Tailwind CSS v4 markup with Livewire directives.

---

## 1. Admin Layout Shell

The admin layout is a persistent shell that wraps every admin page. It consists of a left sidebar, a top bar, and a main content area.

### 1.1 Route Prefix

All admin routes live under `/admin` and are protected by authentication middleware plus store-scoping middleware. The store is resolved from the session or a store-selector in the top bar.

### 1.2 Sidebar Navigation

**Livewire component:** `App\Livewire\Admin\Layout\Sidebar`

**Blade view:** `resources/views/livewire/admin/layout/sidebar.blade.php`

#### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `collapsed` | `bool` | Whether the sidebar is collapsed (mobile state) |
| `currentRoute` | `string` | The current route name for active highlighting |

| Action | Behavior |
|--------|----------|
| `toggle()` | Toggles the `collapsed` state |

#### Wireframe

```
+-------------------------------+
|  [BRAND LOGO]  Platform Name  |
|-------------------------------|
|  [separator]                  |
|                               |
|  [chart-bar]    Dashboard     |
|                               |
|  PRODUCTS                     |
|  [cube]         Products      |
|  [rect-stack]   Collections   |
|  [archive-box]  Inventory     |
|                               |
|  [separator]                  |
|  ORDERS                       |
|  [shopping-bag] Orders        |
|                               |
|  [separator]                  |
|  CUSTOMERS                    |
|  [users]        Customers     |
|                               |
|  [separator]                  |
|  DISCOUNTS                    |
|  [tag]          Discounts     |
|                               |
|  [separator]                  |
|  CONTENT                      |
|  [doc-text]     Pages         |
|  [bars-3]       Navigation    |
|  [paint-brush]  Themes        |
|                               |
|  [separator]                  |
|  [chart-pie]    Analytics     |
|  [cog-6-tooth]  Settings      |
|  [squares-2x2]  Apps          |
|  [code-bracket] Developers    |
+-------------------------------+
```

#### Navigation Structure

```
Dashboard                        -> admin.dashboard
Products (group label)
  Products                       -> admin.products.index
  Collections                    -> admin.collections.index
  Inventory                      -> admin.inventory.index
Orders
  Orders                         -> admin.orders.index
Customers
  Customers                      -> admin.customers.index
Discounts
  Discounts                      -> admin.discounts.index
Content (group label)
  Pages                          -> admin.pages.index
  Navigation                     -> admin.navigation.index
  Themes                         -> admin.themes.index
Analytics                        -> admin.analytics.index
Settings                         -> admin.settings.index
Apps                             -> admin.apps.index
Developers                       -> admin.developers.index
```

Each nav item displays an icon (via Flux icon component) and a text label. The active item receives a highlighted background and bold text. All navigation links use Livewire SPA-style page transitions. Groups are visually separated with Flux separator components.

#### Flux Component Mapping

| UI Element | Flux Component |
|-----------|----------------|
| Platform logo and name | `brand` |
| Navigation icons | `icon` |
| Group dividers | `separator` |

#### Responsive Behavior

- **Desktop (lg and above):** Sidebar is always visible, fixed left, 256px wide. Main content has a left margin of 256px.
- **Mobile (below lg):** Sidebar is hidden off-screen. A hamburger button (icon: bars-3) appears in the top bar. When user clicks it, the sidebar slides in as an overlay with a semi-transparent backdrop. Clicking the backdrop or a nav item closes it.

### 1.3 Top Bar

**Livewire component:** `App\Livewire\Admin\Layout\TopBar`

**Blade view:** `resources/views/livewire/admin/layout/top-bar.blade.php`

#### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `currentStoreName` | `string` | Name of the active store |
| `stores` | `Collection` | List of stores the user has access to |
| `unreadNotificationCount` | `int` | Count of unread notifications |

| Action | Behavior |
|--------|----------|
| `switchStore(string $storeId)` | Switches active store in session, redirects to dashboard |

#### Wireframe

```
+--------------------------------------------------------------------+
| [hamburger*]  [Store Name v]                  [bell(3)]  [avatar v] |
+--------------------------------------------------------------------+
  * hamburger visible on mobile only

  Store Name dropdown:
    - Store A
    - Store B
    - Store C

  Avatar dropdown:
    - Settings (links to /admin/settings)
    - [separator]
    - Log out (POST /logout with CSRF)
```

#### Interaction Flows

- When user clicks the store name, a dropdown appears listing all stores. Clicking a store calls `switchStore()` which updates the session and redirects to the dashboard.
- Notification bell shows an unread count badge (positioned absolutely over the icon) when `unreadNotificationCount > 0`.
- Profile dropdown is triggered by a Flux profile component showing the user's avatar and name.

#### Flux Component Mapping

| UI Element | Flux Component |
|-----------|----------------|
| Store selector | `dropdown` |
| Hamburger (mobile) | `button` (icon: bars-3) |
| Notification bell | `button` (icon: bell, variant: ghost) |
| Notification count | `badge` |
| User profile trigger | `profile` |
| Profile menu | `dropdown` |
| Menu divider | `separator` |

### 1.4 Main Content Area

The main content area sits to the right of the sidebar and below the top bar. Every page renders within this area.

**Breadcrumbs:** Every page includes a Flux breadcrumbs component at the top of the content area. The first item is always "Home" linking to `/admin`. Subsequent items reflect the page hierarchy. Example for product edit: Home > Products > "Blue T-Shirt".

**Layout wrapper:** The content area has consistent padding (larger on desktop, smaller on mobile) and a max-width container centered horizontally.

### 1.5 Toast Notifications

A global toast notification system lives in the layout shell. It uses Alpine.js to listen for Livewire dispatched events.

| Property | Value |
|----------|-------|
| Event name | `toast` |
| Payload | `{ type: 'success' / 'error' / 'info', message: string }` |
| Position | Top-right corner |
| Auto-dismiss | 5 seconds |
| Stacking | Supports multiple toasts |
| Styling | Rounded card, shadow, colored left border (green=success, red=error, blue=info) |

Components dispatch toasts after successful actions (e.g., "Product saved successfully.") or on errors ("Something went wrong. Please try again.").

### 1.6 Dark Mode

The admin supports dark mode via Tailwind's `dark:` variant. The mode follows the user's system preference by default. A toggle can be added in the profile dropdown later. All components and custom markup must include dark mode variants.

Dark mode preference is persisted in `localStorage` under the key `theme` with values `light` or `dark`. On page load, the stored preference is applied before first paint to avoid flash of incorrect theme. If no preference is stored, the system preference (`prefers-color-scheme`) is used as default.

---

## 2. Dashboard

**Route:** `GET /admin`

**Livewire component:** `App\Livewire\Admin\Dashboard`

**Blade view:** `resources/views/livewire/admin/dashboard.blade.php`

### Component Requirements

| Property | Type | Purpose |
|----------|------|---------|
| `dateRange` | `string` | Active date range preset: `today`, `last_7_days`, `last_30_days`, `custom` |
| `customStartDate` | `?string` | Custom range start (Y-m-d) |
| `customEndDate` | `?string` | Custom range end (Y-m-d) |
| `totalSales` | `int` | Total sales amount in minor units |
| `ordersCount` | `int` | Number of orders in range |
| `averageOrderValue` | `int` | Average order value in minor units |
| `visitorsCount` | `int` | Unique visitors in range |
| `salesChange` | `float` | Percentage change vs previous period |
| `ordersChange` | `float` | Percentage change vs previous period |
| `aovChange` | `float` | Percentage change vs previous period |
| `visitorsChange` | `float` | Percentage change vs previous period |
| `ordersChartData` | `array` | Array of `{date, count}` for last 30 days |
| `topProducts` | `array` | Top 5 products: `{title, units_sold, revenue}` |
| `funnelData` | `array` | Funnel steps: `{visits, add_to_cart, checkout_started, checkout_completed}` |

| Action | Behavior |
|--------|----------|
| `updatedDateRange()` | Re-fetches all KPI data for the selected range |
| `loadKpis()` | Queries aggregated order/analytics data |
| `loadChart()` | Queries daily order counts for chart |
| `loadTopProducts()` | Queries top 5 products by revenue |
| `loadFunnel()` | Queries conversion funnel data |

| Computed Property | Purpose |
|-------------------|---------|
| `formattedTotalSales` | Formatted currency string |
| `formattedAov` | Formatted currency string |

### Wireframe

```
+------------------------------------------------------------------+
| Dashboard                           [Today v] (date range picker) |
+------------------------------------------------------------------+
|                                                                    |
|  +-------------+  +-------------+  +-------------+  +----------+  |
|  | Total Sales |  | Orders      |  | Avg Order   |  | Visitors |  |
|  | $12,345     |  | 156         |  | $79.13      |  | 2,340    |  |
|  | [+12.3%] ^  |  | [+8.1%] ^  |  | [-2.1%] v  |  | [+5%] ^  |  |
|  +-------------+  +-------------+  +-------------+  +----------+  |
|                                                                    |
|  +--------------------------------------------------------------+  |
|  | Orders over time                                              |  |
|  |  [line/bar chart - daily order counts for selected range]     |  |
|  +--------------------------------------------------------------+  |
|                                                                    |
|  +------------------------------+  +----------------------------+  |


output:
Chunk ID: c94225
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 3334
Output:
# 04 - Storefront UI/UX Specification

> E-commerce platform - Customer-facing storefront UI/UX requirements

---

## Conventions

| Convention | Detail |
|---|---|
| CSS Framework | Tailwind CSS v4, mobile-first design, dark mode support |
| Interactivity | Livewire v4 for all dynamic UI (cart, filters, checkout) |
| Templating | Blade templates with reusable storefront-prefixed components |
| Accessibility | WCAG 2.2 AA compliance throughout |
| Responsive | Mobile-first with progressive enhancement at small, medium, large, and extra-large breakpoints |
| Currency | All prices stored as integers (cents), formatted with locale-aware helpers |
| Images | Lazy-loaded, with proper alt text and maintained aspect ratios |

---

## Currency Formatting

All monetary amounts are stored as integers in minor units (cents) and must be formatted for display according to these rules:

| Setting | Value |
|---------|-------|
| Decimal separator | `.` (period) |
| Thousands separator | `,` (comma) |
| Currency symbol | After amount with space (e.g., `24.99 EUR`) |
| Decimal places | Always 2 |
| Free amounts | Display as `0.00 EUR` |
| Negative amounts (refunds) | Prefix with `-` (e.g., `-12.50 EUR`) |

**Helper:** Use a shared Blade component or helper (e.g., `<x-price :amount="$amount" :currency="$currency" />`) to ensure consistent formatting across all storefront pages.

**Examples:**
- 2499 cents -> `24.99 EUR`
- 0 cents -> `0.00 EUR`
- 149900 cents -> `1,499.00 EUR`

---

## 1. Theme System Architecture

### 1.1 View Organization

The storefront views are organized into the following categories:

| Category | Purpose | Views |
|---|---|---|
| Layouts | Master page shell | app (master layout) |
| Pages | Core storefront pages | home, collection, product, cart, search, page (static CMS) |
| Checkout | Purchase flow | checkout index, order confirmation |
| Account | Customer area | login, register, dashboard, orders (list + detail), addresses |
| Errors | Error states | 404, 503 |
| Components | Reusable UI elements | product-card, price, badge, quantity-selector, address-form, order-summary, breadcrumbs, pagination |

### 1.2 Layout Hierarchy

All storefront pages extend a single master layout, which provides the full page shell including header, footer, cart drawer, and global Livewire listeners. Individual page templates fill the main content section.

### 1.3 Theme Settings

Theme settings are stored in the database as JSON (keyed by theme ID). A singleton service loads and caches the active theme settings for the current store. Settings control:

- Announcement bar visibility, text, link, and background color
- Sticky header toggle
- Home page section order and visibility
- Color palette overrides (primary, secondary, accent)
- Typography scale
- Footer content and social links
- Dark mode behavior (system preference, toggle, or forced)

### 1.4 Section-Based Architecture

Each page is composed of configurable sections. Sections are Blade includes or Livewire components receiving configuration from theme settings.

| Section | Description | Used On |
|---|---|---|
| Hero | Full-width banner with heading, subheading, call-to-action | Home |
| Featured Collections | Grid of collection cards | Home |
| Featured Products | Grid of product cards (lazy-loaded) | Home |
| Newsletter | Email signup form | Home, Footer |
| Rich Text | Customizable content block | Home, Pages |

### 1.5 Blade Components

All reusable UI elements are implemented as Blade components with a storefront prefix. See Section 16 for the full component library reference.

---

## 2. Base Layout

### 2.1 Document Head

The document head includes:

| Element | Description |
|---|---|
| Character encoding | UTF-8 |
| Viewport | Width = device width, initial scale 1 |
| Meta description | Page-specific, yielded from child templates |
| Title | Page-specific title appended with the app name |
| Stylesheets | Compiled CSS via Vite |
| Scripts | Compiled JS via Vite |
| Livewire styles | Injected by Livewire |
| Language attribute | Set on the HTML element from application locale |
| Scroll behavior | Smooth scrolling enabled globally |

### 2.2 Skip Link

A visually hidden "Skip to main content" link is the first element in the body. It becomes visible on keyboard focus, positioned fixed at top-left with a clear visual treatment (solid background, shadow, focus ring). Supports dark mode.

**Accessibility:** Allows keyboard users to bypass the header navigation and jump directly to the main content area.

### 2.3 Announcement Bar

Optional, controlled by theme settings. Renders a full-width bar above the header.

| Attribute | Description |
|---|---|
| Position | Full-width, above the header |
| Background | Configurable color, defaults to dark background (light text) / inverted in dark mode |
| Text | Centered, small size, configurable content |
| Link | Optional, underlined, opens in same tab |
| Dismiss | Close button (X icon) on the right side; dismissal persisted via localStorage |
| Height | Auto height with vertical padding |

### 2.4 Header

The header serves as the primary navigation banner.

**Desktop Layout (large breakpoint and above):**

```
+--------------------------------------------------------------+
| [Logo]      [Nav Item] [Nav Item] [Nav Item]     [S] [C] [A] |
+--------------------------------------------------------------+
```

| Element | Position | Description |
|---|---|---|
| Logo | Left | Linked to home page. Shows image if logo URL is set in theme settings, otherwise store name as text. Max height approximately 40px on desktop, 32px on smaller screens |
| Main Navigation | Center | Horizontal nav with links sourced from the "main-menu" navigation menu. Supports one level of dropdown submenus (revealed on hover/focus) |
| Search Icon | Right group | Button that opens the search modal |
| Cart Icon | Right group | Button that opens the cart drawer. Displays item count badge (small circular indicator, primary color background, white text) |
| Account Icon | Right group | Link to account dashboard (logged in) or login page (guest) |

**Mobile Layout (below large breakpoint):**

```
+--------------------------------------------------------------+
| [Hamburger]           [Logo]                            [Cart]|
+--------------------------------------------------------------+
```

| Element | Position | Description |
|---|---|---|
| Hamburger menu | Left | Toggle button for mobile navigation drawer |
| Logo | Center | Same as desktop but horizontally centered |
| Cart icon | Right | Same as desktop |

**Sticky Header (optional):**

When enabled in theme settings, the header sticks to the top of the viewport with a semi-transparent background and backdrop blur. A subtle bottom border appears on scroll.

**Mobile Navigation Drawer:**

| Attribute | Description |
|---|---|
| Animation | Slides in from the left side |
| Height | Full viewport height |
| Backdrop | Semi-transparent dark overlay behind the drawer |
| Close button | X icon at the top-right of the drawer |
| Navigation items | Vertical stack with comfortable tap targets |
| Submenus | Collapsible accordion pattern with chevron icons |
| Account link | Positioned at the bottom of the navigation list |
| Focus behavior | Focus is trapped within the drawer while open |
| ARIA | Labeled as "Mobile navigation" |

### 2.5 Main Content Area

The main content area is a landmark element with a unique ID for skip-link targeting. It occupies at least the full viewport height.

### 2.6 Footer

The footer is a content-info landmark.

**Layout:**

```
+--------------------------------------------------------------+
| [Column 1: Links]  [Column 2: Links]  [Column 3: Store Info] |
|                                                               |
| [Social Icons]                                                |
| [Copyright] [Payment Icons]                                   |
+--------------------------------------------------------------+
```

| Element | Description |
|---|---|
| Link columns | Responsive grid: 2 columns on mobile, 3 on tablet, up to 4 on desktop. Links sourced from "footer-menu" navigation menu. Each column has an uppercase heading and a list of links |
| Store info column | Store name, address (if configured), contact email |
| Social links | Row of icon links (Facebook, Instagram, Twitter/X, TikTok, YouTube) configured in theme settings. Each with screen reader label. Icons are 20x20, muted color with hover to full contrast |
| Copyright line | Small muted text: "(c) {year} {store name}. All rights reserved." |
| Payment method icons | Row of SVG icons for accepted payment methods (Visa, Mastercard, Amex, PayPal, etc.). Slightly reduced opacity |
| Spacing | Generous vertical padding, content constrained to max-width container with horizontal padding |
| Background | Light gray (dark: very dark gray), top border separator |

### 2.7 Cart Drawer (Livewire)

The cart drawer is always present in the layout as a global Livewire component. It listens for the "cart-updated" browser event to refresh and open. See Section 6 for full specification.

### 2.8 Dark Mode

Dark mode is implemented via Tailwind's dark variant. The behavior is controlled by theme settings:

| Mode | Implementation |
|---|---|
| System preference (default) | Follows OS-level dark mode preference automatically |
| Toggle | User-controlled toggle button in header/footer; preference stored in localStorage |
| Forced light/dark | Applied at server render time on the HTML element |

**Color Token Patterns:**

| Token | Light Mode | Dark Mode |
|---|---|---|
| Page background | White | Near-black |
| Card/section background | Light gray | Very dark gray |
| Heading text | Near-black | White |
| Body text | Medium gray | Light gray |
| Borders | Light gray | Medium-dark gray |
| Primary actions | Blue, darkens on hover | Slightly lighter blue, lightens on hover |

---

## 3. Home Page (GET /)

The home page renders sections in the order defined by theme settings. Each section can be toggled on/off and reordered. Default section order:

1. Hero Banner
2. Featured Collections
3. Featured Products
4. Newsletter Signup
5. Rich Text

### 3.1 Hero Banner Section

**Layout:** Full-width container (no max-width on the outer wrapper). Inner content constrained to standard max-width.

**Desktop (large breakpoint and above):**

```
+--------------------------------------------------------------+
|                                                               |
|  [Background Image / Gradient]                                |
|                                                               |
|       [Heading - very large, bold]                            |
|       [Subheading - medium, regular weight]                   |
|       [CTA Button - primary, large]                           |
|                                                               |
+--------------------------------------------------------------+
```

| Attribute | Description |
|---|---|
| Background | Full-width image (cover, centered) or gradient. Image set via theme settings. Semi-transparent dark overlay for text readability |
| Content | Centered vertically and horizontally, white text |
| Heading | H1 or H2 depending on context. Very large on desktop, progressively smaller on mobile. Bold, tight tracking |
| Subheading | Regular paragraph, medium size, generous top margin. Constrained to a comfortable reading width |
| CTA | Styled as primary button, large. Links to a configured collection or product |
| Height | Minimum 600px on desktop, 500px on tablet, 400px on mobile, 300px on small mobile |
| Padding | Generous vertical and horizontal padding |

**Mobile:** Same structure but stacked, with reduced font sizes and shorter minimum height. Full-bleed background image remains.

**Accessibility:**

- If background is an image, it is decorative (the content provides meaning)
- CTA button has descriptive text (e.g., "Shop the summer collection")

### 3.2 Featured Collections Section

**Layout:** Section with heading and grid of collection cards.

| Attribute | Description |
|---|---|
| Section heading | H2, large, bold, centered, with generous bottom margin |
| Grid | 2 columns on mobile, 4 columns on large screens, with gap spacing |
| Count | 2 to 4 collections, configurable in theme settings |

**Collection Card:**

```
+---------------------------+
|  [Collection Image]       |
|  3:4 aspect ratio         |
|  cover-fit, rounded       |
|                           |
|  [Title overlay at bottom]|
|  [Shop now ->]            |
+---------------------------+
```

| Element | Description |
|---|---|
| Image | 3:4 aspect ratio, cover-fit, rounded corners. Gradient overlay at bottom fading from transparent to semi-transparent dark |
| Title | White text overlaid at bottom of image, semi-bold, medium-large size |
| "Shop now" link | Small white text below title, slightly transparent, underlined. Becomes fully opaque on hover |
| Interaction | Entire card is clickable. Subtle scale-up on hover with smooth transition |

**Accessibility:**

- Each card link has the collection title as accessible name
- Images have alt text matching the collection title

### 3.3 Featured Products Section

**Livewire Component:** FeaturedProducts


command: rg -n "Products|Collections|Catalog|Product detail|Collection|Search|Admin|Storefront" specs/02-API-ROUTES.md specs/03-ADMIN-UI.md specs/04-STOREFRONT-UI.md specs/08-PLAYWRIGHT-E2E-PLAN.md

type: search

cmd: rg -n 'Products|Collections|Catalog|Product detail|Collection|Search|Admin|Storefront' specs/02-API-ROUTES.md specs/03-ADMIN-UI.md specs/04-STOREFRONT-UI.md specs/08-PLAYWRIGHT-E2E-PLAN.md

query: Products|Collections|Catalog|Product detail|Collection|Search|Admin|Storefront

aggregated_output:
specs/04-STOREFRONT-UI.md:1:# 04 - Storefront UI/UX Specification
specs/04-STOREFRONT-UI.md:81:| Featured Collections | Grid of collection cards | Home |
specs/04-STOREFRONT-UI.md:82:| Featured Products | Grid of product cards (lazy-loaded) | Home |
specs/04-STOREFRONT-UI.md:145:| Search Icon | Right group | Button that opens the search modal |
specs/04-STOREFRONT-UI.md:242:2. Featured Collections
specs/04-STOREFRONT-UI.md:243:3. Featured Products
specs/04-STOREFRONT-UI.md:282:### 3.2 Featured Collections Section
specs/04-STOREFRONT-UI.md:292:**Collection Card:**
specs/04-STOREFRONT-UI.md:296:|  [Collection Image]       |
specs/04-STOREFRONT-UI.md:317:### 3.3 Featured Products Section
specs/04-STOREFRONT-UI.md:319:**Livewire Component:** FeaturedProducts
specs/04-STOREFRONT-UI.md:327:| Products | 4 to 8, configurable. Sourced from a configured collection or "best sellers" logic |
specs/04-STOREFRONT-UI.md:376:## 4. Collection Page (GET /collections/{handle})
specs/04-STOREFRONT-UI.md:378:**Livewire Component:** CollectionPage
specs/04-STOREFRONT-UI.md:380:### 4.1 Collection Header
specs/04-STOREFRONT-UI.md:384:| Breadcrumbs | Home > Collections > {Collection Title} |
specs/04-STOREFRONT-UI.md:538:|  [Search icon - large, muted]                                 |
specs/04-STOREFRONT-UI.md:625:Home > {Primary Collection} > {Product Title}. Small, muted text with separator characters.
specs/04-STOREFRONT-UI.md:1408:## 11. Search
specs/04-STOREFRONT-UI.md:1410:### 11.1 Search Modal
specs/04-STOREFRONT-UI.md:1412:**Livewire Component:** SearchModal
specs/04-STOREFRONT-UI.md:1418:|  [Search input with icon]                           [X close] |
specs/04-STOREFRONT-UI.md:1420:|  Products                                                     |
specs/04-STOREFRONT-UI.md:1424:|  Collections                                                  |
specs/04-STOREFRONT-UI.md:1425:|  Summer Collection                                            |
specs/04-STOREFRONT-UI.md:1426:|  Winter Collection                                            |
specs/04-STOREFRONT-UI.md:1436:| Search input | Large text, search icon prefix, autofocus on open. Live binding with 300ms debounce |
specs/04-STOREFRONT-UI.md:1437:| Results | Appear below input as user types. Grouped by type: "Products" and "Collections" headings |
specs/04-STOREFRONT-UI.md:1439:| Collection results | Title only. Clickable to collection page |
specs/04-STOREFRONT-UI.md:1446:| ARIA | Dialog role, modal, labeled "Search". Results list as listbox with option items |
specs/04-STOREFRONT-UI.md:1448:### 11.2 Search Results Page (GET /search?q=)
specs/04-STOREFRONT-UI.md:1450:**Livewire Component:** SearchResults
specs/04-STOREFRONT-UI.md:1456:| Heading | H1, "X results for '{query}'" or "Search results for '{query}'" |
specs/04-STOREFRONT-UI.md:1457:| Breadcrumbs | Home > Search results |
specs/04-STOREFRONT-UI.md:1490:|  [Search input]                                               |
specs/04-STOREFRONT-UI.md:1501:| Search | Simple input + button, submits to search page |
specs/04-STOREFRONT-UI.md:1547:| Collection filters | Drawer overlay | Drawer overlay | Persistent sidebar |
specs/04-STOREFRONT-UI.md:1580:| Collection Page | Live region for product count/grid on filter change. Filter sidebar labeled as navigation. Sort dropdown has associated label |
specs/04-STOREFRONT-UI.md:1584:| Search Modal | Dialog role with modal behavior. Results as listbox with option items. Active descendant tracking for keyboard navigation |
specs/04-STOREFRONT-UI.md:1596:| Search modal | Escape | Close |
specs/04-STOREFRONT-UI.md:1597:| Search results | Arrow Up/Down | Navigate results |
specs/04-STOREFRONT-UI.md:1598:| Search results | Enter | Select highlighted result |
specs/04-STOREFRONT-UI.md:1727:| FeaturedProducts | Home page | Lazy-loaded featured products grid |
specs/04-STOREFRONT-UI.md:1729:| CollectionPage | Collection page | Filtering, sorting, pagination |
specs/04-STOREFRONT-UI.md:1734:| SearchModal | Layout (global) | Autocomplete search overlay |
specs/04-STOREFRONT-UI.md:1735:| SearchResults | Search page | Full search results with filters |
specs/04-STOREFRONT-UI.md:1751:| open-search-modal | Header search icon click | SearchModal | None |
specs/04-STOREFRONT-UI.md:1752:| close-search-modal | SearchModal close actions | SearchModal | None |
specs/04-STOREFRONT-UI.md:1766:| Collection | "{Collection title} - {Store name}" | Collection description (stripped of markup) |
specs/04-STOREFRONT-UI.md:1769:| Search | "Search results - {Store name}" | Static |
specs/04-STOREFRONT-UI.md:1802:    B --> C[Collection Page]
specs/04-STOREFRONT-UI.md:1803:    B --> D[Search Modal]
specs/04-STOREFRONT-UI.md:1804:    D --> E[Search Results Page]
specs/03-ADMIN-UI.md:1:# 03 - Admin Panel UI/UX Specification
specs/03-ADMIN-UI.md:11:## 1. Admin Layout Shell
specs/03-ADMIN-UI.md:21:**Livewire component:** `App\Livewire\Admin\Layout\Sidebar`
specs/03-ADMIN-UI.md:47:|  [cube]         Products      |
sp…31345 chars truncated…duct page - gallery, variant selector, add-to-cart | `Storefront\Products\Show` |
specs/02-API-ROUTES.md:158:| GET | `/cart` | Full cart page - line items, quantity controls, discount input, totals | `Storefront\Cart\Show` |
specs/02-API-ROUTES.md:159:| GET | `/search` | Search results page with filter panel, sort dropdown, product grid | `Storefront\Search\Index` |
specs/02-API-ROUTES.md:160:| GET | `/pages/{handle}` | Static content page (About, FAQ, etc.) | `Storefront\Pages\Show` |
specs/02-API-ROUTES.md:168:| GET | `/account` | Customer account overview | `Storefront\Account\Dashboard` |
specs/02-API-ROUTES.md:169:| GET | `/account/orders` | Order history list | `Storefront\Account\Orders\Index` |
specs/02-API-ROUTES.md:170:| GET | `/account/orders/{orderNumber}` | Order detail | `Storefront\Account\Orders\Show` |
specs/02-API-ROUTES.md:171:| GET | `/account/addresses` | Address book management | `Storefront\Account\Addresses\Index` |
specs/02-API-ROUTES.md:177:| GET | `/account/login` | Customer login page | `Storefront\Account\Auth\Login` |
specs/02-API-ROUTES.md:178:| GET | `/account/register` | Customer registration page | `Storefront\Account\Auth\Register` |
specs/02-API-ROUTES.md:179:| GET | `/forgot-password` | Forgot password page | `Storefront\Account\Auth\ForgotPassword` |
specs/02-API-ROUTES.md:181:| GET | `/reset-password/{token}` | Reset password form | `Storefront\Account\Auth\ResetPassword` |
specs/02-API-ROUTES.md:192:| GET | `/checkout/{checkoutId}` | Checkout page - stepper UI (Contact -> Shipping -> Payment) | `Storefront\Checkout\Show` |
specs/02-API-ROUTES.md:193:| GET | `/checkout/{checkoutId}/confirmation` | Order confirmation page - order number, items, totals | `Storefront\Checkout\Confirmation` |
specs/02-API-ROUTES.md:197:## 2. Storefront REST API
specs/02-API-ROUTES.md:422:    participant API as Storefront API
specs/02-API-ROUTES.md:1017:### 2.5 Search Endpoints
specs/02-API-ROUTES.md:1021:Search products within the current store.
specs/02-API-ROUTES.md:1030:| `q` | string | Yes | Search query. Min: 1, max: 200 characters. |
specs/02-API-ROUTES.md:1108:| `q` | string | Yes | Search prefix. Min: 1, max: 100 characters. |
specs/02-API-ROUTES.md:1206:## 3. Admin REST API
specs/02-API-ROUTES.md:1218:### 3.1 Platform Management (Super-Admin Only)
specs/02-API-ROUTES.md:1373:    "name": "Jane Admin",
specs/02-API-ROUTES.md:1393:### 3.2 Products
specs/02-API-ROUTES.md:1395:#### Admin Products Endpoint Summary
specs/02-API-ROUTES.md:1415:| `query` | string | No | Search by title, vendor, or SKU. |
specs/02-API-ROUTES.md:1516:| `collections` | array of integers | No | Collection IDs to add this product to. |
specs/02-API-ROUTES.md:1631:        "title": "Summer Collection",
specs/02-API-ROUTES.md:1674:Archive a product (soft delete). Products with existing orders cannot be hard-deleted.
specs/02-API-ROUTES.md:1736:### 3.3 Collections
specs/02-API-ROUTES.md:1738:#### Admin Collections Endpoint Summary
specs/02-API-ROUTES.md:1756:| `query` | string | No | Search by title. |
specs/02-API-ROUTES.md:1768:      "title": "Summer Collection",
specs/02-API-ROUTES.md:1797:  "title": "Winter Collection",
specs/02-API-ROUTES.md:1813:| `product_ids` | array of integers | No | Products to add to the collection. |
specs/02-API-ROUTES.md:1835:- `404` - Collection not found
specs/02-API-ROUTES.md:1850:  "message": "Collection deleted"
specs/02-API-ROUTES.md:1856:- `404` - Collection not found
specs/02-API-ROUTES.md:1862:#### Admin Orders Endpoint Summary
specs/02-API-ROUTES.md:1885:| `query` | string | No | Search by order number or customer email. |
specs/02-API-ROUTES.md:2134:#### Admin Discounts Endpoint Summary
specs/02-API-ROUTES.md:2280:#### Admin Shipping Endpoint Summary
specs/02-API-ROUTES.md:2416:#### Admin Tax Endpoint Summary
specs/02-API-ROUTES.md:2494:#### Admin Themes Endpoint Summary
specs/02-API-ROUTES.md:2600:#### Admin Pages Endpoint Summary
specs/02-API-ROUTES.md:2713:### 3.10 Search Admin
specs/02-API-ROUTES.md:2715:#### Admin Search Endpoint Summary
specs/02-API-ROUTES.md:2766:#### Admin Analytics Endpoint Summary
specs/02-API-ROUTES.md:3008:#### Admin
specs/02-API-ROUTES.md:3019:#### Storefront
specs/02-API-ROUTES.md:3027:#### API Storefront
specs/02-API-ROUTES.md:3036:#### API Admin
specs/02-API-ROUTES.md:3080:| `login` | 5 requests | 1 minute | IP address | Admin and customer login attempts |
specs/02-API-ROUTES.md:3081:| `api.admin` | 60 requests | 1 minute | Sanctum token ID | Admin REST API endpoints |
specs/02-API-ROUTES.md:3082:| `api.storefront` | 120 requests | 1 minute | IP address | Storefront REST API (carts, etc.) |
specs/02-API-ROUTES.md:3084:| `search` | 30 requests | 1 minute | IP address | Search and autocomplete endpoints |
specs/02-API-ROUTES.md:3171:- **Storefront API:** Versioned via URL path (`/api/storefront/v1/`). Breaking changes require a new version.
specs/02-API-ROUTES.md:3172:- **Admin API:** Versioned via URL path (`/api/admin/v1/`). Same strategy.