Error: File content (30312 tokens) exceeds maximum allowed tokens (25000). Please use offset and limit parameters to read specific portions of the file, or use the GrepTool to search for specific content.


<tool_use_error>Sibling tool call errored</tool_use_error>


Some files were too large to read in parallel. Let me read them individually with limits or use the Explore agent to summarize them.


Let me read the remaining spec files.


     1→# API and Routing Specification
     2→
     3→This document defines every route, endpoint, middleware stack, request/response schema, and rate limit for the Shopify-clone e-commerce platform. The admin panel is built with Livewire v4 + Flux UI (server-rendered), while the storefront uses Blade + Livewire. REST API endpoints serve cart/checkout operations and programmatic admin access.
     4→
     5→All monetary amounts are stored and transmitted in **minor units** (cents). All IDs are auto-incrementing integers. All monetary amounts are in minor units (cents).
     6→
     7→---
     8→
     9→## 1. Web Routes (Blade/Livewire Pages)
    10→
    11→### 1.1 Admin Auth Routes
    12→
    13→No middleware beyond the default `web` group. These routes handle admin login and logout.
    14→
    15→| Method | Path | Description | Component / Action |
    16→|--------|------|-------------|--------------------|
    17→| GET | `/admin/login` | Admin login page | `Livewire: Admin\Auth\Login` |
    18→| POST | `/admin/login` | Process admin login | Handled by Livewire action |
    19→| POST | `/admin/logout` | Logout and invalidate session | Handled by Livewire action |
    20→| GET | `/admin/forgot-password` | Show forgot password form | `Livewire: Admin\Auth\ForgotPassword` |
    21→| POST | `/admin/forgot-password` | Send password reset link | Handled by Livewire action |
    22→| GET | `/admin/reset-password/{token}` | Show reset password form | `Livewire: Admin\Auth\ResetPassword` |
    23→| POST | `/admin/reset-password` | Reset password with token | Handled by Livewire action |
    24→
    25→Rate limit: `login` tier (5 per minute per IP).
    26→
    27→---
    28→
    29→### 1.2 Admin Routes
    30→
    31→**Prefix:** `/admin`
    32→**Middleware:** `web`, `auth`, `verified`, `store.resolve`, `role.check`
    33→
    34→All admin pages render Livewire full-page components. Data mutations happen via Livewire actions (not separate POST endpoints).
    35→
    36→> **Note:** The Create and Edit routes render the same Livewire form component (`ProductForm`, `OrderForm`, etc.) in create vs edit mode, following the shared-form pattern defined in Spec 03.
    37→
    38→#### Dashboard
    39→
    40→| Method | Path | Description | Component |
    41→|--------|------|-------------|-----------|
    42→| GET | `/admin` | Dashboard with KPI tiles, orders chart, conversion funnel | `Admin\Dashboard` |
    43→
    44→#### Products
    45→
    46→| Method | Path | Description | Component |
    47→|--------|------|-------------|-----------|
    48→| GET | `/admin/products` | Product list - searchable, filterable by status, bulk actions | `Admin\Products\Index` |
    49→| GET | `/admin/products/create` | Create product form | `Admin\Products\Create` |
    50→| GET | `/admin/products/{product}/edit` | Edit product form with variants, media, options | `Admin\Products\Edit` |
    51→
    52→#### Inventory
    53→
    54→| Method | Path | Description | Component |
    55→|--------|------|-------------|-----------|
    56→| GET | `/admin/inventory` | Inventory management page | `Admin\Inventory\Index` |
    57→
    58→#### Collections
    59→
    60→| Method | Path | Description | Component |
    61→|--------|------|-------------|-----------|
    62→| GET | `/admin/collections` | Collection list | `Admin\Collections\Index` |
    63→| GET | `/admin/collections/create` | Create collection form | `Admin\Collections\Create` |
    64→| GET | `/admin/collections/{collection}/edit` | Edit collection form | `Admin\Collections\Edit` |
    65→
    66→#### Orders
    67→
    68→| Method | Path | Description | Component |
    69→|--------|------|-------------|-----------|
    70→| GET | `/admin/orders` | Order list with status filters | `Admin\Orders\Index` |
    71→| GET | `/admin/orders/{order}` | Order detail with timeline, payments, fulfillments | `Admin\Orders\Show` |
    72→
    73→#### Customers
    74→
    75→| Method | Path | Description | Component |
    76→|--------|------|-------------|-----------|
    77→| GET | `/admin/customers` | Customer list | `Admin\Customers\Index` |
    78→| GET | `/admin/customers/{customer}` | Customer detail with order history, addresses | `Admin\Customers\Show` |
    79→
    80→#### Discounts
    81→
    82→| Method | Path | Description | Component |
    83→|--------|------|-------------|-----------|
    84→| GET | `/admin/discounts` | Discount list | `Admin\Discounts\Index` |
    85→| GET | `/admin/discounts/create` | Create discount form with rules builder | `Admin\Discounts\Create` |
    86→| GET | `/admin/discounts/{discount}/edit` | Edit discount form | `Admin\Discounts\Edit` |
    87→
    88→#### Settings
    89→
    90→| Method | Path | Description | Component |
    91→|--------|------|-------------|-----------|
    92→| GET | `/admin/settings` | Store settings (tabs: General, Domains, Localization, Checkout, Notifications, API tokens) | `Admin\Settings\Index` |
    93→| GET | `/admin/settings/shipping` | Shipping zones and rates configuration | `Admin\Settings\Shipping` |
    94→| GET | `/admin/settings/taxes` | Tax settings - mode, provider config, rates | `Admin\Settings\Taxes` |
    95→
    96→#### Themes and Online Store
    97→
    98→| Method | Path | Description | Component |
    99→|--------|------|-------------|-----------|
   100→| GET | `/admin/themes` | Theme management - cards with actions (Customize, Preview, Publish, Duplicate, Delete) | `Admin\Themes\Index` |

# API and Routing Specification

This document defines every route, endpoint, middleware stack, request/response schema, and rate limit for the Shopify-clone e-commerce platform. The admin panel is built with Livewire v4 + Flux UI (server-rendered), while the storefront uses Blade + Livewire. REST API endpoints serve cart/checkout operations and programmatic admin access.

All monetary amounts are stored and transmitted in **minor units** (cents). All IDs are auto-incrementing integers. All monetary amounts are in minor units (cents).

---

## 1. Web Routes (Blade/Livewire Pages)

### 1.1 Admin Auth Routes

No middleware beyond the default `web` group. These routes handle admin login and logout.

| Method | Path | Description | Component / Action |
|--------|------|-------------|--------------------|
| GET | `/admin/login` | Admin login page | `Livewire: Admin\Auth\Login` |
| POST | `/admin/login` | Process admin login | Handled by Livewire action |
| POST | `/admin/logout` | Logout and invalidate session | Handled by Livewire action |
| GET | `/admin/forgot-password` | Show forgot password form | `Livewire: Admin\Auth\ForgotPassword` |
| POST | `/admin/forgot-password` | Send password reset link | Handled by Livewire action |
| GET | `/admin/reset-password/{token}` | Show reset password form | `Livewire: Admin\Auth\ResetPassword` |
| POST | `/admin/reset-password` | Reset password with token | Handled by Livewire action |

Rate limit: `login` tier (5 per minute per IP).

---

### 1.2 Admin Routes

**Prefix:** `/admin`
**Middleware:** `web`, `auth`, `verified`, `store.resolve`, `role.check`

All admin pages render Livewire full-page components. Data mutations happen via Livewire actions (not separate POST endpoints).

> **Note:** The Create and Edit routes render the same Livewire form component (`ProductForm`, `OrderForm`, etc.) in create vs edit mode, following the shared-form pattern defined in Spec 03.

#### Dashboard

| Method | Path | Description | Component |
|--------|------|-------------|-----------|
| GET | `/admin` | Dashboard with KPI tiles, orders chart, conversion funnel | `Admin\Dashboard` |

#### Products

| Method | Path | Description | Component |
|--------|------|-------------|-----------|
| GET | `/admin/products` | Product list - searchable, filterable by status, bulk actions | `Admin\Products\Index` |
| GET | `/admin/products/create` | Create product form | `Admin\Products\Create` |
| GET | `/admin/products/{product}/edit` | Edit product form with variants, media, options | `Admin\Products\Edit` |

#### Inventory

| Method | Path | Description | Component |
|--------|------|-------------|-----------|
| GET | `/admin/inventory` | Inventory management page | `Admin\Inventory\Index` |

#### Collections

| Method | Path | Description | Component |
|--------|------|-------------|-----------|
| GET | `/admin/collections` | Collection list | `Admin\Collections\Index` |
| GET | `/admin/collections/create` | Create collection form | `Admin\Collections\Create` |
| GET | `/admin/collections/{collection}/edit` | Edit collection form | `Admin\Collections\Edit` |

#### Orders

| Method | Path | Description | Component |
|--------|------|-------------|-----------|
| GET | `/admin/orders` | Order list with status filters | `Admin\Orders\Index` |
| GET | `/admin/orders/{order}` | Order detail with timeline, payments, fulfillments | `Admin\Orders\Show` |

#### Customers

| Method | Path | Description | Component |
|--------|------|-------------|-----------|
| GET | `/admin/customers` | Customer list | `Admin\Customers\Index` |
| GET | `/admin/customers/{customer}` | Customer detail with order history, addresses | `Admin\Customers\Show` |

#### Discounts

| Method | Path | Description | Component |
|--------|------|-------------|-----------|
| GET | `/admin/discounts` | Discount list | `Admin\Discounts\Index` |
| GET | `/admin/discounts/create` | Create discount form with rules builder | `Admin\Discounts\Create` |
| GET | `/admin/discounts/{discount}/edit` | Edit discount form | `Admin\Discounts\Edit` |

#### Settings

| Method | Path | Description | Component |
|--------|------|-------------|-----------|
| GET | `/admin/settings` | Store settings (tabs: General, Domains, Localization, Checkout, Notifications, API tokens) | `Admin\Settings\Index` |
| GET | `/admin/settings/shipping` | Shipping zones and rates configuration | `Admin\Settings\Shipping` |
| GET | `/admin/settings/taxes` | Tax settings - mode, provider config, rates | `Admin\Settings\Taxes` |

#### Themes and Online Store

