sed -n '2195,2575p' specs/08-PLAYWRIGHT-E2E-PLAN.md

1. Navigate to `/account` (without logging in)

**Expected Results:**
- Page displays "Log in" (redirected to login form)
- No JavaScript errors

---

### Test 10.7: Shows order history for logged-in customer

**Preconditions:** Logged in as customer@acme.test, Orders #1001/#1002/#1004 exist

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `password`
4. Click "Log in"
5. Click "Orders" or navigate to order history

**Expected Results:**
- Page displays "#1001"
- Page displays "#1002"
- Page displays "#1004"
- No JavaScript errors

---

### Test 10.8: Shows order detail for customer order

**Preconditions:** Logged in as customer, Order #1001 exists

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Orders"
4. Click "#1001"

**Expected Results:**
- Page displays "#1001"
- Page displays "Subtotal"
- Page displays "Total"
- No JavaScript errors

---

### Test 10.9: Can view addresses

**Preconditions:** Logged in as customer

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"

**Expected Results:**
- Existing addresses are displayed
- No JavaScript errors

---

### Test 10.10: Can add a new address

**Preconditions:** Logged in as customer

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"
4. Click "Add address"
5. Enter first name: `John`
6. Enter last name: `Doe`
7. Enter address: `New Street 42`
8. Enter city: `Hamburg`
9. Enter postal code: `20095`
10. Enter country: `DE`
11. Click "Save"

**Expected Results:**
- Page displays "Address saved"
- Page displays "New Street 42"
- Page displays "Hamburg"
- No JavaScript errors

---

### Test 10.11: Can edit an existing address

**Preconditions:** Logged in as customer, at least one address exists

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"
4. Click "Edit" on the first address
5. Change city to: `Frankfurt`
6. Click "Save"

**Expected Results:**
- Page displays "Address saved"
- Page displays "Frankfurt"
- No JavaScript errors

---

### Test 10.12: Can log out

**Preconditions:** Logged in as customer

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `password`
4. Click "Log in"
5. Verify "My Account" is displayed
6. Click "Logout"

**Expected Results:**
- Page displays "Log in" (redirected to login or home page)
- No JavaScript errors

**Total: 12 tests**

---

## Suite 11: Inventory Enforcement

**File:** `tests/Browser/Storefront/InventoryTest.php`

**Purpose:** Verify that inventory policies are correctly enforced on the storefront - deny-policy blocks purchasing when out of stock, continue-policy allows backorders.

### Inventory Policy Decision Matrix

| Stock Level | Policy | Storefront Display | Add-to-Cart |
|-------------|--------|--------------------|-------------|
| > 0 | `deny` | "Add to cart" button enabled | Allowed |
| > 0 | `continue` | "Add to cart" button enabled | Allowed |
| 0 | `deny` | "Sold out" text, button disabled | Blocked |
| 0 | `continue` | "Available on backorder" text, button enabled | Allowed |

---

### Test 11.1: Blocks add-to-cart for out-of-stock deny-policy product

**Preconditions:** Product #17 (0 stock, inventory policy = deny)

**Steps:**
1. Navigate to the product page for Product #17 (use actual handle from seeder)

**Expected Results:**
- Page displays "Sold out"
- "Add to cart" button is disabled or hidden (not clickable)
- No JavaScript errors

---

### Test 11.2: Allows add-to-cart for out-of-stock continue-policy product

**Preconditions:** Product #18 (0 stock, inventory policy = continue)

**Steps:**
1. Navigate to the product page for Product #18 (use actual handle from seeder)
2. Verify "Available on backorder" is displayed
3. Click "Add to cart"
4. Navigate to `/cart`

**Expected Results:**
- "Available on backorder" is visible on the product page
- Add to cart succeeds
- Cart page shows the product
- No JavaScript errors

---

### Test 11.3: Shows correct stock status for in-stock product

**Preconditions:** Product #1 (in stock)

**Steps:**
1. Navigate to `/products/classic-cotton-t-shirt`

**Expected Results:**
- Page displays "Add to cart" button (enabled)
- "Sold out" is NOT displayed
- "Available on backorder" is NOT displayed
- No JavaScript errors

---

### Test 11.4: Prevents adding more than available stock for deny-policy product

**Preconditions:** A product with limited stock (deny policy)

**Steps:**
1. Navigate to `/products/classic-cotton-t-shirt`
2. Click "M" to select size M
3. Click "Black" to select color Black
4. Click "Add to cart"
5. Navigate to `/cart`
6. Attempt to increase quantity beyond the available stock level

**Expected Results:**
- System prevents exceeding available inventory (either caps quantity or shows error)
- No JavaScript errors

**Total: 4 tests**

---

## Suite 12: Tenant Isolation

**File:** `tests/Browser/Storefront/TenantIsolationTest.php`

**Purpose:** Verify that multi-store tenant isolation is enforced - data from one store never leaks into another store's storefront or admin panel.

### Isolation Requirements

```mermaid
flowchart LR
    subgraph Store1[Store 1 - Acme Fashion]
        S1Products[Fashion Products]
        S1Orders[Fashion Orders]
        S1Customers[Fashion Customers]
    end
    subgraph Store2[Store 2 - Different Store]
        S2Products[Other Products]
        S2Orders[Other Orders]
        S2Customers[Other Customers]
    end
    S1Products -.-x S2Products
    S1Orders -.-x S2Orders
    S1Customers -.-x S2Customers
```

Dashed X lines indicate these must NEVER cross. No data from Store 2 should ever appear when browsing Store 1, and vice versa.

---

### Test 12.1: Store 1 only shows Store 1 products

**Preconditions:** Seeded Store 1 products

**Steps:**
1. Navigate to `/` (resolved to Store 1 via acme-fashion.test domain)

**Expected Results:**
- Page displays "Acme Fashion"
- Page displays "Classic Cotton T-Shirt"
- Products from other stores (e.g., electronics from Store 2) are absent
- No JavaScript errors

---

### Test 12.2: Store 1 collections only contain Store 1 products

**Preconditions:** Seeded collections

**Steps:**
1. Navigate to `/collections/t-shirts`

**Expected Results:**
- Page displays "T-Shirts"
- Only Store 1 products appear in the collection grid
- No JavaScript errors

---

### Test 12.3: Admin cannot access other store data

**Preconditions:** Logged in as admin@acme.test (Store 1 owner)

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin (email: `admin@acme.test`, password: `password`)
3. Click "Products" in the sidebar
4. Review the product list
5. Click "Orders" in the sidebar
6. Review the order list

**Expected Results:**
- All products listed belong to Store 1 only
- All orders listed belong to Store 1 only
- No cross-store data is visible
- No JavaScript errors

---

### Test 12.4: Search only returns current store products

**Preconditions:** Seeded Store 1 products

**Steps:**
1. Navigate to `/search?q=product`

**Expected Results:**
- Only Store 1 products appear in search results
- No cross-store data leakage
- No JavaScript errors

---

### Test 12.5: Customer accounts are scoped to their store

**Preconditions:** customer@acme.test seeded for Store 1

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `password`
4. Click "Log in"
5. Click "Orders"