| Method | Path | Description | Component |
|--------|------|-------------|-----------|
| GET | `/admin/themes` | Theme management - cards with actions (Customize, Preview, Publish, Duplicate, Delete) | `Admin\Themes\Index` |


     1→# 03 - Admin Panel UI/UX Specification
     2→
     3→This document defines every view, component, and interaction for the Shopify-clone 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.
     4→
     5→**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
     6→
     7→Anything not covered by Flux UI Free uses plain Tailwind CSS v4 markup with Livewire directives.
     8→
     9→---
    10→
    11→## 1. Admin Layout Shell
    12→
    13→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.
    14→
    15→### 1.1 Route Prefix
    16→
    17→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.
    18→
    19→### 1.2 Sidebar Navigation
    20→
    21→**Livewire component:** `App\Livewire\Admin\Layout\Sidebar`
    22→
    23→**Blade view:** `resources/views/livewire/admin/layout/sidebar.blade.php`
    24→
    25→#### Component Requirements
    26→
    27→| Property | Type | Purpose |
    28→|----------|------|---------|
    29→| `collapsed` | `bool` | Whether the sidebar is collapsed (mobile state) |
    30→| `currentRoute` | `string` | The current route name for active highlighting |
    31→
    32→| Action | Behavior |
    33→|--------|----------|
    34→| `toggle()` | Toggles the `collapsed` state |
    35→
    36→#### Wireframe
    37→
    38→```
    39→+-------------------------------+
    40→|  [BRAND LOGO]  Platform Name  |
    41→|-------------------------------|
    42→|  [separator]                  |
    43→|                               |
    44→|  [chart-bar]    Dashboard     |
    45→|                               |
    46→|  PRODUCTS                     |
    47→|  [cube]         Products      |
    48→|  [rect-stack]   Collections   |
    49→|  [archive-box]  Inventory     |
    50→|                               |
    51→|  [separator]                  |
    52→|  ORDERS                       |
    53→|  [shopping-bag] Orders        |
    54→|                               |
    55→|  [separator]                  |
    56→|  CUSTOMERS                    |
    57→|  [users]        Customers     |
    58→|                               |
    59→|  [separator]                  |
    60→|  DISCOUNTS                    |
    61→|  [tag]          Discounts     |
    62→|                               |
    63→|  [separator]                  |
    64→|  CONTENT                      |
    65→|  [doc-text]     Pages         |
    66→|  [bars-3]       Navigation    |
    67→|  [paint-brush]  Themes        |
    68→|                               |
    69→|  [separator]                  |
    70→|  [chart-pie]    Analytics     |
    71→|  [cog-6-tooth]  Settings      |
    72→|  [squares-2x2]  Apps          |
    73→|  [code-bracket] Developers    |
    74→+-------------------------------+
    75→```
    76→
    77→#### Navigation Structure
    78→
    79→```
    80→Dashboard                        -> admin.dashboard
    81→Products (group label)
    82→  Products                       -> admin.products.index
    83→  Collections                    -> admin.collections.index
    84→  Inventory                      -> admin.inventory.index
    85→Orders
    86→  Orders                         -> admin.orders.index
    87→Customers
    88→  Customers                      -> admin.customers.index
    89→Discounts
    90→  Discounts                      -> admin.discounts.index
    91→Content (group label)
    92→  Pages                          -> admin.pages.index
    93→  Navigation                     -> admin.navigation.index
    94→  Themes                         -> admin.themes.index
    95→Analytics                        -> admin.analytics.index
    96→Settings                         -> admin.settings.index
    97→Apps                             -> admin.apps.index
    98→Developers                       -> admin.developers.index
    99→```
   100→

# 03 - Admin Panel UI/UX Specification

This document defines every view, component, and interaction for the Shopify-clone 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
```


     1→# 04 - Storefront UI/UX Specification
     2→
     3→> Shopify-clone e-commerce platform - Customer-facing storefront UI/UX requirements
     4→
     5→---
     6→
     7→## Conventions
     8→
     9→| Convention | Detail |
    10→|---|---|
    11→| CSS Framework | Tailwind CSS v4, mobile-first design, dark mode support |
    12→| Interactivity | Livewire v4 for all dynamic UI (cart, filters, checkout) |
    13→| Templating | Blade templates with reusable storefront-prefixed components |
    14→| Accessibility | WCAG 2.2 AA compliance throughout |
    15→| Responsive | Mobile-first with progressive enhancement at small, medium, large, and extra-large breakpoints |
    16→| Currency | All prices stored as integers (cents), formatted with locale-aware helpers |
    17→| Images | Lazy-loaded, with proper alt text and maintained aspect ratios |
    18→
    19→---
    20→
    21→## Currency Formatting
    22→
    23→All monetary amounts are stored as integers in minor units (cents) and must be formatted for display according to these rules:
    24→
    25→| Setting | Value |
    26→|---------|-------|
    27→| Decimal separator | `.` (period) |
    28→| Thousands separator | `,` (comma) |
    29→| Currency symbol | After amount with space (e.g., `24.99 EUR`) |
    30→| Decimal places | Always 2 |
    31→| Free amounts | Display as `0.00 EUR` |
    32→| Negative amounts (refunds) | Prefix with `-` (e.g., `-12.50 EUR`) |
    33→
    34→**Helper:** Use a shared Blade component or helper (e.g., `<x-price :amount="$amount" :currency="$currency" />`) to ensure consistent formatting across all storefront pages.
    35→
    36→**Examples:**
    37→- 2499 cents -> `24.99 EUR`
    38→- 0 cents -> `0.00 EUR`
    39→- 149900 cents -> `1,499.00 EUR`
    40→
    41→---
    42→
    43→## 1. Theme System Architecture
    44→
    45→### 1.1 View Organization
    46→
    47→The storefront views are organized into the following categories:
    48→
    49→| Category | Purpose | Views |
    50→|---|---|---|
    51→| Layouts | Master page shell | app (master layout) |
    52→| Pages | Core storefront pages | home, collection, product, cart, search, page (static CMS) |
    53→| Checkout | Purchase flow | checkout index, order confirmation |
    54→| Account | Customer area | login, register, dashboard, orders (list + detail), addresses |
    55→| Errors | Error states | 404, 503 |
    56→| Components | Reusable UI elements | product-card, price, badge, quantity-selector, address-form, order-summary, breadcrumbs, pagination |
    57→
    58→### 1.2 Layout Hierarchy
    59→
    60→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.
    61→
    62→### 1.3 Theme Settings
    63→
    64→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:
    65→
    66→- Announcement bar visibility, text, link, and background color
    67→- Sticky header toggle
    68→- Home page section order and visibility
    69→- Color palette overrides (primary, secondary, accent)
    70→- Typography scale
    71→- Footer content and social links
    72→- Dark mode behavior (system preference, toggle, or forced)
    73→
    74→### 1.4 Section-Based Architecture
    75→
    76→Each page is composed of configurable sections. Sections are Blade includes or Livewire components receiving configuration from theme settings.
    77→
    78→| Section | Description | Used On |
    79→|---|---|---|
    80→| Hero | Full-width banner with heading, subheading, call-to-action | Home |
    81→| Featured Collections | Grid of collection cards | Home |
    82→| Featured Products | Grid of product cards (lazy-loaded) | Home |
    83→| Newsletter | Email signup form | Home, Footer |
    84→| Rich Text | Customizable content block | Home, Pages |
    85→
    86→### 1.5 Blade Components
    87→
    88→All reusable UI elements are implemented as Blade components with a storefront prefix. See Section 16 for the full component library reference.
    89→
    90→---
    91→
    92→## 2. Base Layout
    93→
    94→### 2.1 Document Head
    95→
    96→The document head includes:
    97→
    98→| Element | Description |
    99→|---|---|
   100→| Character encoding | UTF-8 |

# 04 - Storefront UI/UX Specification

> Shopify-clone 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 |


     1→# 05 - Business Logic Specification
     2→
     3→> Shopify-clone e-commerce platform - All domain logic, state machines, calculations, and rules for Laravel 12
     4→
     5→---
     6→
     7→## Conventions
     8→
     9→| Convention | Detail |
    10→|---|---|
    11→| Monetary amounts | **INTEGER in minor units** (cents). All arithmetic uses integers - never floating point. |
    12→| Percentage storage | Basis points where noted (e.g., 1900 = 19.00%) or whole-number percentage in `discounts.value_amount` (e.g., 15 = 15%) |
    13→| Rounding | Round each line independently, then sum (prevents rounding drift) |
    14→| Database | SQLite - single-writer, WAL mode, no advisory locks needed |
    15→| Time | All timestamps in ISO-8601 UTC via Laravel `created_at` / `updated_at` |
    16→| Currency | Single currency per store (`stores.default_currency`). No multi-currency conversion. |
    17→
    18→---
    19→
    20→## 1. Multi-Tenancy and Store Isolation
    21→
    22→### 1.1 Tenant Resolution Middleware
    23→
    24→**Class:** `App\Http\Middleware\ResolveStore`
    25→
    26→**Register** in `bootstrap/app.php` under both the `storefront` and `admin` middleware groups.
    27→
    28→#### Storefront Route Resolution (from request hostname)
    29→
    30→1. Extract hostname from the incoming HTTP request.
    31→2. Look up `store_domains` table where `hostname` matches.
    32→3. Cache the hostname-to-store_id mapping using file cache with a 5-minute TTL. Cache key pattern: `store_domain:{hostname}`.
    33→4. Retrieve the full Store model and bind it as a singleton in the application container under the key `current_store`.
    34→5. If hostname is not found in `store_domains`: return HTTP 404.
    35→6. If the resolved store has `status = 'suspended'`: return HTTP 503 maintenance page.
    36→
    37→#### Admin Route Resolution (from session)
    38→
    39→1. Read the selected store ID from the authenticated user's session (key: `current_store_id`).
    40→2. Verify the authenticated user has a `store_users` record for that store.
    41→3. If the store is suspended: return HTTP 403 Forbidden. Admin users can still view settings but cannot perform storefront-affecting mutations.
    42→
    43→```mermaid
    44→flowchart TD
    45→    A[Incoming Request] --> B{Route type?}
    46→    B -->|Storefront| C[Extract hostname]
    47→    C --> D{Hostname in cache?}
    48→    D -->|Yes| E[Load store from cache]
    49→    D -->|No| F[Query store_domains table]
    50→    F --> G{Found?}
    51→    G -->|No| H[Return 404]
    52→    G -->|Yes| I[Cache hostname->store_id, 5 min TTL]
    53→    I --> E
    54→    E --> J{Store suspended?}
    55→    J -->|Yes| K[Return 503 maintenance]
    56→    J -->|No| L[Bind store as singleton, continue]
    57→
    58→    B -->|Admin| M[Read store_id from session]
    59→    M --> N{User has store_users record?}
    60→    N -->|No| O[Return 403]
    61→    N -->|Yes| P{Store suspended?}
    62→    P -->|Yes| Q[Return 403 for mutations]
    63→    P -->|No| L
    64→```
    65→
    66→### 1.2 Store Scoping
    67→
    68→**Trait:** `App\Models\Concerns\BelongsToStore`
    69→**Global Scope:** `App\Models\Scopes\StoreScope`
    70→
    71→The trait applies a global query scope to every model that uses it. The scope adds a `WHERE store_id = <current_store_id>` clause to all queries automatically.
    72→
    73→**Behavior:**
    74→
    75→- On the model's `creating` event, automatically set `store_id` from the current store context (defense-in-depth).
    76→- All SELECT, UPDATE, DELETE queries on tenant-scoped models include the store filter.
    77→- In platform-admin contexts where cross-store access is needed, the scope can be temporarily removed.
    78→
    79→**Models that must use this trait:**
    80→products, collections, customers, orders, carts, checkouts, discounts, shipping_zones, themes, pages, navigation_menus, analytics_events, analytics_daily, webhook_subscriptions, inventory_items, search_queries.
    81→
    82→### 1.3 Role-Based Access Control
    83→
    84→**Enum:** `App\Enums\StoreUserRole` - backed by string values: `owner`, `admin`, `staff`, `support`
    85→
    86→**Permission Matrix:**
    87→
    88→| Permission | Owner | Admin | Staff | Support |
    89→|---|---|---|---|---|
    90→| Manage store settings | Yes | Yes | No | No |
    91→| Manage staff | Yes | Yes | No | No |
    92→| Manage products | Yes | Yes | Yes | No |
    93→| Manage orders | Yes | Yes | Yes | Yes (read-only) |
    94→| Manage discounts | Yes | Yes | Yes | No |
    95→| Manage themes | Yes | Yes | No | No |
    96→| Manage apps | Yes | Yes | No | No |
    97→| View analytics | Yes | Yes | Yes | No |
    98→| Manage shipping/tax | Yes | Yes | No | No |
    99→| Process refunds | Yes | Yes | No | No |
   100→| Create fulfillments | Yes | Yes | Yes | No |

# 05 - Business Logic Specification

> Shopify-clone e-commerce platform - All domain logic, state machines, calculations, and rules for Laravel 12

---

## Conventions

| Convention | Detail |
|---|---|
| Monetary amounts | **INTEGER in minor units** (cents). All arithmetic uses integers - never floating point. |
| Percentage storage | Basis points where noted (e.g., 1900 = 19.00%) or whole-number percentage in `discounts.value_amount` (e.g., 15 = 15%) |
| Rounding | Round each line independently, then sum (prevents rounding drift) |
| Database | SQLite - single-writer, WAL mode, no advisory locks needed |
| Time | All timestamps in ISO-8601 UTC via Laravel `created_at` / `updated_at` |
| Currency | Single currency per store (`stores.default_currency`). No multi-currency conversion. |

---

## 1. Multi-Tenancy and Store Isolation

### 1.1 Tenant Resolution Middleware

**Class:** `App\Http\Middleware\ResolveStore`

**Register** in `bootstrap/app.php` under both the `storefront` and `admin` middleware groups.

#### Storefront Route Resolution (from request hostname)

1. Extract hostname from the incoming HTTP request.
2. Look up `store_domains` table where `hostname` matches.
3. Cache the hostname-to-store_id mapping using file cache with a 5-minute TTL. Cache key pattern: `store_domain:{hostname}`.
4. Retrieve the full Store model and bind it as a singleton in the application container under the key `current_store`.
5. If hostname is not found in `store_domains`: return HTTP 404.
6. If the resolved store has `status = 'suspended'`: return HTTP 503 maintenance page.

#### Admin Route Resolution (from session)

1. Read the selected store ID from the authenticated user's session (key: `current_store_id`).
2. Verify the authenticated user has a `store_users` record for that store.
3. If the store is suspended: return HTTP 403 Forbidden. Admin users can still view settings but cannot perform storefront-affecting mutations.

```mermaid
flowchart TD
    A[Incoming Request] --> B{Route type?}
    B -->|Storefront| C[Extract hostname]
    C --> D{Hostname in cache?}
    D -->|Yes| E[Load store from cache]
    D -->|No| F[Query store_domains table]
    F --> G{Found?}
    G -->|No| H[Return 404]
    G -->|Yes| I[Cache hostname->store_id, 5 min TTL]
    I --> E
    E --> J{Store suspended?}
    J -->|Yes| K[Return 503 maintenance]
    J -->|No| L[Bind store as singleton, continue]

    B -->|Admin| M[Read store_id from session]
    M --> N{User has store_users record?}
    N -->|No| O[Return 403]
    N -->|Yes| P{Store suspended?}
    P -->|Yes| Q[Return 403 for mutations]
    P -->|No| L
```

### 1.2 Store Scoping

**Trait:** `App\Models\Concerns\BelongsToStore`
**Global Scope:** `App\Models\Scopes\StoreScope`

The trait applies a global query scope to every model that uses it. The scope adds a `WHERE store_id = <current_store_id>` clause to all queries automatically.

**Behavior:**

- On the model's `creating` event, automatically set `store_id` from the current store context (defense-in-depth).
- All SELECT, UPDATE, DELETE queries on tenant-scoped models include the store filter.
- In platform-admin contexts where cross-store access is needed, the scope can be temporarily removed.

**Models that must use this trait:**
products, collections, customers, orders, carts, checkouts, discounts, shipping_zones, themes, pages, navigation_menus, analytics_events, analytics_daily, webhook_subscriptions, inventory_items, search_queries.

### 1.3 Role-Based Access Control

**Enum:** `App\Enums\StoreUserRole` - backed by string values: `owner`, `admin`, `staff`, `support`

**Permission Matrix:**

| Permission | Owner | Admin | Staff | Support |
|---|---|---|---|---|
| Manage store settings | Yes | Yes | No | No |
| Manage staff | Yes | Yes | No | No |
| Manage products | Yes | Yes | Yes | No |
| Manage orders | Yes | Yes | Yes | Yes (read-only) |
| Manage discounts | Yes | Yes | Yes | No |
| Manage themes | Yes | Yes | No | No |
| Manage apps | Yes | Yes | No | No |
| View analytics | Yes | Yes | Yes | No |
| Manage shipping/tax | Yes | Yes | No | No |
| Process refunds | Yes | Yes | No | No |
| Create fulfillments | Yes | Yes | Yes | No |


     1→# 06 - Authentication and Security Specification
     2→
     3→> Shopify-clone e-commerce platform - Auth, authorization, and security controls for Laravel 12 + Livewire v4 + SQLite
     4→
     5→---
     6→
     7→## 1. Authentication
     8→
     9→The platform supports three distinct authentication mechanisms: session-based admin auth, session-based customer auth (store-scoped), and token-based API auth via Sanctum.
    10→
    11→### 1.1 Admin Authentication
    12→
    13→| Setting | Value |
    14→|---------|-------|
    15→| Guard name | `web` (default Laravel guard) |
    16→| Provider name | `users` (Eloquent driver) |
    17→| Model | `App\Models\User` |
    18→| Driver | Session (cookie-based) |
    19→| Login route | `GET /admin/login` |
    20→| Login form | Livewire component `Admin\Auth\Login` |
    21→
    22→#### Admin Login Flow
    23→
    24→```mermaid
    25→sequenceDiagram
    26→    participant B as Browser
    27→    participant LW as Livewire Component
    28→    participant Auth as Auth Guard (web)
    29→    participant DB as Database
    30→    participant S as Session
    31→
    32→    B->>LW: Submit email + password
    33→    LW->>LW: Validate input (email required, password required)
    34→    LW->>LW: Check rate limiter (5/min per IP)
    35→    alt Rate limit exceeded
    36→        LW-->>B: Flash "Too many attempts. Try again in X seconds."
    37→    end
    38→    LW->>Auth: attempt(credentials, remember)
    39→    Auth->>DB: SELECT from users WHERE email = ?
    40→    Auth->>Auth: Verify bcrypt hash
    41→    alt Credentials valid
    42→        Auth->>S: Regenerate session ID (prevent fixation)
    43→        Auth-->>LW: Success
    44→        LW-->>B: Redirect to /admin (dashboard)
    45→    else Credentials invalid
    46→        Auth-->>LW: Failure
    47→        LW-->>B: Flash "Invalid credentials" (generic, never reveal which field)
    48→    end
    49→```
    50→
    51→**Requirements:**
    52→
    53→- The login form collects `email` and `password`.
    54→- On successful login, the session MUST be regenerated to prevent session fixation attacks.
    55→- On failed login, only the generic message "Invalid credentials" is shown. The system must not indicate whether the email or password was wrong.
    56→- Rate limiting: maximum 5 attempts per minute, keyed by IP address. Uses the `login` rate limiter.
    57→- After login: redirect to `/admin` (the dashboard).
    58→
    59→#### Remember Me
    60→
    61→- An optional "Remember me" checkbox on the login form.
    62→- When enabled, Laravel sets a long-lived remember token cookie.
    63→- The `remember_token` column on the `users` table stores the hashed token.
    64→- Cookie name follows Laravel default convention: `remember_web_{hash}`.
    65→
    66→#### Admin Password Reset Flow
    67→
    68→```mermaid
    69→sequenceDiagram
    70→    participant B as Browser
    71→    participant App as Application
    72→    participant DB as Database
    73→    participant Mail as Mail Service
    74→
    75→    B->>App: GET /admin/forgot-password
    76→    App-->>B: Render forgot-password form
    77→    B->>App: POST /admin/forgot-password (email)
    78→    App->>DB: Look up user by email
    79→    alt User exists
    80→        App->>DB: Store reset token in password_reset_tokens table
    81→        App->>Mail: Send reset link email
    82→    end
    83→    App-->>B: "If that email exists, we sent a reset link." (generic)
    84→    B->>App: GET /admin/reset-password/{token}
    85→    App-->>B: Render reset-password form
    86→    B->>App: POST /admin/reset-password (token, email, password, password_confirmation)
    87→    App->>DB: Validate token (exists, not expired, matches email)
    88→    alt Valid token
    89→        App->>DB: Update user password (bcrypt hash)
    90→        App->>DB: Delete used token
    91→        App-->>B: Redirect to /admin/login with success flash
    92→    else Invalid/expired token
    93→        App-->>B: Error message
    94→    end
    95→```
    96→
    97→**Requirements:**
    98→
    99→- Uses Laravel's built-in password broker (`users` broker).
   100→- Reset tokens stored in the `password_reset_tokens` table.

# 06 - Authentication and Security Specification

> Shopify-clone e-commerce platform - Auth, authorization, and security controls for Laravel 12 + Livewire v4 + SQLite

---

## 1. Authentication

The platform supports three distinct authentication mechanisms: session-based admin auth, session-based customer auth (store-scoped), and token-based API auth via Sanctum.

### 1.1 Admin Authentication

| Setting | Value |
|---------|-------|
| Guard name | `web` (default Laravel guard) |
| Provider name | `users` (Eloquent driver) |
| Model | `App\Models\User` |
| Driver | Session (cookie-based) |
| Login route | `GET /admin/login` |
| Login form | Livewire component `Admin\Auth\Login` |

#### Admin Login Flow

```mermaid
sequenceDiagram
    participant B as Browser
    participant LW as Livewire Component
    participant Auth as Auth Guard (web)
    participant DB as Database
    participant S as Session

    B->>LW: Submit email + password
    LW->>LW: Validate input (email required, password required)
    LW->>LW: Check rate limiter (5/min per IP)
    alt Rate limit exceeded
        LW-->>B: Flash "Too many attempts. Try again in X seconds."
    end
    LW->>Auth: attempt(credentials, remember)
    Auth->>DB: SELECT from users WHERE email = ?
    Auth->>Auth: Verify bcrypt hash
    alt Credentials valid
        Auth->>S: Regenerate session ID (prevent fixation)
        Auth-->>LW: Success
        LW-->>B: Redirect to /admin (dashboard)
    else Credentials invalid
        Auth-->>LW: Failure
        LW-->>B: Flash "Invalid credentials" (generic, never reveal which field)
    end
```

**Requirements:**

- The login form collects `email` and `password`.
- On successful login, the session MUST be regenerated to prevent session fixation attacks.
- On failed login, only the generic message "Invalid credentials" is shown. The system must not indicate whether the email or password was wrong.
- Rate limiting: maximum 5 attempts per minute, keyed by IP address. Uses the `login` rate limiter.
- After login: redirect to `/admin` (the dashboard).

#### Remember Me

- An optional "Remember me" checkbox on the login form.
- When enabled, Laravel sets a long-lived remember token cookie.
- The `remember_token` column on the `users` table stores the hashed token.
- Cookie name follows Laravel default convention: `remember_web_{hash}`.

#### Admin Password Reset Flow

```mermaid
sequenceDiagram
    participant B as Browser
    participant App as Application
    participant DB as Database
    participant Mail as Mail Service

    B->>App: GET /admin/forgot-password
    App-->>B: Render forgot-password form
    B->>App: POST /admin/forgot-password (email)
    App->>DB: Look up user by email
    alt User exists
        App->>DB: Store reset token in password_reset_tokens table
        App->>Mail: Send reset link email
    end
    App-->>B: "If that email exists, we sent a reset link." (generic)
    B->>App: GET /admin/reset-password/{token}
    App-->>B: Render reset-password form
    B->>App: POST /admin/reset-password (token, email, password, password_confirmation)
    App->>DB: Validate token (exists, not expired, matches email)
    alt Valid token
        App->>DB: Update user password (bcrypt hash)
        App->>DB: Delete used token
        App-->>B: Redirect to /admin/login with success flash
    else Invalid/expired token
        App-->>B: Error message
    end