**Expected Results:**
- Customer only sees Store 1 orders (#1001, #1002, #1004)
- No JavaScript errors

**Total: 5 tests**

---

## Suite 13: Responsive / Mobile

**File:** `tests/Browser/Storefront/ResponsiveTest.php`

**Purpose:** Verify that the storefront and admin panel render and function correctly on mobile (375x812) and tablet (768x1024) viewports.

### Viewport Definitions

| Device | Width | Height | Use For |
|--------|-------|--------|---------|
| iPhone (mobile) | 375 | 812 | Storefront tests |
| iPad (tablet) | 768 | 1024 | Admin panel tests |

---

### Test 13.1: Storefront home works on mobile viewport

**Preconditions:** Seeded store

**Steps:**
1. Set viewport to iPhone dimensions (375x812)
2. Navigate to `/`

**Expected Results:**
- Page displays "Acme Fashion"
- Mobile menu (hamburger) is visible
- Desktop navigation is hidden
- No horizontal scroll
- No JavaScript errors

---

### Test 13.2: Product page stacks layout on mobile

**Preconditions:** Product #1

**Steps:**
1. Set viewport to mobile (375x812)
2. Navigate to `/products/classic-cotton-t-shirt`

**Expected Results:**
- Page displays "Classic Cotton T-Shirt", "24.99", "Add to cart"
- Gallery and details stack vertically
- No JavaScript errors

---

### Test 13.3: Can add to cart on mobile

**Preconditions:** Product #1

**Steps:**
1. Set viewport to mobile (375x812)
2. Navigate to `/products/classic-cotton-t-shirt`
3. Click "M" to select size M
4. Click "Black" to select color Black
5. Click "Add to cart"

**Expected Results:**
- Product added to cart successfully
- No JavaScript errors


Output:
Chunk ID: 2bf646
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2323
Output:
1. Navigate to `/account` (without logging in)

**Expected Results:**
- Page displays "Log in" (redirected to login form)
- No JavaScript errors

---

### Test 10.7: Shows order history for logged-in customer

**Preconditions:** Logged in as customer@acme.test, Orders #1001/#1002/#1004 exist

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `password`
4. Click "Log in"
5. Click "Orders" or navigate to order history

**Expected Results:**
- Page displays "#1001"
- Page displays "#1002"
- Page displays "#1004"
- No JavaScript errors

---

### Test 10.8: Shows order detail for customer order

**Preconditions:** Logged in as customer, Order #1001 exists

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Orders"
4. Click "#1001"

**Expected Results:**
- Page displays "#1001"
- Page displays "Subtotal"
- Page displays "Total"
- No JavaScript errors

---

### Test 10.9: Can view addresses

**Preconditions:** Logged in as customer

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"

**Expected Results:**
- Existing addresses are displayed
- No JavaScript errors

---

### Test 10.10: Can add a new address

**Preconditions:** Logged in as customer

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"
4. Click "Add address"
5. Enter first name: `John`
6. Enter last name: `Doe`
7. Enter address: `New Street 42`
8. Enter city: `Hamburg`
9. Enter postal code: `20095`
10. Enter country: `DE`
11. Click "Save"

**Expected Results:**
- Page displays "Address saved"
- Page displays "New Street 42"
- Page displays "Hamburg"
- No JavaScript errors

---

### Test 10.11: Can edit an existing address

**Preconditions:** Logged in as customer, at least one address exists

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"
4. Click "Edit" on the first address
5. Change city to: `Frankfurt`
6. Click "Save"

**Expected Results:**
- Page displays "Address saved"
- Page displays "Frankfurt"
- No JavaScript errors

---

### Test 10.12: Can log out

**Preconditions:** Logged in as customer

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `password`
4. Click "Log in"
5. Verify "My Account" is displayed
6. Click "Logout"

**Expected Results:**
- Page displays "Log in" (redirected to login or home page)
- No JavaScript errors

**Total: 12 tests**

---

## Suite 11: Inventory Enforcement

**File:** `tests/Browser/Storefront/InventoryTest.php`

**Purpose:** Verify that inventory policies are correctly enforced on the storefront - deny-policy blocks purchasing when out of stock, continue-policy allows backorders.

### Inventory Policy Decision Matrix

| Stock Level | Policy | Storefront Display | Add-to-Cart |
|-------------|--------|--------------------|-------------|
| > 0 | `deny` | "Add to cart" button enabled | Allowed |
| > 0 | `continue` | "Add to cart" button enabled | Allowed |
| 0 | `deny` | "Sold out" text, button disabled | Blocked |
| 0 | `continue` | "Available on backorder" text, button enabled | Allowed |

---

### Test 11.1: Blocks add-to-cart for out-of-stock deny-policy product

**Preconditions:** Product #17 (0 stock, inventory policy = deny)

**Steps:**
1. Navigate to the product page for Product #17 (use actual handle from seeder)

**Expected Results:**
- Page displays "Sold out"
- "Add to cart" button is disabled or hidden (not clickable)
- No JavaScript errors

---

### Test 11.2: Allows add-to-cart for out-of-stock continue-policy product

**Preconditions:** Product #18 (0 stock, inventory policy = continue)

**Steps:**
1. Navigate to the product page for Product #18 (use actual handle from seeder)
2. Verify "Available on backorder" is displayed
3. Click "Add to cart"
4. Navigate to `/cart`

**Expected Results:**
- "Available on backorder" is visible on the product page
- Add to cart succeeds
- Cart page shows the product
- No JavaScript errors

---

### Test 11.3: Shows correct stock status for in-stock product

**Preconditions:** Product #1 (in stock)

**Steps:**
1. Navigate to `/products/classic-cotton-t-shirt`

**Expected Results:**
- Page displays "Add to cart" button (enabled)
- "Sold out" is NOT displayed
- "Available on backorder" is NOT displayed
- No JavaScript errors

---

### Test 11.4: Prevents adding more than available stock for deny-policy product

**Preconditions:** A product with limited stock (deny policy)

**Steps:**
1. Navigate to `/products/classic-cotton-t-shirt`
2. Click "M" to select size M
3. Click "Black" to select color Black
4. Click "Add to cart"
5. Navigate to `/cart`
6. Attempt to increase quantity beyond the available stock level

**Expected Results:**
- System prevents exceeding available inventory (either caps quantity or shows error)
- No JavaScript errors

**Total: 4 tests**

---

## Suite 12: Tenant Isolation

**File:** `tests/Browser/Storefront/TenantIsolationTest.php`

**Purpose:** Verify that multi-store tenant isolation is enforced - data from one store never leaks into another store's storefront or admin panel.

### Isolation Requirements

```mermaid
flowchart LR
    subgraph Store1[Store 1 - Acme Fashion]
        S1Products[Fashion Products]
        S1Orders[Fashion Orders]
        S1Customers[Fashion Customers]
    end
    subgraph Store2[Store 2 - Different Store]
        S2Products[Other Products]
        S2Orders[Other Orders]
        S2Customers[Other Customers]
    end
    S1Products -.-x S2Products
    S1Orders -.-x S2Orders
    S1Customers -.-x S2Customers
```

Dashed X lines indicate these must NEVER cross. No data from Store 2 should ever appear when browsing Store 1, and vice versa.

---

### Test 12.1: Store 1 only shows Store 1 products

**Preconditions:** Seeded Store 1 products

**Steps:**
1. Navigate to `/` (resolved to Store 1 via acme-fashion.test domain)

**Expected Results:**
- Page displays "Acme Fashion"
- Page displays "Classic Cotton T-Shirt"
- Products from other stores (e.g., electronics from Store 2) are absent
- No JavaScript errors

---

### Test 12.2: Store 1 collections only contain Store 1 products

**Preconditions:** Seeded collections

**Steps:**
1. Navigate to `/collections/t-shirts`

**Expected Results:**
- Page displays "T-Shirts"
- Only Store 1 products appear in the collection grid
- No JavaScript errors

---

### Test 12.3: Admin cannot access other store data

**Preconditions:** Logged in as admin@acme.test (Store 1 owner)

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin (email: `admin@acme.test`, password: `password`)
3. Click "Products" in the sidebar
4. Review the product list
5. Click "Orders" in the sidebar
6. Review the order list

**Expected Results:**
- All products listed belong to Store 1 only
- All orders listed belong to Store 1 only
- No cross-store data is visible
- No JavaScript errors

---

### Test 12.4: Search only returns current store products

**Preconditions:** Seeded Store 1 products

**Steps:**
1. Navigate to `/search?q=product`

**Expected Results:**
- Only Store 1 products appear in search results
- No cross-store data leakage
- No JavaScript errors

---

### Test 12.5: Customer accounts are scoped to their store

**Preconditions:** customer@acme.test seeded for Store 1

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `password`
4. Click "Log in"
5. Click "Orders"

**Expected Results:**
- Customer only sees Store 1 orders (#1001, #1002, #1004)
- No JavaScript errors

**Total: 5 tests**

---

## Suite 13: Responsive / Mobile

**File:** `tests/Browser/Storefront/ResponsiveTest.php`

**Purpose:** Verify that the storefront and admin panel render and function correctly on mobile (375x812) and tablet (768x1024) viewports.

### Viewport Definitions

| Device | Width | Height | Use For |
|--------|-------|--------|---------|
| iPhone (mobile) | 375 | 812 | Storefront tests |
| iPad (tablet) | 768 | 1024 | Admin panel tests |

---

### Test 13.1: Storefront home works on mobile viewport

**Preconditions:** Seeded store

**Steps:**
1. Set viewport to iPhone dimensions (375x812)
2. Navigate to `/`

**Expected Results:**
- Page displays "Acme Fashion"
- Mobile menu (hamburger) is visible
- Desktop navigation is hidden
- No horizontal scroll
- No JavaScript errors

---

### Test 13.2: Product page stacks layout on mobile

**Preconditions:** Product #1

**Steps:**
1. Set viewport to mobile (375x812)
2. Navigate to `/products/classic-cotton-t-shirt`

**Expected Results:**
- Page displays "Classic Cotton T-Shirt", "24.99", "Add to cart"
- Gallery and details stack vertically
- No JavaScript errors

---

### Test 13.3: Can add to cart on mobile

**Preconditions:** Product #1

**Steps:**
1. Set viewport to mobile (375x812)
2. Navigate to `/products/classic-cotton-t-shirt`
3. Click "M" to select size M
4. Click "Black" to select color Black
5. Click "Add to cart"

**Expected Results:**
- Product added to cart successfully
- No JavaScript errors


find app/Livewire/Storefront/Account -maxdepth 3 -type f -print | sort


find resources/views/livewire/storefront/account -maxdepth 3 -type f -print | sort


Output:
Chunk ID: f6889c
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 104
Output:
resources/views/livewire/storefront/account/auth/forgot-password.blade.php
resources/views/livewire/storefront/account/auth/login.blade.php
resources/views/livewire/storefront/account/auth/register.blade.php
resources/views/livewire/storefront/account/auth/reset-password.blade.php
resources/views/livewire/storefront/account/orders/index.blade.php
resources/views/livewire/storefront/account/orders/show.blade.php


Output:
Chunk ID: f293d6
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 77
Output:
app/Livewire/Storefront/Account/Auth/ForgotPassword.php
app/Livewire/Storefront/Account/Auth/Login.php
app/Livewire/Storefront/Account/Auth/Register.php
app/Livewire/Storefront/Account/Auth/ResetPassword.php
app/Livewire/Storefront/Account/Orders/Index.php
app/Livewire/Storefront/Account/Orders/Show.php


sed -n '2070,2295p' specs/08-PLAYWRIGHT-E2E-PLAN.md


sed -n '2070,2295p' specs/08-PLAYWRIGHT-E2E-PLAN.md

**Expected Results:**
- Payment form dynamically updates based on selected payment method
- No JavaScript errors

**Total: 13 tests**

---

## Suite 10: Customer Account

**File:** `tests/Browser/Storefront/CustomerAccountTest.php`

**Purpose:** Verify customer registration, login, account dashboard, order history, order detail, address management, and logout on the storefront.

### Customer Account Flow

```mermaid
flowchart TD
    Guest[Guest visitor] -->|visit /account/register| Register[Registration Form]
    Guest -->|visit /account/login| Login[Login Form]
    Register -->|valid data + click 'Create account'| Dashboard[My Account Dashboard]
    Login -->|valid credentials + click 'Log in'| Dashboard
    Login -->|invalid credentials| Login
    Dashboard --> OrderHistory[/account/orders]
    OrderHistory --> OrderDetail[/account/orders/number]
    Dashboard --> Addresses[/account/addresses]
    Addresses -->|click 'Add address'| AddAddress[Address form]
    Addresses -->|click 'Edit'| EditAddress[Edit address form]
    Dashboard -->|click 'Logout'| Guest
```

---

### Test 10.1: Can register a new customer

**Preconditions:** None

**Steps:**
1. Navigate to `/account/register`
2. Enter name: `New Customer`
3. Enter email: `new-customer-e2e@example.com`
4. Enter password: `password123`
5. Enter password confirmation: `password123`
6. Click "Create account"

**Expected Results:**
- Page displays "My Account"
- No JavaScript errors

---

### Test 10.2: Shows validation errors for duplicate email registration

**Preconditions:** customer@acme.test already exists

**Steps:**
1. Navigate to `/account/register`
2. Enter name: `Duplicate Customer`
3. Enter email: `customer@acme.test`
4. Enter password: `password123`
5. Enter password confirmation: `password123`
6. Click "Create account"

**Expected Results:**
- Page displays "already been taken" error
- No JavaScript errors

---

### Test 10.3: Shows validation errors for mismatched passwords

**Preconditions:** None

**Steps:**
1. Navigate to `/account/register`
2. Enter name: `Test Customer`
3. Enter email: `mismatch@example.com`
4. Enter password: `password123`
5. Enter password confirmation: `different456`
6. Click "Create account"

**Expected Results:**
- Validation error referencing "password" is displayed
- No JavaScript errors

---

### Test 10.4: Can log in as existing customer

**Preconditions:** customer@acme.test seeded

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `password`
4. Click "Log in"

**Expected Results:**
- Page displays "My Account"
- Page displays "John Doe"
- No JavaScript errors

---

### Test 10.5: Shows error for invalid customer credentials

**Preconditions:** customer@acme.test seeded

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `wrongpassword`
4. Click "Log in"

**Expected Results:**
- Page displays "Invalid credentials"
- No JavaScript errors

---

### Test 10.6: Redirects unauthenticated customers to login

**Preconditions:** Not logged in

**Steps:**
1. Navigate to `/account` (without logging in)

**Expected Results:**
- Page displays "Log in" (redirected to login form)
- No JavaScript errors

---

### Test 10.7: Shows order history for logged-in customer

**Preconditions:** Logged in as customer@acme.test, Orders #1001/#1002/#1004 exist

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `password`
4. Click "Log in"
5. Click "Orders" or navigate to order history

**Expected Results:**
- Page displays "#1001"
- Page displays "#1002"
- Page displays "#1004"
- No JavaScript errors

---

### Test 10.8: Shows order detail for customer order

**Preconditions:** Logged in as customer, Order #1001 exists

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Orders"
4. Click "#1001"

**Expected Results:**
- Page displays "#1001"
- Page displays "Subtotal"
- Page displays "Total"
- No JavaScript errors

---

### Test 10.9: Can view addresses

**Preconditions:** Logged in as customer

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"

**Expected Results:**
- Existing addresses are displayed
- No JavaScript errors

---

### Test 10.10: Can add a new address

**Preconditions:** Logged in as customer

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"
4. Click "Add address"
5. Enter first name: `John`
6. Enter last name: `Doe`
7. Enter address: `New Street 42`
8. Enter city: `Hamburg`
9. Enter postal code: `20095`
10. Enter country: `DE`
11. Click "Save"

**Expected Results:**
- Page displays "Address saved"
- Page displays "New Street 42"
- Page displays "Hamburg"
- No JavaScript errors

---

### Test 10.11: Can edit an existing address

**Preconditions:** Logged in as customer, at least one address exists

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"
4. Click "Edit" on the first address
5. Change city to: `Frankfurt`
6. Click "Save"

**Expected Results:**
- Page displays "Address saved"
- Page displays "Frankfurt"
- No JavaScript errors


Output:
Chunk ID: 07400b
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1350
Output:
**Expected Results:**
- Payment form dynamically updates based on selected payment method
- No JavaScript errors

**Total: 13 tests**

---

## Suite 10: Customer Account

**File:** `tests/Browser/Storefront/CustomerAccountTest.php`

**Purpose:** Verify customer registration, login, account dashboard, order history, order detail, address management, and logout on the storefront.

### Customer Account Flow

```mermaid
flowchart TD
    Guest[Guest visitor] -->|visit /account/register| Register[Registration Form]
    Guest -->|visit /account/login| Login[Login Form]
    Register -->|valid data + click 'Create account'| Dashboard[My Account Dashboard]
    Login -->|valid credentials + click 'Log in'| Dashboard
    Login -->|invalid credentials| Login
    Dashboard --> OrderHistory[/account/orders]
    OrderHistory --> OrderDetail[/account/orders/number]
    Dashboard --> Addresses[/account/addresses]
    Addresses -->|click 'Add address'| AddAddress[Address form]
    Addresses -->|click 'Edit'| EditAddress[Edit address form]
    Dashboard -->|click 'Logout'| Guest
```

---

### Test 10.1: Can register a new customer

**Preconditions:** None

**Steps:**
1. Navigate to `/account/register`
2. Enter name: `New Customer`
3. Enter email: `new-customer-e2e@example.com`
4. Enter password: `password123`
5. Enter password confirmation: `password123`
6. Click "Create account"

**Expected Results:**
- Page displays "My Account"
- No JavaScript errors

---

### Test 10.2: Shows validation errors for duplicate email registration

**Preconditions:** customer@acme.test already exists

**Steps:**
1. Navigate to `/account/register`
2. Enter name: `Duplicate Customer`
3. Enter email: `customer@acme.test`
4. Enter password: `password123`
5. Enter password confirmation: `password123`
6. Click "Create account"

**Expected Results:**
- Page displays "already been taken" error
- No JavaScript errors

---

### Test 10.3: Shows validation errors for mismatched passwords

**Preconditions:** None

**Steps:**
1. Navigate to `/account/register`
2. Enter name: `Test Customer`
3. Enter email: `mismatch@example.com`
4. Enter password: `password123`
5. Enter password confirmation: `different456`
6. Click "Create account"

**Expected Results:**
- Validation error referencing "password" is displayed
- No JavaScript errors

---

### Test 10.4: Can log in as existing customer

**Preconditions:** customer@acme.test seeded

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `password`
4. Click "Log in"

**Expected Results:**
- Page displays "My Account"
- Page displays "John Doe"
- No JavaScript errors

---

### Test 10.5: Shows error for invalid customer credentials

**Preconditions:** customer@acme.test seeded

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `wrongpassword`
4. Click "Log in"

**Expected Results:**
- Page displays "Invalid credentials"
- No JavaScript errors

---

### Test 10.6: Redirects unauthenticated customers to login

**Preconditions:** Not logged in

**Steps:**
1. Navigate to `/account` (without logging in)

**Expected Results:**
- Page displays "Log in" (redirected to login form)
- No JavaScript errors

---

### Test 10.7: Shows order history for logged-in customer

**Preconditions:** Logged in as customer@acme.test, Orders #1001/#1002/#1004 exist

**Steps:**
1. Navigate to `/account/login`
2. Enter email: `customer@acme.test`
3. Enter password: `password`
4. Click "Log in"
5. Click "Orders" or navigate to order history

**Expected Results:**
- Page displays "#1001"
- Page displays "#1002"
- Page displays "#1004"
- No JavaScript errors

---

### Test 10.8: Shows order detail for customer order

**Preconditions:** Logged in as customer, Order #1001 exists

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Orders"
4. Click "#1001"

**Expected Results:**
- Page displays "#1001"
- Page displays "Subtotal"
- Page displays "Total"
- No JavaScript errors

---

### Test 10.9: Can view addresses

**Preconditions:** Logged in as customer

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"

**Expected Results:**
- Existing addresses are displayed
- No JavaScript errors

---

### Test 10.10: Can add a new address

**Preconditions:** Logged in as customer

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"
4. Click "Add address"
5. Enter first name: `John`
6. Enter last name: `Doe`
7. Enter address: `New Street 42`
8. Enter city: `Hamburg`
9. Enter postal code: `20095`
10. Enter country: `DE`
11. Click "Save"

**Expected Results:**
- Page displays "Address saved"
- Page displays "New Street 42"
- Page displays "Hamburg"
- No JavaScript errors

---

### Test 10.11: Can edit an existing address

**Preconditions:** Logged in as customer, at least one address exists

**Steps:**
1. Navigate to `/account/login`
2. Log in as customer (email: `customer@acme.test`, password: `password`)
3. Click "Addresses"
4. Click "Edit" on the first address
5. Change city to: `Frankfurt`
6. Click "Save"

**Expected Results:**
- Page displays "Address saved"
- Page displays "Frankfurt"
- No JavaScript errors


php artisan route:list --path=account --except-vendor


sed -n '1,220p' database/seeders/CustomerSeeder.php


sed -n '1,240p' resources/views/livewire/storefront/account/orders/index.blade.php && sed -n '1,240p' resources/views/livewire/storefront/account/orders/show.blade.php


/bin/zsh
-lc
sed -n '1,240p' routes/web.php

<?php

use App\Http\Controllers\Api\OAuthController;
use App\Http\Controllers\Storefront\Account\Auth\CustomerPasswordResetController;
use App\Http\Middleware\EnsureUserEmailIsVerified;
use App\Livewire\Admin\Analytics\Index as AdminAnalyticsIndex;
use App\Livewire\Admin\Apps\Index as AdminAppsIndex;
use App\Livewire\Admin\Apps\Show as AdminAppShow;
use App\Livewire\Admin\Auth\Login as AdminLogin;
use App\Livewire\Admin\Collections\Form as AdminCollectionForm;
use App\Livewire\Admin\Collections\Index as AdminCollectionsIndex;
use App\Livewire\Admin\Customers\Index as AdminCustomersIndex;
use App\Livewire\Admin\Customers\Show as AdminCustomerShow;
use App\Livewire\Admin\Dashboard as AdminDashboard;
use App\Livewire\Admin\Developers\Index as AdminDevelopersIndex;
use App\Livewire\Admin\Discounts\Form as AdminDiscountForm;
use App\Livewire\Admin\Discounts\Index as AdminDiscountsIndex;
use App\Livewire\Admin\Inventory\Index as AdminInventoryIndex;
use App\Livewire\Admin\Navigation\Index as AdminNavigationIndex;
use App\Livewire\Admin\Orders\Index as AdminOrdersIndex;
use App\Livewire\Admin\Orders\Show as AdminOrderShow;
use App\Livewire\Admin\Pages\Form as AdminPageForm;
use App\Livewire\Admin\Pages\Index as AdminPagesIndex;
use App\Livewire\Admin\Products\Form as AdminProductForm;
use App\Livewire\Admin\Products\Index as AdminProductsIndex;
use App\Livewire\Admin\Search\Settings as AdminSearchSettings;
use App\Livewire\Admin\Settings\Checkout as AdminSettingsCheckout;
use App\Livewire\Admin\Settings\Index as AdminSettingsIndex;
use App\Livewire\Admin\Settings\Notifications as AdminSettingsNotifications;
use App\Livewire\Admin\Settings\Shipping as AdminSettingsShipping;
use App\Livewire\Admin\Settings\Taxes as AdminSettingsTaxes;
use App\Livewire\Admin\Themes\Editor as AdminThemeEditor;
use App\Livewire\Admin\Themes\Index as AdminThemesIndex;
use App\Livewire\Storefront\Account\Auth\ForgotPassword as CustomerForgotPassword;
use App\Livewire\Storefront\Account\Auth\Login as CustomerLogin;
use App\Livewire\Storefront\Account\Auth\Register as CustomerRegister;
use App\Livewire\Storefront\Account\Auth\ResetPassword as CustomerResetPassword;
use App\Livewire\Storefront\Account\Orders\Index as CustomerOrdersIndex;
use App\Livewire\Storefront\Account\Orders\Show as CustomerOrderShow;
use App\Livewire\Storefront\Cart\Show as StorefrontCartShow;
use App\Livewire\Storefront\Checkout\Confirmation as StorefrontCheckoutConfirmation;
use App\Livewire\Storefront\Checkout\Show as StorefrontCheckoutShow;
use App\Livewire\Storefront\Collections\Index as StorefrontCollectionsIndex;
use App\Livewire\Storefront\Collections\Show as StorefrontCollectionShow;
use App\Livewire\Storefront\Home as StorefrontHome;
use App\Livewire\Storefront\Pages\Show as StorefrontPageShow;
use App\Livewire\Storefront\Products\Show as StorefrontProductShow;
use App\Livewire\Storefront\Search\Index as StorefrontSearchIndex;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Laravel\Fortify\Http\Controllers\NewPasswordController as FortifyNewPasswordController;
use Laravel\Fortify\Http\Controllers\PasswordResetLinkController as FortifyPasswordResetLinkController;

Route::middleware(['storefront'])->group(function (): void {
    Route::livewire('/', StorefrontHome::class)->name('home');
    Route::livewire('collections', StorefrontCollectionsIndex::class)->name('collections.index');
    Route::livewire('collections/{handle}', StorefrontCollectionShow::class)->name('collections.show');
    Route::livewire('products/{handle}', StorefrontProductShow::class)->name('products.show');
    Route::livewire('cart', StorefrontCartShow::class)->name('cart.show');
    Route::livewire('checkout', StorefrontCheckoutShow::class)->name('checkout.show');
    Route::livewire('checkout/confirmation/{order}', StorefrontCheckoutConfirmation::class)->name('checkout.confirmation');
    Route::livewire('search', StorefrontSearchIndex::class)->name('search.index');
    Route::livewire('pages/{handle}', StorefrontPageShow::class)->name('pages.show');

    Route::livewire('forgot-password', CustomerForgotPassword::class)
        ->middleware('guest:customer')
        ->name('customer.password.request');

    Route::post('forgot-password', [CustomerPasswordResetController::class, 'send'])
        ->middleware('guest:customer')
        ->name('customer.password.email');

    Route::livewire('reset-password/{token}', CustomerResetPassword::class)
        ->middleware('guest:customer')
        ->name('customer.password.reset');

    Route::post('reset-password', [CustomerPasswordResetController::class, 'update'])
        ->middleware('guest:customer')
        ->name('customer.password.update');
});

Route::livewire('admin/login', AdminLogin::class)
    ->middleware('guest')
    ->name('admin.login');

Route::get('admin/forgot-password', [FortifyPasswordResetLinkController::class, 'create'])
    ->middleware('guest')
    ->name('admin.password.request');

Route::post('admin/forgot-password', [FortifyPasswordResetLinkController::class, 'store'])
    ->middleware('guest')
    ->name('admin.password.email');

Route::get('admin/reset-password/{token}', [FortifyNewPasswordController::class, 'create'])
    ->middleware('guest')
    ->name('admin.password.reset');

Route::post('admin/reset-password', [FortifyNewPasswordController::class, 'store'])
    ->middleware('guest')
    ->name('admin.password.update');

Route::post('admin/logout', function () {
    Auth::guard('web')->logout();

    request()->session()->invalidate();
    request()->session()->regenerateToken();

    return redirect()->route('admin.login');
})->middleware('auth')->name('admin.logout');

Route::get('oauth/authorize', [OAuthController::class, 'authorize'])
    ->middleware('auth')
    ->name('oauth.authorize');

Route::post('oauth/token', [OAuthController::class, 'token'])
    ->name('oauth.token');

Route::middleware(['auth', EnsureUserEmailIsVerified::class, 'admin'])->prefix('admin')->name('admin.')->group(function (): void {
    Route::livewire('/', AdminDashboard::class)->name('dashboard');
    Route::livewire('analytics', AdminAnalyticsIndex::class)->name('analytics.index');
    Route::livewire('apps', AdminAppsIndex::class)->name('apps.index');
    Route::livewire('apps/{installation}', AdminAppShow::class)->name('apps.show');
    Route::livewire('developers', AdminDevelopersIndex::class)->name('developers.index');
    Route::livewire('products', AdminProductsIndex::class)->name('products.index');
    Route::livewire('products/create', AdminProductForm::class)->name('products.create');
    Route::livewire('products/{product}/edit', AdminProductForm::class)->name('products.edit');
    Route::livewire('inventory', AdminInventoryIndex::class)->name('inventory.index');
    Route::livewire('orders', AdminOrdersIndex::class)->name('orders.index');
    Route::livewire('orders/{order}', AdminOrderShow::class)->name('orders.show');
    Route::livewire('customers', AdminCustomersIndex::class)->name('customers.index');
    Route::livewire('customers/{customer}', AdminCustomerShow::class)->name('customers.show');
    Route::livewire('discounts', AdminDiscountsIndex::class)->name('discounts.index');
    Route::livewire('discounts/create', AdminDiscountForm::class)->name('discounts.create');
    Route::livewire('discounts/{discount}/edit', AdminDiscountForm::class)->name('discounts.edit');
    Route::livewire('pages', AdminPagesIndex::class)->name('pages.index');
    Route::livewire('pages/create', AdminPageForm::class)->name('pages.create');
    Route::livewire('pages/{page}/edit', AdminPageForm::class)->name('pages.edit');
    Route::livewire('navigation', AdminNavigationIndex::class)->name('navigation.index');
    Route::livewire('themes', AdminThemesIndex::class)->name('themes.index');
    Route::livewire('themes/{theme}/editor', AdminThemeEditor::class)->name('themes.editor');
    Route::livewire('settings', AdminSettingsIndex::class)->name('settings.index');
    Route::livewire('settings/shipping', AdminSettingsShipping::class)->name('settings.shipping');
    Route::livewire('settings/taxes', AdminSettingsTaxes::class)->name('settings.taxes');
    Route::livewire('settings/checkout', AdminSettingsCheckout::class)->name('settings.checkout');
    Route::livewire('settings/notifications', AdminSettingsNotifications::class)->name('settings.notifications');
    Route::livewire('search/settings', AdminSearchSettings::class)->name('search.settings');
    Route::livewire('collections', AdminCollectionsIndex::class)->name('collections.index');
    Route::livewire('collections/create', AdminCollectionForm::class)->name('collections.create');
    Route::livewire('collections/{collection}/edit', AdminCollectionForm::class)->name('collections.edit');
});

Route::middleware(['storefront'])->group(function (): void {
    Route::livewire('account/login', CustomerLogin::class)
        ->middleware('guest:customer')
        ->name('account.login');

    Route::livewire('account/register', CustomerRegister::class)
        ->middleware('guest:customer')
        ->name('account.register');

    Route::livewire('account/forgot-password', CustomerForgotPassword::class)
        ->middleware('guest:customer')
        ->name('account.password.request');

    Route::livewire('account/reset-password/{token}', CustomerResetPassword::class)
        ->middleware('guest:customer')
        ->name('account.password.reset');

    Route::livewire('account', CustomerOrdersIndex::class)
        ->middleware('auth:customer')
        ->name('account.dashboard');

    Route::livewire('account/orders/{order}', CustomerOrderShow::class)
        ->middleware('auth:customer')
        ->name('account.orders.show');
});

Route::redirect('dashboard', 'admin')
    ->middleware(['auth', 'verified'])
    ->name('dashboard');

require __DIR__.'/settings.php';


sed -n '1,220p' database/seeders/CustomerSeeder.php

<?php

namespace Database\Seeders;

use App\Models\Customer;
use App\Models\Store;
use Illuminate\Database\Seeder;

class CustomerSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();

        Customer::withoutGlobalScopes()->updateOrCreate(
            [
                'store_id' => $store->getKey(),
                'email' => 'customer@acme.test',
            ],
            [
                'name' => 'John Doe',
                'password' => 'password',
                'marketing_opt_in' => true,
            ],
        );
    }
}