```

**Requirements:**

- Uses Laravel's built-in password broker (`users` broker).
- Reset tokens stored in the `password_reset_tokens` table.


     1→# 07 - Seeders and Test Data Specification
     2→
     3→> Complete seeder and factory specification for populating the Shopify-clone with realistic demo data. Laravel 12, SQLite. All monetary amounts in cents (INTEGER). All seed data supports Playwright E2E tests.
     4→
     5→---
     6→
     7→## 1. DatabaseSeeder Orchestration
     8→
     9→The main `DatabaseSeeder` calls child seeders in a strict order that respects foreign key dependencies. Each seeder targets a specific entity type. The ordering ensures parent records exist before children are created.
    10→
    11→**Execution order:**
    12→
    13→| Step | Seeder Class | Depends On | Purpose |
    14→|------|-------------|------------|---------|
    15→| 1 | OrganizationSeeder | (none) | Creates billing organizations |
    16→| 2 | StoreSeeder | Organizations | Creates stores under organizations |
    17→| 3 | StoreDomainSeeder | Stores | Attaches hostnames to stores |
    18→| 4 | UserSeeder | (none) | Creates admin/staff user accounts |
    19→| 5 | StoreUserSeeder | Stores, Users | Links users to stores with roles (pivot) |
    20→| 6 | StoreSettingsSeeder | Stores | Inserts per-store JSON settings |
    21→| 7 | TaxSettingsSeeder | Stores | Configures tax mode and rates |
    22→| 8 | ShippingSeeder | Stores | Creates shipping zones and rates |
    23→| 9 | CollectionSeeder | Stores | Creates product collections |
    24→| 10 | ProductSeeder | Stores, Collections | Creates products, options, variants, inventory, collection assignments |
    25→| 11 | DiscountSeeder | Stores | Creates discount codes |
    26→| 12 | CustomerSeeder | Stores | Creates customer accounts with addresses |
    27→| 13 | OrderSeeder | Stores, Customers, Products, Variants, Discounts | Creates orders with lines, payments, fulfillments, refunds |
    28→| 14 | ThemeSeeder | Stores | Creates themes with settings |
    29→| 15 | PageSeeder | Stores | Creates content pages |
    30→| 16 | NavigationSeeder | Stores, Collections, Pages | Creates menus linking to collections and pages |
    31→| 17 | AnalyticsSeeder | Stores, Customers | Creates daily aggregates and event stream |
    32→| 18 | SearchSettingsSeeder | Stores | Configures search synonyms and stop words |
    33→
    34→**Dependency diagram (Mermaid):**
    35→
    36→```mermaid
    37→graph TD
    38→    A[OrganizationSeeder] --> B[StoreSeeder]
    39→    B --> C[StoreDomainSeeder]
    40→    B --> F[StoreSettingsSeeder]
    41→    B --> G[TaxSettingsSeeder]
    42→    B --> H[ShippingSeeder]
    43→    B --> I[CollectionSeeder]
    44→    D[UserSeeder] --> E[StoreUserSeeder]
    45→    B --> E
    46→    B --> J[ProductSeeder]
    47→    I --> J
    48→    B --> K[DiscountSeeder]
    49→    B --> L[CustomerSeeder]
    50→    J --> M[OrderSeeder]
    51→    L --> M
    52→    K --> M
    53→    B --> N[ThemeSeeder]
    54→    B --> O[PageSeeder]
    55→    I --> P[NavigationSeeder]
    56→    O --> P
    57→    B --> Q[AnalyticsSeeder]
    58→    L --> Q
    59→    B --> R[SearchSettingsSeeder]
    60→```
    61→
    62→**Running seeders:**
    63→- All seeders: `php artisan db:seed`
    64→- Single seeder: `php artisan db:seed --class=ProductSeeder`
    65→- Fresh database with seed data: `php artisan migrate:fresh --seed`
    66→
    67→---
    68→
    69→## 2. Factory Definitions
    70→
    71→Each factory below lists the model, default field generation rules, named states (overrides), and relationship hooks. The coding agent should create corresponding Laravel factory classes.
    72→
    73→---
    74→
    75→### 2.1 OrganizationFactory
    76→
    77→**Model:** Organization
    78→
    79→**Default definition:**
    80→
    81→| Field | Generation Rule |
    82→|-------|----------------|
    83→| name | Faker company name |
    84→| billing_email | Faker company email |
    85→
    86→**States:** None.
    87→
    88→---
    89→
    90→### 2.2 StoreFactory
    91→
    92→**Model:** Store
    93→
    94→**Default definition:**
    95→
    96→| Field | Generation Rule |
    97→|-------|----------------|
    98→| organization_id | Creates a new Organization via its factory |
    99→| name | Faker company name + " Store" suffix |
   100→| handle | Faker unique slug (2 words) |

# 07 - Seeders and Test Data Specification

> Complete seeder and factory specification for populating the Shopify-clone with realistic demo data. Laravel 12, SQLite. All monetary amounts in cents (INTEGER). All seed data supports Playwright E2E tests.

---

## 1. DatabaseSeeder Orchestration

The main `DatabaseSeeder` calls child seeders in a strict order that respects foreign key dependencies. Each seeder targets a specific entity type. The ordering ensures parent records exist before children are created.

**Execution order:**

| Step | Seeder Class | Depends On | Purpose |
|------|-------------|------------|---------|
| 1 | OrganizationSeeder | (none) | Creates billing organizations |
| 2 | StoreSeeder | Organizations | Creates stores under organizations |
| 3 | StoreDomainSeeder | Stores | Attaches hostnames to stores |
| 4 | UserSeeder | (none) | Creates admin/staff user accounts |
| 5 | StoreUserSeeder | Stores, Users | Links users to stores with roles (pivot) |
| 6 | StoreSettingsSeeder | Stores | Inserts per-store JSON settings |
| 7 | TaxSettingsSeeder | Stores | Configures tax mode and rates |
| 8 | ShippingSeeder | Stores | Creates shipping zones and rates |
| 9 | CollectionSeeder | Stores | Creates product collections |
| 10 | ProductSeeder | Stores, Collections | Creates products, options, variants, inventory, collection assignments |
| 11 | DiscountSeeder | Stores | Creates discount codes |
| 12 | CustomerSeeder | Stores | Creates customer accounts with addresses |
| 13 | OrderSeeder | Stores, Customers, Products, Variants, Discounts | Creates orders with lines, payments, fulfillments, refunds |
| 14 | ThemeSeeder | Stores | Creates themes with settings |
| 15 | PageSeeder | Stores | Creates content pages |
| 16 | NavigationSeeder | Stores, Collections, Pages | Creates menus linking to collections and pages |
| 17 | AnalyticsSeeder | Stores, Customers | Creates daily aggregates and event stream |
| 18 | SearchSettingsSeeder | Stores | Configures search synonyms and stop words |

**Dependency diagram (Mermaid):**

```mermaid
graph TD
    A[OrganizationSeeder] --> B[StoreSeeder]
    B --> C[StoreDomainSeeder]
    B --> F[StoreSettingsSeeder]
    B --> G[TaxSettingsSeeder]
    B --> H[ShippingSeeder]
    B --> I[CollectionSeeder]
    D[UserSeeder] --> E[StoreUserSeeder]
    B --> E
    B --> J[ProductSeeder]
    I --> J
    B --> K[DiscountSeeder]
    B --> L[CustomerSeeder]
    J --> M[OrderSeeder]
    L --> M
    K --> M
    B --> N[ThemeSeeder]
    B --> O[PageSeeder]
    I --> P[NavigationSeeder]
    O --> P
    B --> Q[AnalyticsSeeder]
    L --> Q
    B --> R[SearchSettingsSeeder]