sed -n '1,240p' resources/views/livewire/storefront/account/orders/index.blade.php && sed -n '1,240p' resources/views/livewire/storefront/account/orders/show.blade.php

show.blade.php

    <x-storefront.breadcrumbs :items="[
        ['label' => 'Account'],
    ]" />

Orders

            @forelse ($orders as $order)

{{ $order->order_number }}

{{ $order->placed_at?->format('M j, Y') }}

                        <flux:badge>{{ $order->financial_status->value }}</flux:badge>
                        <flux:badge>{{ $order->fulfillment_status->value }}</flux:badge>

                    <x-storefront.price :amount="$order->total_amount" :currency="$order->currency" class="justify-start sm:justify-end" />

            @empty

                    <flux:icon name="shopping-bag" class="mx-auto size-10 text-zinc-400 dark:text-zinc-600" />

No orders yet

                    <flux:button :href="route('collections.index')" wire:navigate variant="primary" class="mt-6">
                        Browse products
                    </flux:button>

            @endforelse

    <x-storefront.breadcrumbs :items="[
        ['label' => 'Account', 'url' => route('account.dashboard')],
        ['label' => $order->order_number],
    ]" />

{{ $order->order_number }}

{{ $order->placed_at?->format('M j, Y') }}

                <flux:heading size="lg">Items</flux:heading>

                    @foreach ($order->lines as $line)

getKey() }}">

{{ $line->title_snapshot }}

Qty {{ $line->quantity }}

                            <x-storefront.price :amount="$line->total_amount" :currency="$order->currency" />

                    @endforeach

            @if ($order->fulfillments->isNotEmpty())

                    <flux:heading size="lg">Fulfillment</flux:heading>

                        @foreach ($order->fulfillments as $fulfillment)

getKey() }}">

                                    {{ $fulfillment->status->value }}
                                    @if ($fulfillment->tracking_number)
                                        {{ $fulfillment->tracking_number }}
                                    @endif

                        @endforeach

            @endif

Summary

                <flux:badge>{{ $order->financial_status->value }}</flux:badge>
                <flux:badge>{{ $order->fulfillment_status->value }}</flux:badge>

                    Subtotal
                    <x-storefront.price :amount="$order->subtotal_amount" :currency="$order->currency" />

                    Discount
                    -{{ \App\Support\Money::format($order->discount_amount, $order->currency) }}

                    Shipping
                    <x-storefront.price :amount="$order->shipping_amount" :currency="$order->currency" />

                    Tax
                    <x-storefront.price :amount="$order->tax_amount" :currency="$order->currency" />

                    Total
                    <x-storefront.price :amount="$order->total_amount" :currency="$order->currency" />


Output:
Chunk ID: 62ebff
Wall time: 0.0299 seconds
Process exited with code 0
Original token count: 21
Output:

   ERROR  Your application doesn't have any routes matching the given criteria.


Output:
Chunk ID: 0f8d0a
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 2477
Output:
<?php

use App\Http\Controllers\Api\OAuthController;
use App\Http\Controllers\Storefront\Account\Auth\CustomerPasswordResetController;
use App\Http\Middleware\EnsureUserEmailIsVerified;
use App\Livewire\Admin\Analytics\Index as AdminAnalyticsIndex;
use App\Livewire\Admin\Apps\Index as AdminAppsIndex;
use App\Livewire\Admin\Apps\Show as AdminAppShow;
use App\Livewire\Admin\Auth\Login as AdminLogin;
use App\Livewire\Admin\Collections\Form as AdminCollectionForm;
use App\Livewire\Admin\Collections\Index as AdminCollectionsIndex;
use App\Livewire\Admin\Customers\Index as AdminCustomersIndex;
use App\Livewire\Admin\Customers\Show as AdminCustomerShow;
use App\Livewire\Admin\Dashboard as AdminDashboard;
use App\Livewire\Admin\Developers\Index as AdminDevelopersIndex;
use App\Livewire\Admin\Discounts\Form as AdminDiscountForm;
use App\Livewire\Admin\Discounts\Index as AdminDiscountsIndex;
use App\Livewire\Admin\Inventory\Index as AdminInventoryIndex;
use App\Livewire\Admin\Navigation\Index as AdminNavigationIndex;
use App\Livewire\Admin\Orders\Index as AdminOrdersIndex;
use App\Livewire\Admin\Orders\Show as AdminOrderShow;
use App\Livewire\Admin\Pages\Form as AdminPageForm;
use App\Livewire\Admin\Pages\Index as AdminPagesIndex;
use App\Livewire\Admin\Products\Form as AdminProductForm;
use App\Livewire\Admin\Products\Index as AdminProductsIndex;
use App\Livewire\Admin\Search\Settings as AdminSearchSettings;
use App\Livewire\Admin\Settings\Checkout as AdminSettingsCheckout;
use App\Livewire\Admin\Settings\Index as AdminSettingsIndex;
use App\Livewire\Admin\Settings\Notifications as AdminSettingsNotifications;
use App\Livewire\Admin\Settings\Shipping as AdminSettingsShipping;
use App\Livewire\Admin\Settings\Taxes as AdminSettingsTaxes;
use App\Livewire\Admin\Themes\Editor as AdminThemeEditor;
use App\Livewire\Admin\Themes\Index as AdminThemesIndex;
use App\Livewire\Storefront\Account\Auth\ForgotPassword as CustomerForgotPassword;
use App\Livewire\Storefront\Account\Auth\Login as CustomerLogin;
use App\Livewire\Storefront\Account\Auth\Register as CustomerRegister;
use App\Livewire\Storefront\Account\Auth\ResetPassword as CustomerResetPassword;
use App\Livewire\Storefront\Account\Orders\Index as CustomerOrdersIndex;
use App\Livewire\Storefront\Account\Orders\Show as CustomerOrderShow;
use App\Livewire\Storefront\Cart\Show as StorefrontCartShow;
use App\Livewire\Storefront\Checkout\Confirmation as StorefrontCheckoutConfirmation;
use App\Livewire\Storefront\Checkout\Show as StorefrontCheckoutShow;
use App\Livewire\Storefront\Collections\Index as StorefrontCollectionsIndex;
use App\Livewire\Storefront\Collections\Show as StorefrontCollectionShow;
use App\Livewire\Storefront\Home as StorefrontHome;
use App\Livewire\Storefront\Pages\Show as StorefrontPageShow;
use App\Livewire\Storefront\Products\Show as StorefrontProductShow;
use App\Livewire\Storefront\Search\Index as StorefrontSearchIndex;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
use Laravel\Fortify\Http\Controllers\NewPasswordController as FortifyNewPasswordController;
use Laravel\Fortify\Http\Controllers\PasswordResetLinkController as FortifyPasswordResetLinkController;