```

**Running seeders:**
- All seeders: `php artisan db:seed`
- Single seeder: `php artisan db:seed --class=ProductSeeder`
- Fresh database with seed data: `php artisan migrate:fresh --seed`

---

## 2. Factory Definitions

Each factory below lists the model, default field generation rules, named states (overrides), and relationship hooks. The coding agent should create corresponding Laravel factory classes.

---

### 2.1 OrganizationFactory

**Model:** Organization

**Default definition:**

| Field | Generation Rule |
|-------|----------------|
| name | Faker company name |
| billing_email | Faker company email |

**States:** None.

---

### 2.2 StoreFactory

**Model:** Store

**Default definition:**

| Field | Generation Rule |
|-------|----------------|
| organization_id | Creates a new Organization via its factory |
| name | Faker company name + " Store" suffix |
| handle | Faker unique slug (2 words) |


     1→# 08 - Playwright E2E Test Plan
     2→
     3→> Complete end-to-end browser test specification for the Shopify-clone platform using Pest v4 browser testing (Playwright-backed). All tests verify the entire application works through a real browser. This document defines requirements and specifications for the coding agent to implement.
     4→
     5→---
     6→
     7→## Test Suite Summary
     8→
     9→| Suite | File | Tests | Purpose | Dependencies |
    10→|-------|------|:-----:|---------|--------------|
    11→| 1 - Smoke Tests | `tests/Browser/SmokeTest.php` | 10 | Hit every major page, assert HTTP 200 and no JS errors | Store 1, Products, Collections, Pages |
    12→| 2 - Admin Authentication | `tests/Browser/Admin/AuthenticationTest.php` | 10 | Admin login, logout, invalid credentials, session access control | Admin user |
    13→| 3 - Admin Product Management | `tests/Browser/Admin/ProductManagementTest.php` | 7 | Product CRUD: listing, creating, editing, archiving, filtering | Admin user, Products (incl. #15 draft) |
    14→| 4 - Admin Order Management | `tests/Browser/Admin/OrderManagementTest.php` | 7 | Order listing, filtering, detail view, fulfillment, refund | Admin user, Orders (#1001), Customer |
    15→| 5 - Admin Discount Management | `tests/Browser/Admin/DiscountManagementTest.php` | 6 | Discount code listing, creation, editing | Admin user, Discounts |
    16→| 6 - Admin Settings | `tests/Browser/Admin/SettingsTest.php` | 7 | Store settings, shipping zones, tax config, domains | Admin user, Shipping zones, Store 1 |
    17→| 7 - Storefront Browsing | `tests/Browser/Storefront/BrowsingTest.php` | 15 | Home page, collections, product detail, variants, search, pages | Products, Collections, Pages, Products #15/#17/#18 |
    18→| 8 - Cart Flow | `tests/Browser/Storefront/CartTest.php` | 12 | Cart lifecycle: add, update qty, remove, discounts, totals | Products, Discounts (all codes) |
    19→| 9 - Checkout Flow | `tests/Browser/Storefront/CheckoutTest.php` | 8 | Full checkout: contact, address, shipping, payment, confirmation | Products, Shipping zones, Discounts |
    20→| 10 - Customer Account | `tests/Browser/Storefront/CustomerAccountTest.php` | 12 | Registration, login, order history, addresses, logout | Customer user, Orders (#1001/#1002/#1004) |
    21→| 11 - Inventory Enforcement | `tests/Browser/Storefront/InventoryTest.php` | 4 | Inventory policy enforcement: deny vs. continue | Products #17 (deny), #18 (continue), #1 |
    22→| 12 - Tenant Isolation | `tests/Browser/Storefront/TenantIsolationTest.php` | 5 | Multi-store data isolation verification | Store 1, Admin user, Customer user |
    23→| 13 - Responsive / Mobile | `tests/Browser/Storefront/ResponsiveTest.php` | 8 | Mobile and tablet viewport rendering and interaction | Products, Admin user |
    24→| 14 - Accessibility | `tests/Browser/Storefront/AccessibilityTest.php` | 11 | Heading hierarchy, ARIA labels, form labels, keyboard nav | Products, Store 1 |
    25→| 15 - Admin Collections | `tests/Browser/Admin/CollectionManagementTest.php` | 3 | Collection CRUD in admin | Admin user, Collections |
    26→| 16 - Admin Customers | `tests/Browser/Admin/CustomerManagementTest.php` | 3 | Customer listing and detail views | Admin user, Customer user, Orders |
    27→| 17 - Admin Pages | `tests/Browser/Admin/PageManagementTest.php` | 3 | CMS page management | Admin user, Pages |
    28→| 18 - Admin Analytics | `tests/Browser/Admin/AnalyticsTest.php` | 3 | Analytics dashboard rendering | Admin user, Orders |
    29→| **Total** | **18 files** | **134** | | |
    30→
    31→---
    32→
    33→## Test Infrastructure Requirements
    34→
    35→### Framework
    36→
    37→- **Test runner:** Pest v4 with browser testing capabilities (Playwright under the hood)
    38→- **Test traits:** Each browser test file must use `TestCase` and `RefreshDatabase`
    39→- **Configuration:** Register the `Browser` test directory in `tests/Pest.php` with appropriate base classes
    40→- **Base URL:** Configured via `APP_URL` in `.env.testing`, set to `http://acme-fashion.test`
    41→
    42→### Pest v4 Browser Testing API Reference
    43→
    44→The coding agent should use these Pest v4 browser methods:
    45→
    46→| Method | Purpose |
    47→|--------|---------|
    48→| `visit(url)` | Open a real browser and navigate to the given URL |
    49→| `visit([url1, url2, ...])` | Visit multiple pages (for batch smoke testing) |
    50→| `fill(field, value)` | Type a value into a named form field |
    51→| `click(text)` | Click a visible element matching the given text |
    52→| `assertSee(text)` | Assert the page contains the given visible text |
    53→| `assertNoJavascriptErrors()` | Assert no uncaught JS exceptions occurred |
    54→| `assertNoConsoleLogs()` | Assert no console warnings or errors were logged |
    55→
    56→Additionally, standard Laravel test features are available within browser tests: factories, `Event::fake()`, `Notification::fake()`, `$this->actingAs()`, and model queries.
    57→
    58→### Environment Configuration
    59→
    60→The `.env.testing` file must contain the following keys:
    61→
    62→| Key | Value | Purpose |
    63→|-----|-------|---------|
    64→| `APP_ENV` | `testing` | Laravel environment |
    65→| `APP_URL` | `http://acme-fashion.test` | Browser base URL (served by Herd) |
    66→| `DB_CONNECTION` | `sqlite` | Database driver |
    67→| `DB_DATABASE` | Absolute path to test SQLite file | Isolated test database |
    68→| `STRIPE_SECRET_KEY` | `sk_test_fake` | Fake Stripe key for test mode |
    69→| `STRIPE_WEBHOOK_SECRET` | `whsec_test_fake` | Fake webhook secret |
    70→| `MAIL_MAILER` | `array` | Trap emails in memory |
    71→| `QUEUE_CONNECTION` | `sync` | Process jobs synchronously |
    72→
    73→### Prerequisites Before Running
    74→
    75→1. Database seeded with `php artisan migrate:fresh --seed`
    76→2. Laravel Herd serving `acme-fashion.test`
    77→3. Playwright browsers installed via `npx playwright install`
    78→4. Frontend assets built via `npm run build`
    79→
    80→---
    81→
    82→## Seeded Data Dependency Table
    83→
    84→All tests depend on the database seeder providing this baseline data. Each test gets a fresh database via `RefreshDatabase`, then the seeder repopulates it.
    85→
    86→Each browser test file must set `protected bool $seed = true;` on the test class (or call `$this->seed(DatabaseSeeder::class)` in `beforeEach`) to ensure the database is populated after RefreshDatabase clears it. Laravel's `RefreshDatabase` trait does NOT automatically run seeders unless explicitly configured.
    87→
    88→| Entity | Key Details | Used By Suites |
    89→|--------|-------------|----------------|
    90→| **Admin user** | Email: `admin@acme.test`, password: `password`, role: `owner` on Store 1 | 2, 3, 4, 5, 6, 12, 13, 15, 16, 17, 18 |
    91→| **Customer user** | Email: `customer@acme.test`, password: `password`, name: "John Doe", belongs to Store 1 | 10, 12 |
    92→| **Store 1** | Name: "Acme Fashion", handle: `acme-fashion`, domain: `acme-fashion.test`, currency: EUR | 1, 6, 7, 12, 14 |
    93→| **Product #1** | Title: "Classic Cotton T-Shirt", handle: `classic-cotton-t-shirt`, price: 24.99 EUR, status: active, options: Size (S/M/L/XL), Color (Black/White/Navy), inventory: in stock | 1, 3, 7, 8, 9, 11, 13, 14 |
    94→| **Product #2** | Title: "Premium Slim Fit Jeans", handle: `premium-slim-fit-jeans`, status: active, has compare-at pricing (sale), options: Size, Color | 7, 8 |
    95→| **Product #15** | Status: `draft` - must NOT appear on storefront | 3, 7 |
    96→| **Product #17** | Status: active, inventory: 0 on hand, policy: `deny` - displays "Sold out", add-to-cart disabled | 7, 11 |
    97→| **Product #18** | Status: active, inventory: 0 on hand, policy: `continue` - displays "Available on backorder", add-to-cart enabled | 7, 11 |
    98→| **Products (20 total)** | Seeded across collections, with variants, options, images, inventory | 1, 3, 7, 8, 9, 11, 13 |
    99→| **Collections** | "T-Shirts" (handle: `t-shirts`), "New Arrivals" (handle: `new-arrivals`), plus others | 1, 7, 13, 15 |
   100→| **Orders** | #1001 (status: paid, fulfillment: unfulfilled, customer: customer@acme.test), #1002, #1004 also belonging to the same customer | 4, 10, 16, 18 |

# 08 - Playwright E2E Test Plan

> Complete end-to-end browser test specification for the Shopify-clone platform using Pest v4 browser testing (Playwright-backed). All tests verify the entire application works through a real browser. This document defines requirements and specifications for the coding agent to implement.

---

## Test Suite Summary