Route::middleware(['storefront'])->group(function (): void {
    Route::livewire('/', StorefrontHome::class)->name('home');
    Route::livewire('collections', StorefrontCollectionsIndex::class)->name('collections.index');
    Route::livewire('collections/{handle}', StorefrontCollectionShow::class)->name('collections.show');
    Route::livewire('products/{handle}', StorefrontProductShow::class)->name('products.show');
    Route::livewire('cart', StorefrontCartShow::class)->name('cart.show');
    Route::livewire('checkout', StorefrontCheckoutShow::class)->name('checkout.show');
    Route::livewire('checkout/confirmation/{order}', StorefrontCheckoutConfirmation::class)->name('checkout.confirmation');
    Route::livewire('search', StorefrontSearchIndex::class)->name('search.index');
    Route::livewire('pages/{handle}', StorefrontPageShow::class)->name('pages.show');

    Route::livewire('forgot-password', CustomerForgotPassword::class)
        ->middleware('guest:customer')
        ->name('customer.password.request');

    Route::post('forgot-password', [CustomerPasswordResetController::class, 'send'])
        ->middleware('guest:customer')
        ->name('customer.password.email');

    Route::livewire('reset-password/{token}', CustomerResetPassword::class)
        ->middleware('guest:customer')
        ->name('customer.password.reset');

    Route::post('reset-password', [CustomerPasswordResetController::class, 'update'])
        ->middleware('guest:customer')
        ->name('customer.password.update');
});

Route::livewire('admin/login', AdminLogin::class)
    ->middleware('guest')
    ->name('admin.login');

Route::get('admin/forgot-password', [FortifyPasswordResetLinkController::class, 'create'])
    ->middleware('guest')
    ->name('admin.password.request');

Route::post('admin/forgot-password', [FortifyPasswordResetLinkController::class, 'store'])
    ->middleware('guest')
    ->name('admin.password.email');

Route::get('admin/reset-password/{token}', [FortifyNewPasswordController::class, 'create'])
    ->middleware('guest')
    ->name('admin.password.reset');

Route::post('admin/reset-password', [FortifyNewPasswordController::class, 'store'])
    ->middleware('guest')
    ->name('admin.password.update');

Route::post('admin/logout', function () {
    Auth::guard('web')->logout();

    request()->session()->invalidate();
    request()->session()->regenerateToken();

    return redirect()->route('admin.login');
})->middleware('auth')->name('admin.logout');

Route::get('oauth/authorize', [OAuthController::class, 'authorize'])
    ->middleware('auth')
    ->name('oauth.authorize');

Route::post('oauth/token', [OAuthController::class, 'token'])
    ->name('oauth.token');

Route::middleware(['auth', EnsureUserEmailIsVerified::class, 'admin'])->prefix('admin')->name('admin.')->group(function (): void {
    Route::livewire('/', AdminDashboard::class)->name('dashboard');
    Route::livewire('analytics', AdminAnalyticsIndex::class)->name('analytics.index');
    Route::livewire('apps', AdminAppsIndex::class)->name('apps.index');
    Route::livewire('apps/{installation}', AdminAppShow::class)->name('apps.show');
    Route::livewire('developers', AdminDevelopersIndex::class)->name('developers.index');
    Route::livewire('products', AdminProductsIndex::class)->name('products.index');
    Route::livewire('products/create', AdminProductForm::class)->name('products.create');
    Route::livewire('products/{product}/edit', AdminProductForm::class)->name('products.edit');
    Route::livewire('inventory', AdminInventoryIndex::class)->name('inventory.index');
    Route::livewire('orders', AdminOrdersIndex::class)->name('orders.index');
    Route::livewire('orders/{order}', AdminOrderShow::class)->name('orders.show');
    Route::livewire('customers', AdminCustomersIndex::class)->name('customers.index');
    Route::livewire('customers/{customer}', AdminCustomerShow::class)->name('customers.show');
    Route::livewire('discounts', AdminDiscountsIndex::class)->name('discounts.index');
    Route::livewire('discounts/create', AdminDiscountForm::class)->name('discounts.create');
    Route::livewire('discounts/{discount}/edit', AdminDiscountForm::class)->name('discounts.edit');
    Route::livewire('pages', AdminPagesIndex::class)->name('pages.index');
    Route::livewire('pages/create', AdminPageForm::class)->name('pages.create');
    Route::livewire('pages/{page}/edit', AdminPageForm::class)->name('pages.edit');
    Route::livewire('navigation', AdminNavigationIndex::class)->name('navigation.index');
    Route::livewire('themes', AdminThemesIndex::class)->name('themes.index');
    Route::livewire('themes/{theme}/editor', AdminThemeEditor::class)->name('themes.editor');
    Route::livewire('settings', AdminSettingsIndex::class)->name('settings.index');
    Route::livewire('settings/shipping', AdminSettingsShipping::class)->name('settings.shipping');
    Route::livewire('settings/taxes', AdminSettingsTaxes::class)->name('settings.taxes');
    Route::livewire('settings/checkout', AdminSettingsCheckout::class)->name('settings.checkout');
    Route::livewire('settings/notifications', AdminSettingsNotifications::class)->name('settings.notifications');
    Route::livewire('search/settings', AdminSearchSettings::class)->name('search.settings');
    Route::livewire('collections', AdminCollectionsIndex::class)->name('collections.index');
    Route::livewire('collections/create', AdminCollectionForm::class)->name('collections.create');
    Route::livewire('collections/{collection}/edit', AdminCollectionForm::class)->name('collections.edit');
});

Route::middleware(['storefront'])->group(function (): void {
    Route::livewire('account/login', CustomerLogin::class)
        ->middleware('guest:customer')
        ->name('account.login');

    Route::livewire('account/register', CustomerRegister::class)
        ->middleware('guest:customer')
        ->name('account.register');

    Route::livewire('account/forgot-password', CustomerForgotPassword::class)
        ->middleware('guest:customer')
        ->name('account.password.request');

    Route::livewire('account/reset-password/{token}', CustomerResetPassword::class)
        ->middleware('guest:customer')
        ->name('account.password.reset');

    Route::livewire('account', CustomerOrdersIndex::class)
        ->middleware('auth:customer')
        ->name('account.dashboard');

    Route::livewire('account/orders/{order}', CustomerOrderShow::class)
        ->middleware('auth:customer')
        ->name('account.orders.show');
});

Route::redirect('dashboard', 'admin')
    ->middleware(['auth', 'verified'])
    ->name('dashboard');

require __DIR__.'/settings.php';


Output:
Chunk ID: 7a10bc
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 169
Output:
<?php

namespace Database\Seeders;

use App\Models\Customer;
use App\Models\Store;
use Illuminate\Database\Seeder;

class CustomerSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        $store = Store::query()->where('handle', 'acme-fashion')->firstOrFail();

        Customer::withoutGlobalScopes()->updateOrCreate(
            [
                'store_id' => $store->getKey(),
                'email' => 'customer@acme.test',
            ],
            [
                'name' => 'John Doe',
                'password' => 'password',
                'marketing_opt_in' => true,
            ],
        );
    }
}


Output:
Chunk ID: 15906d
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 1672
Output:

    <x-storefront.breadcrumbs :items="[
        ['label' => 'Account'],
    ]" />

Orders

            @forelse ($orders as $order)

{{ $order->order_number }}

{{ $order->placed_at?->format('M j, Y') }}

                        <flux:badge>{{ $order->financial_status->value }}</flux:badge>
                        <flux:badge>{{ $order->fulfillment_status->value }}</flux:badge>

                    <x-storefront.price :amount="$order->total_amount" :currency="$order->currency" class="justify-start sm:justify-end" />

            @empty

                    <flux:icon name="shopping-bag" class="mx-auto size-10 text-zinc-400 dark:text-zinc-600" />

No orders yet

                    <flux:button :href="route('collections.index')" wire:navigate variant="primary" class="mt-6">
                        Browse products
                    </flux:button>

            @endforelse

    <x-storefront.breadcrumbs :items="[
        ['label' => 'Account', 'url' => route('account.dashboard')],
        ['label' => $order->order_number],
    ]" />

{{ $order->order_number }}

{{ $order->placed_at?->format('M j, Y') }}

                <flux:heading size="lg">Items</flux:heading>

                    @foreach ($order->lines as $line)

getKey() }}">

{{ $line->title_snapshot }}

Qty {{ $line->quantity }}

                            <x-storefront.price :amount="$line->total_amount" :currency="$order->currency" />

                    @endforeach

            @if ($order->fulfillments->isNotEmpty())

                    <flux:heading size="lg">Fulfillment</flux:heading>

                        @foreach ($order->fulfillments as $fulfillment)

getKey() }}">

                                    {{ $fulfillment->status->value }}
                                    @if ($fulfillment->tracking_number)
                                        {{ $fulfillment->tracking_number }}
                                    @endif

                        @endforeach

            @endif

Summary

                <flux:badge>{{ $order->financial_status->value }}</flux:badge>
                <flux:badge>{{ $order->fulfillment_status->value }}</flux:badge>

                    Subtotal
                    <x-storefront.price :amount="$order->subtotal_amount" :currency="$order->currency" />

                    Discount
                    -{{ \App\Support\Money::format($order->discount_amount, $order->currency) }}

                    Shipping
                    <x-storefront.price :amount="$order->shipping_amount" :currency="$order->currency" />

                    Tax
                    <x-storefront.price :amount="$order->tax_amount" :currency="$order->currency" />

                    Total
                    <x-storefront.price :amount="$order->total_amount" :currency="$order->currency" />


php artisan route:list --path=account --except-vendor

ERROR  Your application doesn't have any routes matching the given criteria.


rg "CustomerAddress|customer_addresses|Address" app resources tests database -n


rg "CustomerAddress|customer_addresses|Address" app resources tests database -n

rg 'CustomerAddress|customer_addresses|Address' app resources tests database -n

Question: CustomerAddress|customer_addresses|Address

database/factories/OrderFactory.php:145:            'address1' => fake()->streetAddress(),
database/factories/CustomerAddressFactory.php:9: * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\CustomerAddress>
database/factories/CustomerAddressFactory.php:11:class CustomerAddressFactory extends Factory
database/factories/CustomerAddressFactory.php:26:                'address1' => fake()->streetAddress(),
tests/Feature/Api/StorefrontCheckoutApiTest.php:50:function storefrontApiCheckoutAddress(string $country = 'DE'): array
tests/Feature/Api/StorefrontCheckoutApiTest.php:97:            'shipping_address' => storefrontApiCheckoutAddress(),
tests/Feature/Api/StorefrontCheckoutApiTest.php:169:            'shipping_address' => array_diff_key(storefrontApiCheckoutAddress(), ['first_name' => true]),
tests/Feature/Api/StorefrontCheckoutApiTest.php:176:            'shipping_address' => storefrontApiCheckoutAddress(),
tests/Feature/Orders/OrderServiceTest.php:122:    $checkout = app(CheckoutService::class)->setAddress($checkout, [
tests/Feature/Checkout/CheckoutServiceTest.php:5:use App\Exceptions\UnserviceableShippingAddressException;
tests/Feature/Checkout/CheckoutServiceTest.php:60:function checkoutAddress(string $country = 'DE'): array
tests/Feature/Checkout/CheckoutServiceTest.php:95:    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
tests/Feature/Checkout/CheckoutServiceTest.php:96:    expect($checkout->status)->toBe(CheckoutStatus::Addressed)
tests/Feature/Checkout/CheckoutServiceTest.php:128:    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress('FR'));
tests/Feature/Checkout/CheckoutServiceTest.php:131:        ->toThrow(UnserviceableShippingAddressException::class);
tests/Feature/Checkout/CheckoutServiceTest.php:140:    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
tests/Feature/Checkout/CheckoutServiceTest.php:167:    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
tests/Feature/Checkout/CheckoutServiceTest.php:197:    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
tests/Feature/Api/AdminCatalogApiTest.php:4:use App\Models\CustomerAddress;
tests/Feature/Api/AdminCatalogApiTest.php:88:    CustomerAddress::factory()->default()->create(['customer_id' => $customer->getKey()]);
tests/Browser/Storefront/CheckoutTest.php:44:function storefrontCheckoutFillAddress(mixed $page, array $overrides = []): mixed
tests/Browser/Storefront/CheckoutTest.php:60:        ->fill('input[wire\\:model="shippingAddress.first_name"]', $address['first_name'])
tests/Browser/Storefront/CheckoutTest.php:61:        ->fill('input[wire\\:model="shippingAddress.last_name"]', $address['last_name'])
tests/Browser/Storefront/CheckoutTest.php:62:        ->fill('input[wire\\:model="shippingAddress.address1"]', $address['address1'])
tests/Browser/Storefront/CheckoutTest.php:63:        ->fill('input[wire\\:model="shippingAddress.city"]', $address['city'])
tests/Browser/Storefront/CheckoutTest.php:64:        ->fill('input[wire\\:model="shippingAddress.postal_code"]', $address['postal_code'])
tests/Browser/Storefront/CheckoutTest.php:65:        ->select('select[wire\\:model="shippingAddress.country"]', $address['country']);
tests/Browser/Storefront/CheckoutTest.php:68:function storefrontCheckoutSubmitAddress(mixed $page): mixed
tests/Browser/Storefront/CheckoutTest.php:71:        ->click('form[wire\\:submit="saveAddress"] button[type="submit"]')
tests/Browser/Storefront/CheckoutTest.php:77:    return storefrontCheckoutSubmitAddress(
tests/Browser/Storefront/CheckoutTest.php:78:        storefrontCheckoutFillAddress(storefrontCheckoutStart(), $address),
tests/Browser/Storefront/CheckoutTest.php:166:    storefrontCheckoutSubmitAddress(storefrontCheckoutFillAddress($page))
tests/Browser/Storefront/CheckoutTest.php:179:        ->click('form[wire\\:submit="saveAddress"] button[type="submit"]')
tests/Browser/Storefront/CheckoutTest.php:188:        ->click('form[wire\\:submit="saveAddress"] button[type="submit"]')
tests/Browser/Storefront/CheckoutTest.php:199:    storefrontCheckoutSubmitAddress(storefrontCheckoutFillAddress(storefrontCheckoutStart(), [
database/seeders/CustomerAddressSeeder.php:7:class CustomerAddressSeeder extends Seeder
tests/Feature/Storefront/OrderViewsTest.php:68:        ->set('shippingAddress.first_name', 'Test')
tests/Feature/Storefront/OrderViewsTest.php:69:        ->set('shippingAddress.last_name', 'Buyer')
tests/Feature/Storefront/OrderViewsTest.php:70:        ->set('shippingAddress.address1', 'Main Street 1')
tests/Feature/Storefront/OrderViewsTest.php:71:        ->set('shippingAddress.city', 'Berlin')
tests/Feature/Storefront/OrderViewsTest.php:72:        ->set('shippingAddress.country', 'DE')
tests/Feature/Storefront/OrderViewsTest.php:73:        ->set('shippingAddress.postal_code', '10115')
tests/Feature/Storefront/OrderViewsTest.php:74:      …11878 chars truncated…json ?? []);
app/Livewire/Admin/Customers/Show.php:69:            $this->resetAddressForm();
app/Livewire/Admin/Customers/Show.php:75:    public function saveAddress(): void
app/Livewire/Admin/Customers/Show.php:89:        $address = $this->editingAddressId
app/Livewire/Admin/Customers/Show.php:90:            ? $this->address($this->editingAddressId)
app/Livewire/Admin/Customers/Show.php:91:            : new CustomerAddress(['customer_id' => $this->customerId]);
app/Livewire/Admin/Customers/Show.php:100:        $this->resetAddressForm();
app/Livewire/Admin/Customers/Show.php:102:        $this->dispatch('toast', type: 'success', message: __('Address saved'));
app/Livewire/Admin/Customers/Show.php:105:    public function deleteAddress(int $addressId): void
app/Livewire/Admin/Customers/Show.php:112:            $this->setFirstAddressAsDefault();
app/Livewire/Admin/Customers/Show.php:115:        $this->dispatch('toast', type: 'success', message: __('Address deleted'));
app/Livewire/Admin/Customers/Show.php:118:    public function setDefaultAddress(int $addressId): void
app/Livewire/Admin/Customers/Show.php:123:            CustomerAddress::query()
app/Livewire/Admin/Customers/Show.php:164:    private function address(int $addressId): CustomerAddress
app/Livewire/Admin/Customers/Show.php:166:        return CustomerAddress::query()
app/Livewire/Admin/Customers/Show.php:172:    private function setFirstAddressAsDefault(): void
app/Livewire/Admin/Customers/Show.php:174:        $nextAddress = CustomerAddress::query()
app/Livewire/Admin/Customers/Show.php:179:        if ($nextAddress instanceof CustomerAddress) {
app/Livewire/Admin/Customers/Show.php:180:            $nextAddress->forceFill(['is_default' => true])->save();
app/Livewire/Admin/Customers/Show.php:184:    private function resetAddressForm(): void
app/Livewire/Admin/Customers/Show.php:186:        $this->editingAddressId = null;
app/Livewire/Admin/Customers/Show.php:188:        $this->addressJson = $this->emptyAddressJson();
app/Livewire/Admin/Customers/Show.php:194:    private function emptyAddressJson(): array
database/migrations/2026_05_04_000408_create_customer_addresses_table.php:14:        Schema::create('customer_addresses', function (Blueprint $table) {
database/migrations/2026_05_04_000408_create_customer_addresses_table.php:31:        Schema::dropIfExists('customer_addresses');
app/Livewire/Storefront/Cart/Show.php:193:        return app(ShippingCalculator::class)->getAvailableRates($this->store(), $this->shippingAddress());
app/Livewire/Storefront/Cart/Show.php:301:    private function shippingAddress(): array
app/Livewire/Storefront/Checkout/Show.php:9:use App\Exceptions\UnserviceableShippingAddressException;
app/Livewire/Storefront/Checkout/Show.php:39:    public array $shippingAddress = [
app/Livewire/Storefront/Checkout/Show.php:53:    public array $billingAddress = [
app/Livewire/Storefront/Checkout/Show.php:88:    public function saveAddress(): void
app/Livewire/Storefront/Checkout/Show.php:92:            'shippingAddress.first_name' => ['required', 'string'],
app/Livewire/Storefront/Checkout/Show.php:93:            'shippingAddress.last_name' => ['required', 'string'],
app/Livewire/Storefront/Checkout/Show.php:94:            'shippingAddress.address1' => ['required', 'string'],
app/Livewire/Storefront/Checkout/Show.php:95:            'shippingAddress.city' => ['required', 'string'],
app/Livewire/Storefront/Checkout/Show.php:96:            'shippingAddress.country' => ['required', 'string', 'size:2'],
app/Livewire/Storefront/Checkout/Show.php:97:            'shippingAddress.postal_code' => [
app/Livewire/Storefront/Checkout/Show.php:101:                    if (strtoupper($this->shippingAddress['country']) === 'DE' && preg_match('/^\d{5}$/', (string) $value) !== 1) {
app/Livewire/Storefront/Checkout/Show.php:116:            $checkout = app(CheckoutService::class)->setAddress($checkout, [
app/Livewire/Storefront/Checkout/Show.php:118:                'shipping_address' => $this->shippingAddress,
app/Livewire/Storefront/Checkout/Show.php:119:                'billing_address' => $this->billingSame ? $this->shippingAddress : $this->billingAddress,
app/Livewire/Storefront/Checkout/Show.php:156:        } catch (InvalidCheckoutTransitionException|UnserviceableShippingAddressException $exception) {
app/Livewire/Storefront/Checkout/Show.php:324:        if ($this->shippingAddress['country'] === '') {
app/Livewire/Storefront/Checkout/Show.php:328:        return app(ShippingCalculator::class)->getAvailableRates($this->store(), $this->shippingAddress);
app/Livewire/Storefront/Checkout/Show.php:413:        $this->shippingAddress = array_replace($this->shippingAddress, $checkout->shipping_address_json ?? []);
app/Livewire/Storefront/Checkout/Show.php:414:        $this->billingAddress = array_replace($this->billingAddress, $checkout->billing_address_json ?? []);
app/Livewire/Storefront/Checkout/Show.php:420:            CheckoutStatus::Addressed => 'shipping',


Output:
Chunk ID: 0d9371
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 5470
Output:
database/factories/OrderFactory.php:145:            'address1' => fake()->streetAddress(),
database/factories/CustomerAddressFactory.php:9: * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\CustomerAddress>
database/factories/CustomerAddressFactory.php:11:class CustomerAddressFactory extends Factory
database/factories/CustomerAddressFactory.php:26:                'address1' => fake()->streetAddress(),
tests/Feature/Api/StorefrontCheckoutApiTest.php:50:function storefrontApiCheckoutAddress(string $country = 'DE'): array
tests/Feature/Api/StorefrontCheckoutApiTest.php:97:            'shipping_address' => storefrontApiCheckoutAddress(),
tests/Feature/Api/StorefrontCheckoutApiTest.php:169:            'shipping_address' => array_diff_key(storefrontApiCheckoutAddress(), ['first_name' => true]),
tests/Feature/Api/StorefrontCheckoutApiTest.php:176:            'shipping_address' => storefrontApiCheckoutAddress(),
tests/Feature/Orders/OrderServiceTest.php:122:    $checkout = app(CheckoutService::class)->setAddress($checkout, [
tests/Feature/Checkout/CheckoutServiceTest.php:5:use App\Exceptions\UnserviceableShippingAddressException;
tests/Feature/Checkout/CheckoutServiceTest.php:60:function checkoutAddress(string $country = 'DE'): array
tests/Feature/Checkout/CheckoutServiceTest.php:95:    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
tests/Feature/Checkout/CheckoutServiceTest.php:96:    expect($checkout->status)->toBe(CheckoutStatus::Addressed)
tests/Feature/Checkout/CheckoutServiceTest.php:128:    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress('FR'));
tests/Feature/Checkout/CheckoutServiceTest.php:131:        ->toThrow(UnserviceableShippingAddressException::class);
tests/Feature/Checkout/CheckoutServiceTest.php:140:    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
tests/Feature/Checkout/CheckoutServiceTest.php:167:    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
tests/Feature/Checkout/CheckoutServiceTest.php:197:    $checkout = app(CheckoutService::class)->setAddress($checkout, checkoutAddress());
tests/Feature/Api/AdminCatalogApiTest.php:4:use App\Models\CustomerAddress;
tests/Feature/Api/AdminCatalogApiTest.php:88:    CustomerAddress::factory()->default()->create(['customer_id' => $customer->getKey()]);
tests/Browser/Storefront/CheckoutTest.php:44:function storefrontCheckoutFillAddress(mixed $page, array $overrides = []): mixed
tests/Browser/Storefront/CheckoutTest.php:60:        ->fill('input[wire\\:model="shippingAddress.first_name"]', $address['first_name'])
tests/Browser/Storefront/CheckoutTest.php:61:        ->fill('input[wire\\:model="shippingAddress.last_name"]', $address['last_name'])
tests/Browser/Storefront/CheckoutTest.php:62:        ->fill('input[wire\\:model="shippingAddress.address1"]', $address['address1'])
tests/Browser/Storefront/CheckoutTest.php:63:        ->fill('input[wire\\:model="shippingAddress.city"]', $address['city'])
tests/Browser/Storefront/CheckoutTest.php:64:        ->fill('input[wire\\:model="shippingAddress.postal_code"]', $address['postal_code'])
tests/Browser/Storefront/CheckoutTest.php:65:        ->select('select[wire\\:model="shippingAddress.country"]', $address['country']);
tests/Browser/Storefront/CheckoutTest.php:68:function storefrontCheckoutSubmitAddress(mixed $page): mixed
tests/Browser/Storefront/CheckoutTest.php:71:        ->click('form[wire\\:submit="saveAddress"] button[type="submit"]')
tests/Browser/Storefront/CheckoutTest.php:77:    return storefrontCheckoutSubmitAddress(
tests/Browser/Storefront/CheckoutTest.php:78:        storefrontCheckoutFillAddress(storefrontCheckoutStart(), $address),
tests/Browser/Storefront/CheckoutTest.php:166:    storefrontCheckoutSubmitAddress(storefrontCheckoutFillAddress($page))
tests/Browser/Storefront/CheckoutTest.php:179:        ->click('form[wire\\:submit="saveAddress"] button[type="submit"]')
tests/Browser/Storefront/CheckoutTest.php:188:        ->click('form[wire\\:submit="saveAddress"] button[type="submit"]')
tests/Browser/Storefront/CheckoutTest.php:199:    storefrontCheckoutSubmitAddress(storefrontCheckoutFillAddress(storefrontCheckoutStart(), [
database/seeders/CustomerAddressSeeder.php:7:class CustomerAddressSeeder extends Seeder
tests/Feature/Storefront/OrderViewsTest.php:68:        ->set('shippingAddress.first_name', 'Test')
tests/Feature/Storefront/OrderViewsTest.php:69:        ->set('shippingAddress.last_name', 'Buyer')
tests/Feature/Storefront/OrderViewsTest.php:70:        ->set('shippingAddress.address1', 'Main Street 1')
tests/Feature/Storefront/OrderViewsTest.php:71:        ->set('shippingAddress.city', 'Berlin')
tests/Feature/Storefront/OrderViewsTest.php:72:        ->set('shippingAddress.country', 'DE')
tests/Feature/Storefront/OrderViewsTest.php:73:        ->set('shippingAddress.postal_code', '10115')
tests/Feature/Storefront/OrderViewsTest.php:74:        ->call('saveAddress')
tests/Feature/Storefront/OrderViewsTest.php:102:        ->set('shippingAddress.first_name', 'Test')
tests/Feature/Storefront/OrderViewsTest.php:103:        ->set('shippingAddress.last_name', 'Buyer')
tests/Feature/Storefront/OrderViewsTest.php:104:        ->set('shippingAddress.address1', 'Main Street 1')
tests/Feature/Storefront/OrderViewsTest.php:105:        ->set('shippingAddress.city', 'Berlin')
tests/Feature/Storefront/OrderViewsTest.php:106:        ->set('shippingAddress.country', 'DE')
tests/Feature/Storefront/OrderViewsTest.php:107:        ->set('shippingAddress.postal_code', '10115')
tests/Feature/Storefront/OrderViewsTest.php:108:        ->call('saveAddress')
tests/Feature/Storefront/CartCheckoutUiTest.php:156:        ->set('shippingAddress.first_name', 'Test')
tests/Feature/Storefront/CartCheckoutUiTest.php:157:        ->set('shippingAddress.last_name', 'Buyer')
tests/Feature/Storefront/CartCheckoutUiTest.php:158:        ->set('shippingAddress.address1', 'Main Street 1')
tests/Feature/Storefront/CartCheckoutUiTest.php:159:        ->set('shippingAddress.city', 'Berlin')
tests/Feature/Storefront/CartCheckoutUiTest.php:160:        ->set('shippingAddress.country', 'DE')
tests/Feature/Storefront/CartCheckoutUiTest.php:161:        ->set('shippingAddress.postal_code', '10115')
tests/Feature/Storefront/CartCheckoutUiTest.php:162:        ->call('saveAddress')
tests/Feature/Admin/CustomerManagementTest.php:6:use App\Models\CustomerAddress;
tests/Feature/Admin/CustomerManagementTest.php:61:    CustomerAddress::factory()->default()->create([
tests/Feature/Admin/CustomerManagementTest.php:115:    $home = CustomerAddress::factory()->default()->create([
tests/Feature/Admin/CustomerManagementTest.php:122:        ->call('openAddressForm')
tests/Feature/Admin/CustomerManagementTest.php:128:        ->call('saveAddress')
tests/Feature/Admin/CustomerManagementTest.php:131:    $office = CustomerAddress::query()
tests/Feature/Admin/CustomerManagementTest.php:140:        ->call('setDefaultAddress', $office->getKey())
tests/Feature/Admin/CustomerManagementTest.php:142:        ->call('openAddressForm', $office->getKey())
tests/Feature/Admin/CustomerManagementTest.php:144:        ->call('saveAddress')
tests/Feature/Admin/CustomerManagementTest.php:146:        ->call('deleteAddress', $home->getKey())
tests/Feature/Admin/CustomerManagementTest.php:151:        ->and(CustomerAddress::query()->whereKey($home->getKey())->exists())->toBeFalse();
tests/Feature/Api/StorefrontOrderApiTest.php:49:function storefrontOrderApiCheckout(object $testCase, string $remoteAddress = '10.0.0.41'): array
tests/Feature/Api/StorefrontOrderApiTest.php:53:    $api = fn () => $testCase->withServerVariables(['REMOTE_ADDR' => $remoteAddress])->withHeader('Host', 'shop.test');
tests/Feature/Admin/SettingsManagementTest.php:126:        ->call('testShippingAddress')
tests/Feature/Admin/SettingsManagementTest.php:148:        ->set('billingAddressEnabled', false)
app/Http/Controllers/Api/Storefront/V1/CheckoutController.php:9:use App\Exceptions\UnserviceableShippingAddressException;
app/Http/Controllers/Api/Storefront/V1/CheckoutController.php:14:use App\Http\Requests\Api\Storefront\V1\SetCheckoutAddressRequest;
app/Http/Controllers/Api/Storefront/V1/CheckoutController.php:55:    public function address(SetCheckoutAddressRequest $request, Checkout $checkout, CheckoutService $checkouts): CheckoutResource|JsonResponse
app/Http/Controllers/Api/Storefront/V1/CheckoutController.php:61:            return CheckoutResource::make($this->loadCheckout($checkouts->setAddress($checkout, $addressData)));
app/Http/Controllers/Api/Storefront/V1/CheckoutController.php:74:        } catch (InvalidCheckoutTransitionException|UnserviceableShippingAddressException $exception) {
resources/views/livewire/auth/login.blade.php:11:
resources/views/livewire/admin/settings/checkout.blade.php:33:                    <flux:switch wire:model="billingAddressEnabled" label="Separate billing address enabled" align="left" />
resources/views/livewire/admin/settings/shipping.blade.php:145:                    <flux:button type="button" wire:click="testShippingAddress" variant="filled">Test</flux:button>
resources/views/livewire/auth/forgot-password.blade.php:11:
resources/views/livewire/auth/forgot-password.blade.php:14:                :label="__('Email Address')"
app/Services/CheckoutService.php:8:use App\Exceptions\UnserviceableShippingAddressException;
app/Services/CheckoutService.php:51:    public function setAddress(Checkout $checkout, array $addressData): Checkout
app/Services/CheckoutService.php:55:            $this->assertStatus($checkout, [CheckoutStatus::Started, CheckoutStatus::Addressed]);
app/Services/CheckoutService.php:58:            $shippingAddress = data_get($addressData, 'shipping_address', $addressData);
app/Services/CheckoutService.php:62:                'shipping_address' => $shippingAddress,
app/Services/CheckoutService.php:75:                'shipping_address_json' => $shippingAddress,
app/Services/CheckoutService.php:76:                'billing_address_json' => data_get($addressData, 'billing_address', $shippingAddress),
app/Services/CheckoutService.php:77:                'status' => CheckoutStatus::Addressed,
app/Services/CheckoutService.php:90:            $this->assertStatus($checkout, [CheckoutStatus::Addressed, CheckoutStatus::ShippingSelected]);
app/Services/CheckoutService.php:106:                throw UnserviceableShippingAddressException::forAddress();
resources/views/livewire/admin/customers/show.blade.php:97:                <flux:heading size="lg">Addresses</flux:heading>
resources/views/livewire/admin/customers/show.blade.php:98:                <flux:button wire:click="openAddressForm" variant="primary" icon="plus" size="sm">Add</flux:button>
resources/views/livewire/admin/customers/show.blade.php:109:
{{ $address->label ?: 'Address' }}

resources/views/livewire/admin/customers/show.blade.php:126:                            <flux:button wire:click="openAddressForm({{ $address->getKey() }})" size="sm" variant="filled">Edit</flux:button>
resources/views/livewire/admin/customers/show.blade.php:128:                                <flux:button wire:click="setDefaultAddress({{ $address->getKey() }})" size="sm" variant="ghost">Set default</flux:button>
resources/views/livewire/admin/customers/show.blade.php:130:                            <flux:button wire:click="deleteAddress({{ $address->getKey() }})" wire:confirm="Delete this address?" size="sm" variant="danger">Delete</flux:button>
resources/views/livewire/admin/customers/show.blade.php:144:        <form wire:submit="saveAddress" class="space-y-6">
resources/views/livewire/admin/customers/show.blade.php:146:                <flux:heading size="lg">{{ $editingAddressId ? 'Edit address' : 'Add address' }}</flux:heading>
resources/views/livewire/admin/customers/show.blade.php:155:                    <flux:input wire:model="addressJson.address1" label="Address line 1" />
resources/views/livewire/admin/customers/show.blade.php:159:                    <flux:input wire:model="addressJson.address2" label="Address line 2" />
resources/views/livewire/auth/register.blade.php:22:
resources/views/livewire/auth/reset-password.blade.php:13:
app/Exceptions/UnserviceableShippingAddressException.php:7:class UnserviceableShippingAddressException extends RuntimeException
app/Exceptions/UnserviceableShippingAddressException.php:9:    public static function forAddress(): self
app/Enums/CheckoutStatus.php:8:    case Addressed = 'addressed';
app/Models/CustomerAddress.php:9:class CustomerAddress extends Model
app/Models/CustomerAddress.php:11:    /** @use HasFactory<\Database\Factories\CustomerAddressFactory> */
app/Http/Requests/Api/Storefront/V1/SetCheckoutAddressRequest.php:7:class SetCheckoutAddressRequest extends FormRequest
resources/views/livewire/storefront/checkout/show.blade.php:12:                    @foreach (['address' => 'Address', 'shipping' => 'Shipping', 'payment' => 'Payment'] as $key => $label)
resources/views/livewire/storefront/checkout/show.blade.php:34:                <form wire:submit="saveAddress" class="rounded-lg border border-zinc-200 bg-white p-5 dark:border-zinc-800 dark:bg-zinc-950">
resources/views/livewire/storefront/checkout/show.blade.php:53:                            <flux:input wire:model="shippingAddress.first_name" label="First name" />
resources/views/livewire/storefront/checkout/show.blade.php:54:                            <flux:error name="shippingAddress.first_name" />
resources/views/livewire/storefront/checkout/show.blade.php:57:                            <flux:input wire:model="shippingAddress.last_name" label="Last name" />
resources/views/livewire/storefront/checkout/show.blade.php:58:                            <flux:error name="shippingAddress.last_name" />
resources/views/livewire/storefront/checkout/show.blade.php:62:                            <flux:input wire:model="shippingAddress.address1" label="Address" />
resources/views/livewire/storefront/checkout/show.blade.php:63:                            <flux:error name="shippingAddress.address1" />
resources/views/livewire/storefront/checkout/show.blade.php:67:                            <flux:input wire:model="shippingAddress.address2" label="Apartment, suite, etc." />
resources/views/livewire/storefront/checkout/show.blade.php:71:                            <flux:input wire:model="shippingAddress.city" label="City" />
resources/views/livewire/storefront/checkout/show.blade.php:72:                            <flux:error name="shippingAddress.city" />
resources/views/livewire/storefront/checkout/show.blade.php:75:                            <flux:input wire:model="shippingAddress.postal_code" label="Postal code" />
resources/views/livewire/storefront/checkout/show.blade.php:76:                            <flux:error name="shippingAddress.postal_code" />
resources/views/livewire/storefront/checkout/show.blade.php:79:                        <flux:input wire:model="shippingAddress.province_code" label="Region code" placeholder="DE-BE" />
resources/views/livewire/storefront/checkout/show.blade.php:81:                            <flux:select wire:model="shippingAddress.country" label="Country">
resources/views/livewire/storefront/checkout/show.blade.php:87:                            <flux:error name="shippingAddress.country" />
app/Models/Customer.php:68:     * @return HasMany<CustomerAddress, $this>
app/Models/Customer.php:72:        return $this->hasMany(CustomerAddress::class);
app/Livewire/Admin/Settings/Checkout.php:24:    public bool $billingAddressEnabled = true;
app/Livewire/Admin/Settings/Checkout.php:58:            'billingAddressEnabled' => ['boolean'],
app/Livewire/Admin/Settings/Checkout.php:74:                    'billing_address_enabled' => $validated['billingAddressEnabled'],
app/Livewire/Admin/Settings/Checkout.php:106:        $this->billingAddressEnabled = (bool) data_get($settings, 'checkout.billing_address_enabled', true);
app/Livewire/Admin/Settings/Shipping.php:213:    public function testShippingAddress(ShippingCalculator $shipping): void
app/Livewire/Admin/Customers/Show.php:6:use App\Models\CustomerAddress;
app/Livewire/Admin/Customers/Show.php:25:    public ?int $editingAddressId = null;
app/Livewire/Admin/Customers/Show.php:60:    public function openAddressForm(?int $addressId = null): void
app/Livewire/Admin/Customers/Show.php:62:        $this->editingAddressId = $addressId;
app/Livewire/Admin/Customers/Show.php:67:            $this->addressJson = array_merge($this->emptyAddressJson(), $address->address_json ?? []);
app/Livewire/Admin/Customers/Show.php:69:            $this->resetAddressForm();
app/Livewire/Admin/Customers/Show.php:75:    public function saveAddress(): void
app/Livewire/Admin/Customers/Show.php:89:        $address = $this->editingAddressId
app/Livewire/Admin/Customers/Show.php:90:            ? $this->address($this->editingAddressId)
app/Livewire/Admin/Customers/Show.php:91:            : new CustomerAddress(['customer_id' => $this->customerId]);
app/Livewire/Admin/Customers/Show.php:100:        $this->resetAddressForm();
app/Livewire/Admin/Customers/Show.php:102:        $this->dispatch('toast', type: 'success', message: __('Address saved'));
app/Livewire/Admin/Customers/Show.php:105:    public function deleteAddress(int $addressId): void
app/Livewire/Admin/Customers/Show.php:112:            $this->setFirstAddressAsDefault();
app/Livewire/Admin/Customers/Show.php:115:        $this->dispatch('toast', type: 'success', message: __('Address deleted'));
app/Livewire/Admin/Customers/Show.php:118:    public function setDefaultAddress(int $addressId): void
app/Livewire/Admin/Customers/Show.php:123:            CustomerAddress::query()
app/Livewire/Admin/Customers/Show.php:164:    private function address(int $addressId): CustomerAddress
app/Livewire/Admin/Customers/Show.php:166:        return CustomerAddress::query()
app/Livewire/Admin/Customers/Show.php:172:    private function setFirstAddressAsDefault(): void
app/Livewire/Admin/Customers/Show.php:174:        $nextAddress = CustomerAddress::query()
app/Livewire/Admin/Customers/Show.php:179:        if ($nextAddress instanceof CustomerAddress) {
app/Livewire/Admin/Customers/Show.php:180:            $nextAddress->forceFill(['is_default' => true])->save();
app/Livewire/Admin/Customers/Show.php:184:    private function resetAddressForm(): void
app/Livewire/Admin/Customers/Show.php:186:        $this->editingAddressId = null;
app/Livewire/Admin/Customers/Show.php:188:        $this->addressJson = $this->emptyAddressJson();
app/Livewire/Admin/Customers/Show.php:194:    private function emptyAddressJson(): array
database/migrations/2026_05_04_000408_create_customer_addresses_table.php:14:        Schema::create('customer_addresses', function (Blueprint $table) {
database/migrations/2026_05_04_000408_create_customer_addresses_table.php:31:        Schema::dropIfExists('customer_addresses');
app/Livewire/Storefront/Cart/Show.php:193:        return app(ShippingCalculator::class)->getAvailableRates($this->store(), $this->shippingAddress());
app/Livewire/Storefront/Cart/Show.php:301:    private function shippingAddress(): array
app/Livewire/Storefront/Checkout/Show.php:9:use App\Exceptions\UnserviceableShippingAddressException;
app/Livewire/Storefront/Checkout/Show.php:39:    public array $shippingAddress = [
app/Livewire/Storefront/Checkout/Show.php:53:    public array $billingAddress = [
app/Livewire/Storefront/Checkout/Show.php:88:    public function saveAddress(): void
app/Livewire/Storefront/Checkout/Show.php:92:            'shippingAddress.first_name' => ['required', 'string'],
app/Livewire/Storefront/Checkout/Show.php:93:            'shippingAddress.last_name' => ['required', 'string'],
app/Livewire/Storefront/Checkout/Show.php:94:            'shippingAddress.address1' => ['required', 'string'],
app/Livewire/Storefront/Checkout/Show.php:95:            'shippingAddress.city' => ['required', 'string'],
app/Livewire/Storefront/Checkout/Show.php:96:            'shippingAddress.country' => ['required', 'string', 'size:2'],
app/Livewire/Storefront/Checkout/Show.php:97:            'shippingAddress.postal_code' => [
app/Livewire/Storefront/Checkout/Show.php:101:                    if (strtoupper($this->shippingAddress['country']) === 'DE' && preg_match('/^\d{5}$/', (string) $value) !== 1) {
app/Livewire/Storefront/Checkout/Show.php:116:            $checkout = app(CheckoutService::class)->setAddress($checkout, [
app/Livewire/Storefront/Checkout/Show.php:118:                'shipping_address' => $this->shippingAddress,
app/Livewire/Storefront/Checkout/Show.php:119:                'billing_address' => $this->billingSame ? $this->shippingAddress : $this->billingAddress,
app/Livewire/Storefront/Checkout/Show.php:156:        } catch (InvalidCheckoutTransitionException|UnserviceableShippingAddressException $exception) {
app/Livewire/Storefront/Checkout/Show.php:324:        if ($this->shippingAddress['country'] === '') {
app/Livewire/Storefront/Checkout/Show.php:328:        return app(ShippingCalculator::class)->getAvailableRates($this->store(), $this->shippingAddress);
app/Livewire/Storefront/Checkout/Show.php:413:        $this->shippingAddress = array_replace($this->shippingAddress, $checkout->shipping_address_json ?? []);
app/Livewire/Storefront/Checkout/Show.php:414:        $this->billingAddress = array_replace($this->billingAddress, $checkout->billing_address_json ?? []);
app/Livewire/Storefront/Checkout/Show.php:420:            CheckoutStatus::Addressed => 'shipping',


sed -n '1,200p' database/seeders/CustomerAddressSeeder.php && sed -n '1,120p' database/factories/CustomerAddressFactory.php && sed -n '1,120p' app/Models/CustomerAddress.php


sed -n '1,200p' database/seeders/CustomerAddressSeeder.php && sed -n '1,120p' database/factories/CustomerAddressFactory.php && sed -n '1,120p' app/Models/CustomerAddress.php

CustomerAddress.php

<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class CustomerAddressSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        //
    }
}
<?php

namespace Database\Factories;

use App\Models\Customer;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\CustomerAddress>
 */
class CustomerAddressFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'customer_id' => Customer::factory(),
            'label' => fake()->randomElement(['Shipping', 'Billing', 'Home', 'Office']),
            'address_json' => [
                'first_name' => fake()->firstName(),
                'last_name' => fake()->lastName(),
                'address1' => fake()->streetAddress(),
                'address2' => null,
                'city' => fake()->city(),
                'province_code' => null,
                'country' => 'DE',
                'postal_code' => fake()->postcode(),
            ],
            'is_default' => false,
        ];
    }

    public function default(): static
    {
        return $this->state(fn (array $attributes): array => [
            'is_default' => true,
        ]);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class CustomerAddress extends Model
{
    /** @use HasFactory<\Database\Factories\CustomerAddressFactory> */
    use HasFactory;

    public $timestamps = false;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'customer_id',
        'label',
        'address_json',
        'is_default',
    ];

    /**
     * @return BelongsTo<Customer, $this>
     */
    public function customer(): BelongsTo
    {
        return $this->belongsTo(Customer::class);
    }

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'address_json' => 'array',
            'is_default' => 'bool',
        ];
    }
}


Output:
Chunk ID: 2564bf
Wall time: 0.0000 seconds
Process exited with code 0
Original token count: 571
Output:
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;

class CustomerAddressSeeder extends Seeder
{
    /**
     * Run the database seeds.
     */
    public function run(): void
    {
        //
    }
}
<?php

namespace Database\Factories;

use App\Models\Customer;
use Illuminate\Database\Eloquent\Factories\Factory;

/**
 * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\CustomerAddress>
 */
class CustomerAddressFactory extends Factory
{
    /**
     * Define the model's default state.
     *
     * @return array<string, mixed>
     */
    public function definition(): array
    {
        return [
            'customer_id' => Customer::factory(),
            'label' => fake()->randomElement(['Shipping', 'Billing', 'Home', 'Office']),
            'address_json' => [
                'first_name' => fake()->firstName(),
                'last_name' => fake()->lastName(),
                'address1' => fake()->streetAddress(),
                'address2' => null,
                'city' => fake()->city(),
                'province_code' => null,
                'country' => 'DE',
                'postal_code' => fake()->postcode(),
            ],
            'is_default' => false,
        ];
    }

    public function default(): static
    {
        return $this->state(fn (array $attributes): array => [
            'is_default' => true,
        ]);
    }
}
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class CustomerAddress extends Model
{
    /** @use HasFactory<\Database\Factories\CustomerAddressFactory> */
    use HasFactory;

    public $timestamps = false;

    /**
     * @var list<string>
     */
    protected $fillable = [
        'customer_id',
        'label',
        'address_json',
        'is_default',
    ];

    /**
     * @return BelongsTo<Customer, $this>
     */
    public function customer(): BelongsTo
    {
        return $this->belongsTo(Customer::class);
    }

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'address_json' => 'array',
            'is_default' => 'bool',
        ];
    }
}


sed -n '1,200p' app/Livewire/Storefront/Account/Orders/Index.php && sed -n '1,220p' app/Livewire/Storefront/Account/Orders/Show.php && sed -n '1,180p' app/Livewire/Storefront/Account/Auth/Login.php && sed -n '1,180p' app/Livewire/Storefront/Account/Auth/Register.php