| Suite | File | Tests | Purpose | Dependencies |
|-------|------|:-----:|---------|--------------|
| 1 - Smoke Tests | `tests/Browser/SmokeTest.php` | 10 | Hit every major page, assert HTTP 200 and no JS errors | Store 1, Products, Collections, Pages |
| 2 - Admin Authentication | `tests/Browser/Admin/AuthenticationTest.php` | 10 | Admin login, logout, invalid credentials, session access control | Admin user |
| 3 - Admin Product Management | `tests/Browser/Admin/ProductManagementTest.php` | 7 | Product CRUD: listing, creating, editing, archiving, filtering | Admin user, Products (incl. #15 draft) |
| 4 - Admin Order Management | `tests/Browser/Admin/OrderManagementTest.php` | 7 | Order listing, filtering, detail view, fulfillment, refund | Admin user, Orders (#1001), Customer |
| 5 - Admin Discount Management | `tests/Browser/Admin/DiscountManagementTest.php` | 6 | Discount code listing, creation, editing | Admin user, Discounts |
| 6 - Admin Settings | `tests/Browser/Admin/SettingsTest.php` | 7 | Store settings, shipping zones, tax config, domains | Admin user, Shipping zones, Store 1 |
| 7 - Storefront Browsing | `tests/Browser/Storefront/BrowsingTest.php` | 15 | Home page, collections, product detail, variants, search, pages | Products, Collections, Pages, Products #15/#17/#18 |
| 8 - Cart Flow | `tests/Browser/Storefront/CartTest.php` | 12 | Cart lifecycle: add, update qty, remove, discounts, totals | Products, Discounts (all codes) |
| 9 - Checkout Flow | `tests/Browser/Storefront/CheckoutTest.php` | 8 | Full checkout: contact, address, shipping, payment, confirmation | Products, Shipping zones, Discounts |
| 10 - Customer Account | `tests/Browser/Storefront/CustomerAccountTest.php` | 12 | Registration, login, order history, addresses, logout | Customer user, Orders (#1001/#1002/#1004) |
| 11 - Inventory Enforcement | `tests/Browser/Storefront/InventoryTest.php` | 4 | Inventory policy enforcement: deny vs. continue | Products #17 (deny), #18 (continue), #1 |
| 12 - Tenant Isolation | `tests/Browser/Storefront/TenantIsolationTest.php` | 5 | Multi-store data isolation verification | Store 1, Admin user, Customer user |
| 13 - Responsive / Mobile | `tests/Browser/Storefront/ResponsiveTest.php` | 8 | Mobile and tablet viewport rendering and interaction | Products, Admin user |
| 14 - Accessibility | `tests/Browser/Storefront/AccessibilityTest.php` | 11 | Heading hierarchy, ARIA labels, form labels, keyboard nav | Products, Store 1 |
| 15 - Admin Collections | `tests/Browser/Admin/CollectionManagementTest.php` | 3 | Collection CRUD in admin | Admin user, Collections |
| 16 - Admin Customers | `tests/Browser/Admin/CustomerManagementTest.php` | 3 | Customer listing and detail views | Admin user, Customer user, Orders |
| 17 - Admin Pages | `tests/Browser/Admin/PageManagementTest.php` | 3 | CMS page management | Admin user, Pages |
| 18 - Admin Analytics | `tests/Browser/Admin/AnalyticsTest.php` | 3 | Analytics dashboard rendering | Admin user, Orders |
| **Total** | **18 files** | **134** | | |

---

## Test Infrastructure Requirements

### Framework

- **Test runner:** Pest v4 with browser testing capabilities (Playwright under the hood)
- **Test traits:** Each browser test file must use `TestCase` and `RefreshDatabase`
- **Configuration:** Register the `Browser` test directory in `tests/Pest.php` with appropriate base classes
- **Base URL:** Configured via `APP_URL` in `.env.testing`, set to `http://acme-fashion.test`

### Pest v4 Browser Testing API Reference

The coding agent should use these Pest v4 browser methods:

| Method | Purpose |
|--------|---------|
| `visit(url)` | Open a real browser and navigate to the given URL |
| `visit([url1, url2, ...])` | Visit multiple pages (for batch smoke testing) |
| `fill(field, value)` | Type a value into a named form field |
| `click(text)` | Click a visible element matching the given text |
| `assertSee(text)` | Assert the page contains the given visible text |
| `assertNoJavascriptErrors()` | Assert no uncaught JS exceptions occurred |
| `assertNoConsoleLogs()` | Assert no console warnings or errors were logged |

Additionally, standard Laravel test features are available within browser tests: factories, `Event::fake()`, `Notification::fake()`, `$this->actingAs()`, and model queries.

### Environment Configuration

The `.env.testing` file must contain the following keys:

| Key | Value | Purpose |
|-----|-------|---------|
| `APP_ENV` | `testing` | Laravel environment |
| `APP_URL` | `http://acme-fashion.test` | Browser base URL (served by Herd) |
| `DB_CONNECTION` | `sqlite` | Database driver |
| `DB_DATABASE` | Absolute path to test SQLite file | Isolated test database |
| `STRIPE_SECRET_KEY` | `sk_test_fake` | Fake Stripe key for test mode |
| `STRIPE_WEBHOOK_SECRET` | `whsec_test_fake` | Fake webhook secret |
| `MAIL_MAILER` | `array` | Trap emails in memory |
| `QUEUE_CONNECTION` | `sync` | Process jobs synchronously |

### Prerequisites Before Running

1. Database seeded with `php artisan migrate:fresh --seed`
2. Laravel Herd serving `acme-fashion.test`
3. Playwright browsers installed via `npx playwright install`
4. Frontend assets built via `npm run build`

---

## Seeded Data Dependency Table

All tests depend on the database seeder providing this baseline data. Each test gets a fresh database via `RefreshDatabase`, then the seeder repopulates it.

Each browser test file must set `protected bool $seed = true;` on the test class (or call `$this->seed(DatabaseSeeder::class)` in `beforeEach`) to ensure the database is populated after RefreshDatabase clears it. Laravel's `RefreshDatabase` trait does NOT automatically run seeders unless explicitly configured.

| Entity | Key Details | Used By Suites |
|--------|-------------|----------------|
| **Admin user** | Email: `admin@acme.test`, password: `password`, role: `owner` on Store 1 | 2, 3, 4, 5, 6, 12, 13, 15, 16, 17, 18 |
| **Customer user** | Email: `customer@acme.test`, password: `password`, name: "John Doe", belongs to Store 1 | 10, 12 |
| **Store 1** | Name: "Acme Fashion", handle: `acme-fashion`, domain: `acme-fashion.test`, currency: EUR | 1, 6, 7, 12, 14 |
| **Product #1** | Title: "Classic Cotton T-Shirt", handle: `classic-cotton-t-shirt`, price: 24.99 EUR, status: active, options: Size (S/M/L/XL), Color (Black/White/Navy), inventory: in stock | 1, 3, 7, 8, 9, 11, 13, 14 |
| **Product #2** | Title: "Premium Slim Fit Jeans", handle: `premium-slim-fit-jeans`, status: active, has compare-at pricing (sale), options: Size, Color | 7, 8 |
| **Product #15** | Status: `draft` - must NOT appear on storefront | 3, 7 |
| **Product #17** | Status: active, inventory: 0 on hand, policy: `deny` - displays "Sold out", add-to-cart disabled | 7, 11 |
| **Product #18** | Status: active, inventory: 0 on hand, policy: `continue` - displays "Available on backorder", add-to-cart enabled | 7, 11 |
| **Products (20 total)** | Seeded across collections, with variants, options, images, inventory | 1, 3, 7, 8, 9, 11, 13 |
| **Collections** | "T-Shirts" (handle: `t-shirts`), "New Arrivals" (handle: `new-arrivals`), plus others | 1, 7, 13, 15 |
| **Orders** | #1001 (status: paid, fulfillment: unfulfilled, customer: customer@acme.test), #1002, #1004 also belonging to the same customer | 4, 10, 16, 18 |


     1→# 09 - Implementation Roadmap and Pest Test Specification
     2→
     3→> Shopify-clone e-commerce platform - Step-by-step build order and exhaustive test plan for Laravel 12 + Livewire v4 + Flux UI Free + SQLite + Tailwind CSS v4
     4→
     5→---
     6→
     7→## 1. Technology Decisions (Final)
     8→
     9→These decisions adapt the original PDF spec for a self-contained, benchmarkable Laravel application. All decisions are final and must not be revisited.
    10→
    11→| Concern | PDF Default | Our Decision | Rationale |
    12→|---------|-------------|--------------|-----------|
    13→| Database | PostgreSQL | SQLite | Self-contained, no external DB, zero config |
    14→| Cache | Redis | File (Array for tests) | No Redis dependency |
    15→| Session | Redis | File | No Redis dependency |
    16→| Queue | Redis + Horizon | Sync (dev) / Database (prod) | No Redis dependency, sync for immediate feedback |
    17→| Search | Elasticsearch + Scout | SQLite FTS5 | Self-contained, no external service |
    18→| Storage | S3 | Local filesystem (storage/app/public) | No AWS dependency |
    19→| Admin UI | React/Vue SPA | Livewire v4 + Flux UI Free | Server-rendered, matches project stack |
    20→| Storefront | Blade SSR + Vite | Blade + Livewire + Tailwind v4 | Server-rendered, matches project stack |
    21→| Auth (admin) | Sanctum SPA | Laravel session auth | Standard Livewire auth pattern |
    22→| Auth (API) | Sanctum tokens | Sanctum personal access tokens | For programmatic API access |
    23→| Auth (customer) | Separate guard | Custom `customer` guard | Storefront customer auth |
    24→| OAuth (apps) | Passport | Deferred/Stubbed | Simplifies initial build, can add later |
    25→| Payments | Stripe + PayPal | Stripe test mode + PayPal stub | Stripe with test keys, PayPal interface only |
    26→| Email | SMTP/SES | Log driver (dev) / SMTP | Log for benchmark, SMTP configurable |
    27→| Monitoring | OpenTelemetry | Laravel Log (structured JSON) | Simplified for benchmark |
    28→| CI/CD | GitHub Actions | Not implemented | Out of scope for one-shot benchmark |
    29→| Docker | Multi-stage | Not implemented | App served by Laravel Herd locally |
    30→
    31→---
    32→
    33→## 2. Implementation Phases (Build Order)
    34→
    35→Each phase builds on the previous. A coding agent should execute these in strict sequential order. Tests are written alongside each phase (see Section 3 for the full test specification).
    36→
    37→### Phase Dependency Graph
    38→
    39→```mermaid
    40→flowchart TD
    41→    P1[Phase 1: Foundation]
    42→    P2[Phase 2: Catalog]
    43→    P3[Phase 3: Themes and Storefront Layout]
    44→    P4[Phase 4: Cart, Checkout, Discounts, Shipping, Taxes]
    45→    P5[Phase 5: Payments, Orders, Fulfillment]
    46→    P6[Phase 6: Customer Accounts]
    47→    P7[Phase 7: Admin Panel]
    48→    P8[Phase 8: Search]
    49→    P9[Phase 9: Analytics]
    50→    P10[Phase 10: Apps and Webhooks]
    51→    P11[Phase 11: Polish]
    52→    P12[Phase 12: Full Test Suite]
    53→
    54→    P1 --> P2
    55→    P1 --> P3
    56→    P2 --> P4
    57→    P3 --> P4
    58→    P4 --> P5
    59→    P5 --> P6
    60→    P5 --> P7
    61→    P2 --> P8
    62→    P5 --> P9
    63→    P5 --> P10
    64→    P6 --> P11
    65→    P7 --> P11
    66→    P8 --> P11
    67→    P9 --> P11
    68→    P10 --> P11
    69→    P11 --> P12
    70→```
    71→
    72→---
    73→
    74→### Phase 1: Foundation (Migrations, Models, Middleware, Auth)
    75→
    76→**Priority:** CRITICAL - everything depends on this.
    77→
    78→#### Step 1.1: Environment and Config
    79→
    80→| Config File | Setting | Value | Purpose |
    81→|-------------|---------|-------|---------|
    82→| `.env` | `DB_CONNECTION` | `sqlite` | Use SQLite as database |
    83→| `.env` | `DB_DATABASE` | `database/database.sqlite` | SQLite database file path |
    84→| `.env` | `CACHE_STORE` | `file` | File-based caching |
    85→| `.env` | `SESSION_DRIVER` | `file` | File-based sessions |
    86→| `.env` | `QUEUE_CONNECTION` | `sync` | Synchronous queue for dev |
    87→| `.env` | `MAIL_MAILER` | `log` | Log-based mail for dev |
    88→| `.env` | `FILESYSTEM_DISK` | `local` | Local filesystem storage |
    89→| `config/database.php` | SQLite connection | WAL mode, foreign keys enabled, busy_timeout=5000, synchronous=normal | Optimized SQLite configuration |
    90→| `config/session.php` | `driver` | `file` | Session driver |
    91→| `config/session.php` | `lifetime` | `120` | Session lifetime in minutes |
    92→| `config/cache.php` | `default` | `file` | Cache driver |
    93→| `config/queue.php` | `default` | `sync` | Queue driver |
    94→| `config/auth.php` | Guards | Add `customer` guard with `customers` provider | Customer storefront authentication |
    95→| `config/auth.php` | Providers | Add `customers` provider pointing to Customer model | Customer user provider |
    96→| `config/auth.php` | Passwords | Add `customers` password broker | Customer password reset |
    97→| `config/filesystems.php` | `public` disk | Ensure configured for local storage | Media file storage |
    98→| `config/logging.php` | Channels | Add structured JSON channel | Structured logging |
    99→
   100→#### Step 1.2: Core Migrations (Batch 1-2)

# 09 - Implementation Roadmap and Pest Test Specification

> Shopify-clone e-commerce platform - Step-by-step build order and exhaustive test plan for Laravel 12 + Livewire v4 + Flux UI Free + SQLite + Tailwind CSS v4

---

## 1. Technology Decisions (Final)

These decisions adapt the original PDF spec for a self-contained, benchmarkable Laravel application. All decisions are final and must not be revisited.

| Concern | PDF Default | Our Decision | Rationale |
|---------|-------------|--------------|-----------|
| Database | PostgreSQL | SQLite | Self-contained, no external DB, zero config |
| Cache | Redis | File (Array for tests) | No Redis dependency |
| Session | Redis | File | No Redis dependency |
| Queue | Redis + Horizon | Sync (dev) / Database (prod) | No Redis dependency, sync for immediate feedback |
| Search | Elasticsearch + Scout | SQLite FTS5 | Self-contained, no external service |
| Storage | S3 | Local filesystem (storage/app/public) | No AWS dependency |
| Admin UI | React/Vue SPA | Livewire v4 + Flux UI Free | Server-rendered, matches project stack |
| Storefront | Blade SSR + Vite | Blade + Livewire + Tailwind v4 | Server-rendered, matches project stack |
| Auth (admin) | Sanctum SPA | Laravel session auth | Standard Livewire auth pattern |
| Auth (API) | Sanctum tokens | Sanctum personal access tokens | For programmatic API access |
| Auth (customer) | Separate guard | Custom `customer` guard | Storefront customer auth |
| OAuth (apps) | Passport | Deferred/Stubbed | Simplifies initial build, can add later |
| Payments | Stripe + PayPal | Stripe test mode + PayPal stub | Stripe with test keys, PayPal interface only |
| Email | SMTP/SES | Log driver (dev) / SMTP | Log for benchmark, SMTP configurable |
| Monitoring | OpenTelemetry | Laravel Log (structured JSON) | Simplified for benchmark |
| CI/CD | GitHub Actions | Not implemented | Out of scope for one-shot benchmark |
| Docker | Multi-stage | Not implemented | App served by Laravel Herd locally |

---

## 2. Implementation Phases (Build Order)

Each phase builds on the previous. A coding agent should execute these in strict sequential order. Tests are written alongside each phase (see Section 3 for the full test specification).

### Phase Dependency Graph

```mermaid
flowchart TD
    P1[Phase 1: Foundation]
    P2[Phase 2: Catalog]
    P3[Phase 3: Themes and Storefront Layout]
    P4[Phase 4: Cart, Checkout, Discounts, Shipping, Taxes]
    P5[Phase 5: Payments, Orders, Fulfillment]
    P6[Phase 6: Customer Accounts]
    P7[Phase 7: Admin Panel]
    P8[Phase 8: Search]
    P9[Phase 9: Analytics]
    P10[Phase 10: Apps and Webhooks]
    P11[Phase 11: Polish]
    P12[Phase 12: Full Test Suite]

    P1 --> P2
    P1 --> P3
    P2 --> P4
    P3 --> P4
    P4 --> P5
    P5 --> P6
    P5 --> P7
    P2 --> P8
    P5 --> P9
    P5 --> P10
    P6 --> P11
    P7 --> P11
    P8 --> P11
    P9 --> P11
    P10 --> P11
    P11 --> P12
```

---

### Phase 1: Foundation (Migrations, Models, Middleware, Auth)

**Priority:** CRITICAL - everything depends on this.

#### Step 1.1: Environment and Config

| Config File | Setting | Value | Purpose |
|-------------|---------|-------|---------|
| `.env` | `DB_CONNECTION` | `sqlite` | Use SQLite as database |
| `.env` | `DB_DATABASE` | `database/database.sqlite` | SQLite database file path |
| `.env` | `CACHE_STORE` | `file` | File-based caching |
| `.env` | `SESSION_DRIVER` | `file` | File-based sessions |
| `.env` | `QUEUE_CONNECTION` | `sync` | Synchronous queue for dev |
| `.env` | `MAIL_MAILER` | `log` | Log-based mail for dev |
| `.env` | `FILESYSTEM_DISK` | `local` | Local filesystem storage |
| `config/database.php` | SQLite connection | WAL mode, foreign keys enabled, busy_timeout=5000, synchronous=normal | Optimized SQLite configuration |
| `config/session.php` | `driver` | `file` | Session driver |
| `config/session.php` | `lifetime` | `120` | Session lifetime in minutes |
| `config/cache.php` | `default` | `file` | Cache driver |
| `config/queue.php` | `default` | `sync` | Queue driver |
| `config/auth.php` | Guards | Add `customer` guard with `customers` provider | Customer storefront authentication |
| `config/auth.php` | Providers | Add `customers` provider pointing to Customer model | Customer user provider |
| `config/auth.php` | Passwords | Add `customers` password broker | Customer password reset |
| `config/filesystems.php` | `public` disk | Ensure configured for local storage | Media file storage |
| `config/logging.php` | Channels | Add structured JSON channel | Structured logging |

#### Step 1.2: Core Migrations (Batch 1-2)


Now I have a good overview of all the spec files. Let me also quickly read the remaining portions of the larger files to get a complete picture, particularly the roadmap phases. Let me also check the check files.


   100→#### Step 1.2: Core Migrations (Batch 1-2)
   101→
   102→Create in this dependency order:
   103→
   104→1. `create_organizations_table` - no dependencies
   105→2. `create_stores_table` - FK: `organization_id`
   106→3. `create_store_domains_table` - FK: `store_id`
   107→4. Modify default `users` migration - add `status`, `last_login_at`, `two_factor_*` columns; rename `password` to `password_hash` internally
   108→5. `create_store_users_table` - composite PK: `store_id` + `user_id`, with `role` column
   109→6. `create_store_settings_table` - PK: `store_id`
   110→
   111→All monetary amounts stored as INTEGER in minor units (cents). All enums stored as TEXT with CHECK constraints. All timestamps as TEXT (ISO-8601) via Laravel.
   112→
   113→#### Step 1.3: Core Models
   114→
   115→**Files to create:**
   116→
   117→| Type | Name | Purpose |
   118→|------|------|---------|
   119→| Model (with migration, factory, seeder) | `Organization` | Top-level tenant entity |
   120→| Model (with migration, factory, seeder) | `Store` | Individual store within an organization |
   121→| Model (with migration, factory, seeder) | `StoreDomain` | Domain mapping for a store |
   122→| Model (pivot) | `StoreUser` | Pivot model with `role` attribute, custom Pivot class |
   123→| Model (with migration, factory, seeder) | `StoreSettings` | Per-store configuration |
   124→
   125→**Relationship definitions:**
   126→
   127→| Model | Key Relationships |
   128→|-------|-------------------|
   129→| `Organization` | `hasMany(Store::class)` |
   130→| `Store` | `belongsTo(Organization::class)`, `hasMany(StoreDomain::class)`, `belongsToMany(User::class)` through `store_users`, `hasOne(StoreSettings::class)` |
   131→| `StoreDomain` | `belongsTo(Store::class)` |
   132→| `User` | `belongsToMany(Store::class)` through `store_users` |
   133→| `StoreUser` | Pivot model with `role` attribute, custom `Pivot` class |
   134→| `StoreSettings` | `belongsTo(Store::class)` |
   135→
   136→Each model must have:
   137→- Explicit return type declarations on all methods
   138→- Proper `$fillable` or `$guarded` arrays
   139→- `casts()` method for JSON/enum columns
   140→- Factory with meaningful default values
   141→- Seeder that creates sample data
   142→
   143→#### Step 1.4: Enums
   144→
   145→**Files to create in `app/Enums/`:**
   146→
   147→| Enum | Values |
   148→|------|--------|
   149→| `StoreStatus` | `Active`, `Suspended` |
   150→| `StoreUserRole` | `Owner`, `Admin`, `Staff`, `Support` |
   151→| `StoreDomainType` | `Storefront`, `Admin`, `Api` |
   152→
   153→#### Step 1.5: Tenant Resolution Middleware
   154→
   155→**File to create:** `App\Http\Middleware\ResolveStore`
   156→
   157→Requirements:
   158→1. Storefront routes: extract hostname from the request, look up `store_domains`, cache hostname-to-store_id for 5 minutes, bind `Store` as singleton via container instance `current_store`
   159→2. Admin routes: read `current_store_id` from session, verify user has `store_users` record
   160→3. Return 404 if hostname not found
   161→4. Return 503 for suspended stores on storefront routes
   162→
   163→**Registration in `bootstrap/app.php`:**
   164→- Register middleware group `storefront` containing `ResolveStore`
   165→- Register middleware group `admin` containing `ResolveStore`
   166→
   167→#### Step 1.6: BelongsToStore Trait and Global Scope
   168→
   169→**Files to create:**
   170→
   171→| Type | Name | Purpose |
   172→|------|------|---------|
   173→| Trait | `App\Models\Concerns\BelongsToStore` | Applies StoreScope and auto-sets store_id on creating event |
   174→| Scope | `App\Models\Scopes\StoreScope` | Applies `where('store_id', app('current_store')->id)` to all queries |
   175→
   176→Applied on: products, collections, customers, orders, carts, checkouts, discounts, shipping_zones, themes, pages, navigation_menus, analytics_events, analytics_daily, webhook_subscriptions, inventory_items, search_queries.
   177→
   178→#### Step 1.7: Authentication
   179→
   180→**Admin auth requirements:**
   181→
   182→| Component | Description |
   183→|-----------|-------------|
   184→| Livewire component `Admin\Auth\Login` | Admin login form |
   185→| Livewire component `Admin\Auth\Logout` | Admin logout action |
   186→| Auth mechanism | Standard Laravel session auth via `Auth::guard('web')->attempt()` |
   187→| Rate limiting | 5 attempts per minute per IP via `RateLimiter::for('login')` |
   188→| Password reset | Standard Laravel flow with `Password::broker('users')` |
   189→
   190→**Customer auth requirements:**
   191→
   192→| Component | Description |
   193→|-----------|-------------|
   194→| Custom guard | `customer` guard with `customers` provider |
   195→| Custom user provider | `CustomerUserProvider` that injects `store_id` into queries |
   196→| Livewire component `Storefront\Account\Auth\Login` | Customer login form |
   197→| Livewire component `Storefront\Account\Auth\Register` | Customer registration form |
   198→| Uniqueness | Customer email unique per store, not globally |
   199→| Rate limiting | 5 attempts per minute per IP |

#### Step 1.2: Core Migrations (Batch 1-2)

Create in this dependency order:

1. `create_organizations_table` - no dependencies
2. `create_stores_table` - FK: `organization_id`
3. `create_store_domains_table` - FK: `store_id`
4. Modify default `users` migration - add `status`, `last_login_at`, `two_factor_*` columns; rename `password` to `password_hash` internally
5. `create_store_users_table` - composite PK: `store_id` + `user_id`, with `role` column
6. `create_store_settings_table` - PK: `store_id`

All monetary amounts stored as INTEGER in minor units (cents). All enums stored as TEXT with CHECK constraints. All timestamps as TEXT (ISO-8601) via Laravel.

#### Step 1.3: Core Models

**Files to create:**

| Type | Name | Purpose |
|------|------|---------|
| Model (with migration, factory, seeder) | `Organization` | Top-level tenant entity |
| Model (with migration, factory, seeder) | `Store` | Individual store within an organization |
| Model (with migration, factory, seeder) | `StoreDomain` | Domain mapping for a store |
| Model (pivot) | `StoreUser` | Pivot model with `role` attribute, custom Pivot class |
| Model (with migration, factory, seeder) | `StoreSettings` | Per-store configuration |

**Relationship definitions:**

| Model | Key Relationships |
|-------|-------------------|
| `Organization` | `hasMany(Store::class)` |
| `Store` | `belongsTo(Organization::class)`, `hasMany(StoreDomain::class)`, `belongsToMany(User::class)` through `store_users`, `hasOne(StoreSettings::class)` |
| `StoreDomain` | `belongsTo(Store::class)` |
| `User` | `belongsToMany(Store::class)` through `store_users` |
| `StoreUser` | Pivot model with `role` attribute, custom `Pivot` class |
| `StoreSettings` | `belongsTo(Store::class)` |

Each model must have:
- Explicit return type declarations on all methods
- Proper `$fillable` or `$guarded` arrays
- `casts()` method for JSON/enum columns
- Factory with meaningful default values
- Seeder that creates sample data

#### Step 1.4: Enums

**Files to create in `app/Enums/`:**

| Enum | Values |
|------|--------|
| `StoreStatus` | `Active`, `Suspended` |
| `StoreUserRole` | `Owner`, `Admin`, `Staff`, `Support` |
| `StoreDomainType` | `Storefront`, `Admin`, `Api` |

#### Step 1.5: Tenant Resolution Middleware

**File to create:** `App\Http\Middleware\ResolveStore`

Requirements:
1. Storefront routes: extract hostname from the request, look up `store_domains`, cache hostname-to-store_id for 5 minutes, bind `Store` as singleton via container instance `current_store`
2. Admin routes: read `current_store_id` from session, verify user has `store_users` record
3. Return 404 if hostname not found
4. Return 503 for suspended stores on storefront routes

**Registration in `bootstrap/app.php`:**
- Register middleware group `storefront` containing `ResolveStore`
- Register middleware group `admin` containing `ResolveStore`

#### Step 1.6: BelongsToStore Trait and Global Scope

**Files to create:**

| Type | Name | Purpose |
|------|------|---------|
| Trait | `App\Models\Concerns\BelongsToStore` | Applies StoreScope and auto-sets store_id on creating event |
| Scope | `App\Models\Scopes\StoreScope` | Applies `where('store_id', app('current_store')->id)` to all queries |

Applied on: products, collections, customers, orders, carts, checkouts, discounts, shipping_zones, themes, pages, navigation_menus, analytics_events, analytics_daily, webhook_subscriptions, inventory_items, search_queries.

#### Step 1.7: Authentication

**Admin auth requirements:**

| Component | Description |
|-----------|-------------|
| Livewire component `Admin\Auth\Login` | Admin login form |
| Livewire component `Admin\Auth\Logout` | Admin logout action |
| Auth mechanism | Standard Laravel session auth via `Auth::guard('web')->attempt()` |
| Rate limiting | 5 attempts per minute per IP via `RateLimiter::for('login')` |
| Password reset | Standard Laravel flow with `Password::broker('users')` |

**Customer auth requirements:**

| Component | Description |
|-----------|-------------|
| Custom guard | `customer` guard with `customers` provider |
| Custom user provider | `CustomerUserProvider` that injects `store_id` into queries |
| Livewire component `Storefront\Account\Auth\Login` | Customer login form |
| Livewire component `Storefront\Account\Auth\Register` | Customer registration form |
| Uniqueness | Customer email unique per store, not globally |
| Rate limiting | 5 attempts per minute per IP |


Here is a summary of the specs:

## Specs Summary

The specs describe a **Shopify-clone e-commerce platform** built with Laravel 12, Livewire v4, Flux UI Free, Tailwind CSS v4, and SQLite. It is a multi-tenant, multi-store system.

### 01 - Database Schema
Defines **46 application tables** (55 total including Laravel framework tables) organized across 8 epics:
- **Foundation & Tenancy:** Organizations, stores, domains, users, store-user pivot (roles), store settings
- **Catalog:** Products with options/variants, inventory tracking, collections, media
- **Themes & Storefront:** Themes with files/settings, CMS pages, navigation menus
- **Search:** Search settings (synonyms, stop words) and query logging
- **Cart & Checkout:** Carts, cart lines, checkouts (multi-step), shipping zones/rates, tax settings, discounts
- **Orders & Payments:** Customers, addresses, orders, order lines, payments (Stripe/PayPal), refunds, fulfillments
- **Analytics:** Raw event stream + daily aggregates
- **Apps & Webhooks:** App registry, installations, OAuth clients/tokens, webhook subscriptions/deliveries

All monetary values stored as integers (cents). SQLite with WAL mode, foreign keys enforced.

### 02 - API & Routes
Defines all routes: admin auth, admin CRUD pages (Livewire full-page components), storefront pages (Blade + Livewire), and REST API endpoints for cart/checkout operations. Admin is prefixed `/admin` with auth/store-scoping middleware. Storefront resolves stores by hostname.

### 03 - Admin Panel UI
Full admin panel spec using Livewire v4 + Flux UI Free. Includes sidebar navigation, dashboard with KPIs, product/collection/order/customer/discount management, settings pages, theme management, analytics, and app/developer sections. All interactions via Livewire actions.

### 04 - Storefront UI
Customer-facing storefront with Blade + Livewire + Tailwind v4. Mobile-first, dark mode, WCAG 2.2 AA. Includes: layout shell (header, footer, cart drawer), home page with configurable sections (hero, featured collections/products, newsletter), collection/product/cart/search/checkout pages, customer account area. Prices formatted as `24.99 EUR`.

### 05 - Business Logic
Core domain logic: multi-tenant store resolution (by hostname for storefront, by session for admin), store scoping via global query scope, RBAC (owner/admin/staff/support), product lifecycle, inventory management (deny vs. continue oversell policies), cart calculations, checkout state machine, discount engine, shipping rate calculation, tax computation, order placement, payment processing, fulfillment tracking, and refund handling.

### 06 - Auth & Security
Three auth mechanisms: session-based admin auth, session-based customer auth (store-scoped with custom guard), and Sanctum token-based API auth. Includes password reset flows, rate limiting, CSRF protection, input validation, and PCI-compliant payment data handling (encrypted storage).

### 07 - Seeders & Test Data
18 seeder classes run in dependency order to populate realistic demo data: organizations, stores, domains, users (admin/staff), products (20 with variants/options/inventory), collections, discounts, customers, orders with payments/fulfillments, themes, pages, navigation, and analytics. Includes full factory definitions for all models.

### 08 - Playwright E2E Test Plan
**134 browser tests** across 18 test files using Pest v4 browser testing (Playwright). Covers: smoke tests, admin auth, product/order/discount/collection/customer/page management, storefront browsing, cart flow, checkout flow, customer accounts, inventory enforcement, tenant isolation, responsive/mobile testing, and accessibility (WCAG).

### 09 - Implementation Roadmap
12 sequential phases: Foundation (migrations, models, middleware, auth) -> Catalog -> Themes/Storefront Layout -> Cart/Checkout/Discounts/Shipping/Taxes -> Payments/Orders/Fulfillment -> Customer Accounts -> Admin Panel -> Search -> Analytics -> Apps/Webhooks -> Polish -> Full Test Suite. Includes a comprehensive Pest test specification with expected test counts per phase.


Describe the functionality as user stories (not epic by epic; the big picture)


The user wants me to describe the functionality as user stories from a big-picture perspective, not organized by epic/technical grouping but by user-facing functionality. Let me synthesize all the specs into coherent user stories organized by the different actors/personas.


## User Stories

### Store Owner / Organization

- As a store owner, I can create an organization and set up one or more stores under it, each with its own name, currency, locale, and timezone.
- As a store owner, I can attach custom domains to my store so customers reach my storefront via my own hostname.
- As a store owner, I can invite staff members and assign them roles (admin, staff, support) that control what they can see and do in the admin panel.
- As a store owner, I can suspend a store, which takes the storefront offline (503) while still allowing admin access for configuration.

### Admin / Staff (Product & Catalog)

- As an admin, I can create products with a title, description, vendor, type, tags, and rich-text content.
- As an admin, I can define option dimensions on a product (e.g. Size, Color) and their values (S/M/L, Black/White), which generate purchasable variants.
- As an admin, I can set per-variant pricing (including compare-at/sale prices), SKUs, barcodes, weight, and shipping requirements.
- As an admin, I can upload images and videos to a product and reorder them.
- As an admin, I can manage product lifecycle: draft (invisible to customers), active (published), or archived (hidden but preserved).
- As an admin, I can organize products into collections - either curated manually or (later) rule-based - and control the display order.
- As an admin, I can track inventory per variant, see on-hand vs. reserved quantities, and choose whether a variant can be oversold ("continue") or blocks purchases at zero stock ("deny").
- As an admin, I can search, filter, and bulk-act on products from a list view.

### Admin / Staff (Orders & Fulfillment)

- As an admin, I can view all orders filtered by status (pending, paid, fulfilled, cancelled, refunded) and by date range.
- As an admin, I can open an order to see its full timeline: line items (with snapshots of what was purchased), payment attempts, fulfillment shipments, and refunds.
- As an admin, I can create a fulfillment for an order by entering a tracking number and carrier, marking specific line items and quantities as shipped.
- As an admin, I can partially fulfill an order (ship some items now, the rest later).
- As an admin, I can issue a full or partial refund against a captured payment, which updates the order's financial status accordingly.
- As a support user, I can view orders read-only but cannot modify them.

### Admin (Discounts)

- As an admin, I can create discount codes that customers enter at checkout, or automatic discounts that apply without a code.
- As an admin, I can configure a discount as fixed amount, percentage, or free shipping.
- As an admin, I can set eligibility rules: minimum purchase amount, applicable products/collections, usage limits, and start/end dates.
- As an admin, I can see how many times a discount has been redeemed and disable it when needed.

### Admin (Shipping & Taxes)

- As an admin, I can define shipping zones by country and region, then create rate options within each zone (flat rate, weight-based, price-based, or carrier-calculated).
- As an admin, I can configure tax settings: manual mode with fixed rates, or provider mode (Stripe Tax), and choose whether prices are tax-inclusive.

### Admin (Content & Themes)

- As an admin, I can create and edit static CMS pages (About Us, Contact, FAQ) with rich-text content and publish/draft/archive controls.
- As an admin, I can build navigation menus (main menu, footer) with links pointing to pages, collections, products, or arbitrary URLs.
- As an admin, I can manage themes: customize settings (colors, typography, announcement bar, section order), preview, publish, duplicate, or delete a theme.

### Admin (Analytics & Settings)

- As an admin, I can view a dashboard with KPI tiles (revenue, orders, average order value, conversion rate) and charts over configurable date ranges.
- As an admin, I can see a conversion funnel from visits through add-to-cart, checkout started, to checkout completed.
- As an admin, I can configure general store settings, domain mappings, localization, checkout behavior, notification preferences, and API tokens from a unified settings area.

### Admin (Apps & Developers)

- As an admin, I can install third-party apps on my store, granting them specific permission scopes.
- As an admin, I can register webhook subscriptions so external systems receive real-time notifications when events occur (order placed, product updated, etc.).
- As a developer, I can authenticate via OAuth2 and use REST API endpoints to programmatically manage store resources.

### Customer (Browsing & Shopping)

- As a customer, I can visit a store's homepage and see a hero banner, featured collections, and featured products.
- As a customer, I can browse a collection page with products displayed in a grid, filter by availability, price range, or product type, and sort by price, name, or date.
- As a customer, I can view a product detail page showing images (with gallery), description, variant selector (size/color dropdowns or swatches), pricing (with sale badges), and stock status.
- As a customer, I see "Sold out" and a disabled add-to-cart button when a variant has zero stock and the store denies overselling.
- As a customer, I see "Available on backorder" and can still purchase when the store allows overselling.
- As a customer, I can search for products by keyword and see relevant results with highlighted matches.
- As a customer, I can read static content pages (About, Contact, etc.) linked from the navigation menu.

### Customer (Cart)

- As a customer, I can add a product variant to my cart and see it appear in a slide-out cart drawer without a full page reload.
- As a customer, I can update quantities or remove items from my cart, with line totals and the cart total recalculating in real time.
- As a customer, I can enter a discount code in the cart and see the discount applied (or an error if invalid/expired/minimum not met).
- As a customer, my cart persists across page navigations and (if logged in) is tied to my account.

### Customer (Checkout)

- As a customer, I can proceed to checkout where I enter my contact email, shipping address, and billing address in a guided multi-step flow.
- As a customer, I can select a shipping method from the rates available for my address's zone, with the cost reflected in my order total.
- As a customer, I see a breakdown of subtotal, discount, shipping, tax, and grand total before confirming payment.
- As a customer, I can pay via Stripe (credit card) with the transaction processed in test mode.
- As a customer, after successful payment I see an order confirmation page with my order number and summary.
- As a guest, I can complete the entire checkout without creating an account.

### Customer (Account)

- As a customer, I can register for an account with my email and password, scoped to the store I am visiting.
- As a customer, I can log in and out of my account.
- As a customer, I can reset my password via an emailed link.
- As a customer, I can view my order history, with each order showing status, items, and tracking information.
- As a customer, I can manage saved addresses (add, edit, delete, set a default).

### Platform (Cross-Cutting)

- As the platform, I enforce tenant isolation so that Store A's products, customers, orders, and all other data are never visible or accessible from Store B.
- As the platform, I track analytics events (page views, product views, add-to-cart, checkout steps) per store and aggregate them into daily summaries.
- As the platform, I deliver webhooks to subscribed endpoints with HMAC-signed payloads, retrying on failure.
- As the platform, I serve the storefront responsively across mobile, tablet, and desktop viewports, with dark mode support and WCAG 2.2 AA accessibility compliance.