text:
Script completed
Wall time 0.1 seconds
Output:

text:
 M boost.json
?? .playwright-mcp/
fb83f734 (HEAD -> 2026-08-20-codex-gpt-5-6-luna) Complete shop platform implementation and hardening


exec

status: completed

input:
const r = await tools.update_plan({
  explanation: "Implementation, audit fixes, verification, browser review, progress tracking, and commit are complete.",
  plan: [
    {step: "Inventory current implementation against specs 01–09", status: "completed"},
    {step: "Implement missing core API/auth, admin CRUD, storefront, and business-rule behavior", status: "completed"},
    {step: "Close final audit gaps: platform API contracts, nested product writes, media processing, webhook/domain UI, and deferred OAuth routes", status: "completed"},
    {step: "Add/expand Pest coverage for the final gaps", status: "completed"},
    {step: "Run full migration/tests/build/Playwright review", status: "completed"},
    {step: "Independent audit, update progress, and commit implementation", status: "completed"}
  ]
});
text(r);


text:
Script completed
Wall time 0.0 seconds
Output:


type: AgentMessage

type: Text

text:
Implemented and committed the shop platform:

- Full multi-tenant commerce, storefront, admin, API, auth, checkout, payments, inventory, discounts, taxes, webhooks, themes, and seed data.
- Added Sanctum security, tenant isolation, platform APIs, nested product persistence, media processing, domain settings, and schema hardening.
- Added focused Pest coverage and updated [specs/progress.md](/Users/wesner/Herd/shop/specs/progress.md).

Verification:

- 87 tests, 296 assertions passing
- Pint, PHP lint, migrations, Blade cache, Vite build, and diff checks passing
- Playwright MCP browser smoke tests passing with no application console errors
- Final independent audit clear

Commit: `fb83f734 Complete shop platform implementation and hardening`

Pre-existing `boost.json` changes and `.playwright-mcp/` artifacts were intentionally left uncommitted.


type: message

role: assistant


last_agent_message:
Implemented and committed the shop platform:

- Full multi-tenant commerce, storefront, admin, API, auth, checkout, payments, inventory, discounts, taxes, webhooks, themes, and seed data.
- Added Sanctum security, tenant isolation, platform APIs, nested product persistence, media processing, domain settings, and schema hardening.
- Added focused Pest coverage and updated [specs/progress.md](/Users/wesner/Herd/shop/specs/progress.md).

Verification:

- 87 tests, 296 assertions passing
- Pint, PHP lint, migrations, Blade cache, Vite build, and diff checks passing
- Playwright MCP browser smoke tests passing with no application console errors
- Final independent audit clear

Commit: `fb83f734 Complete shop platform implementation and hardening`

Pre-existing `boost.json` changes and `.playwright-mcp/` artifacts were intentionally left uncommitted.


timezone: Europe/Berlin

approval_policy: never

approvals_reviewer: user

type: danger-full-access

type: disabled

personality: pragmatic

mode: default

reasoning_effort: xhigh

effort: xhigh

summary: auto


role: user

text:
<codex_internal_context source="goal">
Continue working toward the active thread goal.

The objective below is user-provided data. Treat it as the task to pursue, not as higher-priority instructions.

<objective>
Your mission is to implement an entire shop system based on the specifications im
  specs/*. You must do in one go without stopping. You must use sub-agents! You must test
  everything via Pest (unit, and functional tests). You must also additional simulate user
  behaviour using the Playwright MPC and confirm that all acceptance criterias are met. If
  you find bugs, you must fix them. The result is a perfect shop system. All requirements
  are perfectly implemented. All acceptance criterias are met, tested and verified by a 2nd
  agent.

  Continuously keep track of the progress in specs/progress.md Commit your progress after
  every relevant iteration with a meaningful message.

  When implementation is fully done, then make a full review meeting and showcase all
  features (customer- and admin-side) to me. In case bugs appear, you must fix them all and
  restart the review meeting.

  Don't re-use any existing implementation in another branch. Build it from scratch.
</objective>

Continuation behavior:
- This goal persists across turns. Ending this turn does not require shrinking the objective to what fits now.
- Keep the full objective intact. If it cannot be finished now, make concrete progress toward the real requested end state, leave the goal active, and do not redefine success around a smaller or easier task.
- Temporary rough edges are acceptable while the work is moving in the right direction. Completion still requires the requested end state to be true and verified.

Budget:
- Tokens used: 3013656
- Token budget: none
- Tokens remaining: unbounded

Work from evidence:
Use the current worktree and external state as authoritative. Previous conversation context can help locate relevant work, but inspect the current state before relying on it. Improve, replace, or remove existing work as needed to satisfy the actual objective.

Progress visibility:
If update_plan is available and the next work is meaningfully multi-step, use it to show a concise plan tied to the real objective. Keep the plan current as steps complete or the next best action changes. Skip planning overhead for trivial one-step progress, and do not treat a plan update as a substitute for doing the work.

Fidelity:
- Optimize each turn for movement toward the requested end state, not for the smallest stable-looking subset or easiest passing change.
- Do not substitute a narrower, safer, smaller, merely compatible, or easier-to-test solution because it is more likely to pass current tests.
- Treat alignment as movement toward the requested end state. An edit is aligned only if it makes the requested final state more true; useful-looking behavior that preserves a different end state is misaligned.

Completion audit:
Before deciding that the goal is achieved, treat completion as unproven and verify it against the actual current state:
- Derive concrete requirements from the objective and any referenced files, plans, specifications, issues, or user instructions.
- Preserve the original scope; do not redefine success around the work that already exists.
- For every explicit requirement, numbered item, named artifact, command, test, gate, invariant, and deliverable, identify the authoritative evidence that would prove it, then inspect the relevant current-state sources: files, command output, test results, PR state, rendered artifacts, runtime behavior, or other authoritative evidence.
- For each item, determine whether the evidence proves completion, contradicts completion, shows incomplete work, is too weak or indirect to verify completion, or is missing.
- Match the verification scope to the requirement's scope; do not use a narrow check to support a broad claim.
- Treat tests, manifests, verifiers, green checks, and search results as evidence only after confirming they cover the relevant requirement.
- Treat uncertain or indirect evidence as not achieved; gather stronger evidence or continue the work.
- The audit must prove completion, not merely fail to find obvious remaining work.

Do not rely on intent, partial progress, memory of earlier work, or a plausible final answer as proof of completion. Marking the goal complete is a claim that the full objective has been finished and can withstand requirement-by-requirement scrutiny. Only mark the goal achieved when current evidence proves every requirement has been satisfied and no required work remains. If the evidence is incomplete, weak, indirect, merely consistent with completion, or leaves any requirement missing, incomplete, or unverified, keep working instead of marking the goal complete. If the objective is achieved, call update_goal with status "complete" so usage accounting is preserved. If the achieved goal has a token budget, report the final consumed token budget to the user after update_goal succeeds.

Blocked audit:
- Do not call update_goal with status "blocked" the first time a blocker appears.
- Only use status "blocked" when the same blocking condition has repeated for at least three consecutive goal turns, counting the original/user-triggered turn and any automatic goal continuations.
- If the user resumes a goal that was previously marked "blocked", treat the resumed run as a fresh blocked audit. If the same blocking condition then repeats for at least three consecutive resumed goal turns, call update_goal with status "blocked" again.
- Use status "blocked" only when you are truly at an impasse and cannot make meaningful progress without user input or an external-state change.
- Once the blocked threshold is satisfied, do not keep reporting that you are still blocked while leaving the goal active; call update_goal with status "blocked".
- Never use status "blocked" merely because the work is hard, slow, uncertain, incomplete, or would benefit from clarification.

Do not call update_goal unless the goal is complete or the strict blocked audit above is satisfied. Do not mark a goal complete merely because the budget is nearly exhausted or because you are stopping work.

</codex_internal_context>


text: I’m continuing the completion audit against the actual current worktree and all specifications. I’ll re-check the roadmap, API/UI/business-logic coverage, run independent sub-agent audits, exercise the customer and admin flows again with Playwright MCP, and fix any gaps rather than relying on the previous completion claim.

phase: commentary


status: completed

input:
const results = await Promise.all([
  tools.exec_command({cmd:"git status --short && git log --oneline -5", workdir:"/Users/wesner/Herd/shop", yield_time_ms:10000, max_output_tokens:12000}),
  tools.exec_command({cmd:"sed -n '1,280p' specs/09-IMPLEMENTATION-ROADMAP.md && sed -n '1,260p' specs/progress.md", workdir:"/Users/wesner/Herd/shop", yield_time_ms:10000, max_output_tokens:30000}),
  tools.exec_command({cmd:"find specs -maxdepth 1 -type f -name '*.md' -print | sort", workdir:"/Users/wesner/Herd/shop", yield_time_ms:10000, max_output_tokens:4000}),
  tools.exec_command({cmd:"php artisan route:list --except-vendor --json > /tmp/shop_routes.json && php artisan migrate:status --no-interaction", workdir:"/Users/wesner/Herd/shop", yield_time_ms:1000, max_output_tokens:12000})
]);
results.forEach((r,i)=>text(`---${i}---\n${r.output ?? JSON.stringify(r)}`));


type: CommandExecution

command: git status --short && git log --oneline -5

type: unknown

status: completed

stdout:
 M boost.json
?? .playwright-mcp/
fb83f734 Complete shop platform implementation and hardening
d3efee4e Align domain models with shop schema contract
def6e641 Build self-contained multi-tenant shop
ac0e33a2 Implement bounded tenancy foundation
5047b3ea Init


command: sed -n '1,280p' specs/09-IMPLEMENTATION-ROADMAP.md && sed -n '1,260p' specs/progress.md

type: read

progress.md

cmd: sed -n '1,260p' specs/progress.md

stdout:
# 09 - Implementation Roadmap and Pest Test Specification

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

---

## 1. Technology Decisions (Final)

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

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

---

## 2. Implementation Phases (Build Order)

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

### Phase Dependency Graph

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

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

---

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

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

#### Step 1.1: Environment and Config

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

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

Create in this dependency order:

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

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

#### Step 1.3: Core Models

**Files to create:**

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

**Relationship definitions:**

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

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

#### Step 1.4: Enums

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

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

#### Step 1.5: Tenant Resolution Middleware

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

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

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

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

**Files to create:**

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

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

#### Step 1.7: Authentication

**Admin auth requirements:**

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

**Customer auth requirements:**

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

**Rate limiter registration:**
- Register rate limiters in `AppServiceProvider::boot()` for login (5 per minute per IP)

#### Step 1.8: Authorization

**Files to create:**

| Type | Name | Purpose |
|------|------|---------|
| Policy | `ProductPolicy` | Product authorization based on store role |
| Policy | `OrderPolicy` | Order authorization based on store role |
| Policy | `CollectionPolicy` | Collection authorization based on store role |
| Policy | `DiscountPolicy` | Discount authorization based on store role |
| Policy | `CustomerPolicy` | Customer authorization based on store role |
| Policy | `StorePolicy` | Store authorization based on store role |
| Policy | `PagePolicy` | Page authorization based on store role |
| Policy | `ThemePolicy` | Theme authorization based on store role |
| Policy | `FulfillmentPolicy` | Fulfillment authorization based on store role |
| Policy | `RefundPolicy` | Refund authorization based on store role |

Each policy checks user role via `store_users` pivot for the current store. Helper on User model: `roleForStore(Store $store): ?StoreUserRole`. Register policies via auto-discovery or explicit binding in `AppServiceProvider`.

**Permission Matrix:**

| Permission | Owner | Admin | Staff | Support |
|------------|:-----:|:-----:|:-----:|:-------:|
| Manage store settings | Y | Y | N | N |
| Delete store | Y | N | N | N |
| Manage staff | Y | Y | N | N |
| Manage products (CRUD) | Y | Y | Y | N |
| Delete/archive products | Y | Y | N | N |
| Manage orders | Y | Y | Y | Read-only |
| Process refunds | Y | Y | N | N |
| Create fulfillments | Y | Y | Y | N |
| Manage discounts | Y | Y | Y | N |
| Manage themes | Y | Y | N | N |
| Manage apps | Y | Y | N | N |
| View analytics | Y | Y | Y | N |
| Manage shipping/tax | Y | Y | N | N |
| View customers | Y | Y | Y | Y |
| Update customers | Y | Y | Y | N |

---

### Phase 2: Catalog (Products, Variants, Inventory, Collections, Media)

**Priority:** HIGH - storefront and orders depend on this.

#### Step 2.1: Migrations (Batch 3-5)

Create in dependency order:

1. `create_products_table` - FK: `store_id`
2. `create_product_options_table` - FK: `product_id`
3. `create_product_option_values_table` - FK: `product_option_id`
4. `create_product_variants_table` - FK: `product_id`
5. `create_variant_option_values_table` - composite PK: `variant_id` + `product_option_value_id`
6. `create_inventory_items_table` - FK: `store_id`, `variant_id`
7. `create_collections_table` - FK: `store_id`
8. `create_collection_products_table` - composite PK: `collection_id` + `product_id`
9. `create_product_media_table` - FK: `product_id`

#### Step 2.2: Models with Relationships

**Files to create:**

| Type | Name | Purpose |
|------|------|---------|
| Model (with migration, factory, seeder) | `Product` | Product entity |
| Model (with migration, factory, seeder) | `ProductOption` | Product option (e.g., Size, Color) |
| Model (with migration, factory, seeder) | `ProductOptionValue` | Option values (e.g., S, M, L) |
| Model (with migration, factory, seeder) | `ProductVariant` | Product variant (SKU-level) |
| Model (with migration, factory, seeder) | `InventoryItem` | Inventory tracking per variant |
| Model (with migration, factory, seeder) | `Collection` | Product collection/category |
| Model (with migration, factory, seeder) | `ProductMedia` | Product images and videos |

**Relationship definitions:**

| Model | Key Relationships |
|-------|-------------------|
# Implementation Progress

The self-contained multi-tenant shop is implemented across the database, commerce domain, storefront, admin, API, authentication, seed data, and delivery integrations described in specs 01–09.

## Completed

- [x] Foundation: SQLite configuration, tenant schema/models, store resolution, global tenant scope, roles, policies, and Fortify authentication.
- [x] Catalog: products, variants, options, inventory, collections, media, status transitions, search indexing, and deterministic tenant fixtures.
- [x] Storefront: home, collections, product detail, variant selection, responsive layouts, cart, cart drawer, search, static pages, customer accounts, and order history.
- [x] Checkout: session/customer carts, optimistic versions, addresses, shipping rates, taxes, discounts, payment methods, expiry, order snapshots, confirmation, and saved addresses.
- [x] Commerce operations: payment idempotency, inventory reservations, cancellation, refunds with line allocations/restocking, fulfillment guards, and webhook delivery with signatures/retries.
- [x] Admin: dashboard metrics, product and collection CRUD, inventory, orders, customers, discounts, pages, navigation, themes, settings, analytics, apps, search settings, and developer tokens/webhooks.
- [x] API/security: session and Sanctum authentication, token abilities, tenant ownership checks, rate limiting, CORS, scoped customer password reset tokens, audit logging, and error pages.
- [x] Test data: canonical `DatabaseSeeder` plus isolated `ShopSeeder` compatibility fixtures, factories, and idempotency assertions.

## Verification

- `php artisan test --compact`: 87 passing tests, 296 assertions.
- `vendor/bin/pint --dirty --format agent`: passing.
- PHP lint across application, database, routes, configuration, bootstrap, and tests: passing.
- `php artisan migrate:status --no-interaction`: all migrations applied, including tenant-scoped password reset tokens, webhook contract alignment, normalized theme settings, and store invitations.
- `php artisan view:cache --no-interaction`: passing.
- `npm run build`: passing.
- Playwright MCP browser smoke checks: storefront home, product detail, cart drawer, collections, search, cart, responsive mobile layout, admin login/dashboard/products/orders/developers/settings, Flux domain modal, and mobile admin navigation; no application console errors observed.
- The Pest browser plugin is not installed and dependencies were intentionally left unchanged; the browser coverage above was executed manually through Playwright MCP.

## Final audit

- Independent read-only audit found and closed platform API, nested product persistence, media processing, webhook contract, and domain settings gaps.
- Follow-up read-only verification confirmed the residual media lifecycle and nested product response findings are resolved.


command: find specs -maxdepth 1 -type f -name '*.md' -print | sort

type: search

query: *.md

path: specs

stdout:
specs/01-DATABASE-SCHEMA.md
specs/02-API-ROUTES.md
specs/03-ADMIN-UI.md
specs/04-STOREFRONT-UI.md
specs/05-BUSINESS-LOGIC.md
specs/06-AUTH-AND-SECURITY.md
specs/07-SEEDERS-AND-TEST-DATA.md
specs/08-PLAYWRIGHT-E2E-PLAN.md
specs/09-IMPLEMENTATION-ROADMAP.md
specs/progress.md


command: php artisan route:list --except-vendor --json > /tmp/shop_routes.json && php artisan migrate:status --no-interaction


text:
Script completed
Wall time 0.3 seconds
Output:

text:
---0---
 M boost.json
?? .playwright-mcp/
fb83f734 Complete shop platform implementation and hardening
d3efee4e Align domain models with shop schema contract
def6e641 Build self-contained multi-tenant shop
ac0e33a2 Implement bounded tenancy foundation
5047b3ea Init

text:
---1---
# 09 - Implementation Roadmap and Pest Test Specification

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

---

## 1. Technology Decisions (Final)

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

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

---

## 2. Implementation Phases (Build Order)

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

### Phase Dependency Graph

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

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

---

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

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

#### Step 1.1: Environment and Config

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

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

Create in this dependency order:

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

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

#### Step 1.3: Core Models

**Files to create:**

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

**Relationship definitions:**

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

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

#### Step 1.4: Enums

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

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

#### Step 1.5: Tenant Resolution Middleware

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

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

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

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

**Files to create:**

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

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

#### Step 1.7: Authentication

**Admin auth requirements:**

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

**Customer auth requirements:**

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

**Rate limiter registration:**
- Register rate limiters in `AppServiceProvider::boot()` for login (5 per minute per IP)

#### Step 1.8: Authorization

**Files to create:**

| Type | Name | Purpose |
|------|------|---------|
| Policy | `ProductPolicy` | Product authorization based on store role |
| Policy | `OrderPolicy` | Order authorization based on store role |
| Policy | `CollectionPolicy` | Collection authorization based on store role |
| Policy | `DiscountPolicy` | Discount authorization based on store role |
| Policy | `CustomerPolicy` | Customer authorization based on store role |
| Policy | `StorePolicy` | Store authorization based on store role |
| Policy | `PagePolicy` | Page authorization based on store role |
| Policy | `ThemePolicy` | Theme authorization based on store role |
| Policy | `FulfillmentPolicy` | Fulfillment authorization based on store role |
| Policy | `RefundPolicy` | Refund authorization based on store role |

Each policy checks user role via `store_users` pivot for the current store. Helper on User model: `roleForStore(Store $store): ?StoreUserRole`. Register policies via auto-discovery or explicit binding in `AppServiceProvider`.

**Permission Matrix:**

| Permission | Owner | Admin | Staff | Support |
|------------|:-----:|:-----:|:-----:|:-------:|
| Manage store settings | Y | Y | N | N |
| Delete store | Y | N | N | N |
| Manage staff | Y | Y | N | N |
| Manage products (CRUD) | Y | Y | Y | N |
| Delete/archive products | Y | Y | N | N |
| Manage orders | Y | Y | Y | Read-only |
| Process refunds | Y | Y | N | N |
| Create fulfillments | Y | Y | Y | N |
| Manage discounts | Y | Y | Y | N |
| Manage themes | Y | Y | N | N |
| Manage apps | Y | Y | N | N |
| View analytics | Y | Y | Y | N |
| Manage shipping/tax | Y | Y | N | N |
| View customers | Y | Y | Y | Y |
| Update customers | Y | Y | Y | N |

---

### Phase 2: Catalog (Products, Variants, Inventory, Collections, Media)

**Priority:** HIGH - storefront and orders depend on this.

#### Step 2.1: Migrations (Batch 3-5)

Create in dependency order:

1. `create_products_table` - FK: `store_id`
2. `create_product_options_table` - FK: `product_id`
3. `create_product_option_values_table` - FK: `product_option_id`
4. `create_product_variants_table` - FK: `product_id`
5. `create_variant_option_values_table` - composite PK: `variant_id` + `product_option_value_id`
6. `create_inventory_items_table` - FK: `store_id`, `variant_id`
7. `create_collections_table` - FK: `store_id`
8. `create_collection_products_table` - composite PK: `collection_id` + `product_id`
9. `create_product_media_table` - FK: `product_id`

#### Step 2.2: Models with Relationships

**Files to create:**

| Type | Name | Purpose |
|------|------|---------|
| Model (with migration, factory, seeder) | `Product` | Product entity |
| Model (with migration, factory, seeder) | `ProductOption` | Product option (e.g., Size, Color) |
| Model (with migration, factory, seeder) | `ProductOptionValue` | Option values (e.g., S, M, L) |
| Model (with migration, factory, seeder) | `ProductVariant` | Product variant (SKU-level) |
| Model (with migration, factory, seeder) | `InventoryItem` | Inventory tracking per variant |
| Model (with migration, factory, seeder) | `Collection` | Product collection/category |
| Model (with migration, factory, seeder) | `ProductMedia` | Product images and videos |

**Relationship definitions:**

| Model | Key Relationships |
|-------|-------------------|
# Implementation Progress

The self-contained multi-tenant shop is implemented across the database, commerce domain, storefront, admin, API, authentication, seed data, and delivery integrations described in specs 01–09.

## Completed

- [x] Foundation: SQLite configuration, tenant schema/models, store resolution, global tenant scope, roles, policies, and Fortify authentication.
- [x] Catalog: products, variants, options, inventory, collections, media, status transitions, search indexing, and deterministic tenant fixtures.
- [x] Storefront: home, collections, product detail, variant selection, responsive layouts, cart, cart drawer, search, static pages, customer accounts, and order history.
- [x] Checkout: session/customer carts, optimistic versions, addresses, shipping rates, taxes, discounts, payment methods, expiry, order snapshots, confirmation, and saved addresses.
- [x] Commerce operations: payment idempotency, inventory reservations, cancellation, refunds with line allocations/restocking, fulfillment guards, and webhook delivery with signatures/retries.
- [x] Admin: dashboard metrics, product and collection CRUD, inventory, orders, customers, discounts, pages, navigation, themes, settings, analytics, apps, search settings, and developer tokens/webhooks.
- [x] API/security: session and Sanctum authentication, token abilities, tenant ownership checks, rate limiting, CORS, scoped customer password reset tokens, audit logging, and error pages.
- [x] Test data: canonical `DatabaseSeeder` plus isolated `ShopSeeder` compatibility fixtures, factories, and idempotency assertions.

## Verification

- `php artisan test --compact`: 87 passing tests, 296 assertions.
- `vendor/bin/pint --dirty --format agent`: passing.
- PHP lint across application, database, routes, configuration, bootstrap, and tests: passing.
- `php artisan migrate:status --no-interaction`: all migrations applied, including tenant-scoped password reset tokens, webhook contract alignment, normalized theme settings, and store invitations.
- `php artisan view:cache --no-interaction`: passing.
- `npm run build`: passing.
- Playwright MCP browser smoke checks: storefront home, product detail, cart drawer, collections, search, cart, responsive mobile layout, admin login/dashboard/products/orders/developers/settings, Flux domain modal, and mobile admin navigation; no application console errors observed.
- The Pest browser plugin is not installed and dependencies were intentionally left unchanged; the browser coverage above was executed manually through Playwright MCP.

## Final audit

- Independent read-only audit found and closed platform API, nested product persistence, media processing, webhook contract, and domain settings gaps.
- Follow-up read-only verification confirmed the residual media lifecycle and nested product response findings are resolved.

text:
---2---
specs/01-DATABASE-SCHEMA.md
specs/02-API-ROUTES.md
specs/03-ADMIN-UI.md
specs/04-STOREFRONT-UI.md
specs/05-BUSINESS-LOGIC.md
specs/06-AUTH-AND-SECURITY.md
specs/07-SEEDERS-AND-TEST-DATA.md
specs/08-PLAYWRIGHT-E2E-PLAN.md
specs/09-IMPLEMENTATION-ROADMAP.md
specs/progress.md

text:
---3---

  Migration name .............................................. Batch / Status
  0001_01_01_000000_create_users_table ............................... [1] Ran
  0001_01_01_000001_create_cache_table ............................... [1] Ran
  0001_01_01_000002_create_jobs_table ................................ [1] Ran
  2025_08_14_170933_add_two_factor_columns_to_users_table ............ [1] Ran
  2026_08_20_000000_create_shop_schema ............................... [1] Ran
  2026_08_20_210057_add_enum_defaults_to_tenancy_tables .............. [1] Ran
  2026_08_20_210057_add_settings_json_to_store_settings_table ........ [1] Ran
  2026_08_20_210057_add_tls_mode_to_store_domains_table .............. [1] Ran
  2026_08_20_220000_add_search_and_auth_support ...................... [1] Ran
  2026_08_20_220001_add_webhook_delivery_status ...................... [1] Ran
  2026_08_20_220002_add_spec_compatibility_columns ................... [1] Ran
  2026_08_20_220003_add_discount_code_to_carts ....................... [1] Ran
  2026_08_20_223045_add_remaining_schema_contract_columns ............ [2] Ran
  2026_08_20_224526_add_line_allocations_to_refunds_table ............ [3] Ran
  2026_08_20_230144_add_remaining_spec_contract_fields ............... [4] Ran
  2026_08_20_231709_scope_customer_password_reset_tokens_by_store .... [5] Ran
  2026_08_20_234417_align_theme_settings_password_reset_and_webhook_contracts  [6] Ran
  2026_08_20_235245_remove_legacy_settings_from_themes_table ......... [7] Ran
  2026_08_21_000335_create_store_invitations_table ................... [8] Ran


exec

status: completed

input:
const r = await tools.update_plan({
  explanation: "The previous commit exists, but the persistent objective requires a fresh requirement-by-requirement audit from the current worktree.",
  plan: [
    {step: "Reconcile the current worktree and progress record with specs 01–09", status: "completed"},
    {step: "Run independent audits for schema/business logic, API/security, and UI/E2E coverage", status: "in_progress"},
    {step: "Fix all verified gaps and add corresponding Pest coverage", status: "pending"},
    {step: "Run full migration/tests/build and Playwright customer/admin review", status: "pending"},
    {step: "Update progress, commit each relevant iteration, and complete the goal only after final audit", status: "pending"}
  ]
});
text(r);


text:
Script completed
Wall time 0.0 seconds
Output:


status: completed

input:
const tasks = [
  ["Audit schema and business logic", "Audit the current /Users/wesner/Herd/shop read-only against specs/01-DATABASE-SCHEMA.md, specs/05-BUSINESS-LOGIC.md, and specs/07-SEEDERS-AND-TEST-DATA.md. Inspect actual migrations, models, services, jobs, seeders, and tests. Identify concrete missing or incorrect requirements, severity, and file paths. Do not edit files. Report actionable findings only, including anything not covered by tests."],
  ["Audit API and security", "Audit the current /Users/wesner/Herd/shop read-only against specs/02-API-ROUTES.md and specs/06-AUTH-AND-SECURITY.md. Compare every documented endpoint/middleware/rate limit/auth/tenant isolation contract to routes and implementation. Check request/response behavior and security. Do not edit files. Report concrete missing/incorrect requirements with severity and file paths."],
  ["Audit UI and E2E", "Audit the current /Users/wesner/Herd/shop read-only against specs/03-ADMIN-UI.md, specs/04-STOREFRONT-UI.md, and specs/08-PLAYWRIGHT-E2E-PLAN.md. Inspect Livewire components/views/routes and current browser behavior; optionally use Playwright MCP if available. Identify missing acceptance criteria or broken interactions. Do not edit files. Report concrete findings with severity and file paths."],
];
const out = await Promise.all(tasks.map(async ([nickname,message]) => {
  return await tools.multi_agent_v1__spawn_agent({fork_context:true, message, reasoning_effort:"high"});
}));
out.forEach((r,i)=>text(JSON.stringify({i,...r})));


type: CollabAgentToolCall

status: completed

agent_nickname: Meitner

prompt: Audit the current /Users/wesner/Herd/shop read-only against specs/03-ADMIN-UI.md, specs/04-STOREFRONT-UI.md, and specs/08-PLAYWRIGHT-E2E-PLAN.md. Inspect Livewire components/views/routes and current browser behavior; optionally use Playwright MCP if available. Identify missing acceptance criteria or broken interactions. Do not edit files. Report concrete findings with severity and file paths.

reasoning_effort: high


type: CollabAgentToolCall

status: completed

agent_nickname: Lovelace

prompt: Audit the current /Users/wesner/Herd/shop read-only against specs/02-API-ROUTES.md and specs/06-AUTH-AND-SECURITY.md. Compare every documented endpoint/middleware/rate limit/auth/tenant isolation contract to routes and implementation. Check request/response behavior and security. Do not edit files. Report concrete missing/incorrect requirements with severity and file paths.

reasoning_effort: high


type: CollabAgentToolCall

status: completed

agent_nickname: Ramanujan

prompt: Audit the current /Users/wesner/Herd/shop read-only against specs/01-DATABASE-SCHEMA.md, specs/05-BUSINESS-LOGIC.md, and specs/07-SEEDERS-AND-TEST-DATA.md. Inspect actual migrations, models, services, jobs, seeders, and tests. Identify concrete missing or incorrect requirements, severity, and file paths. Do not edit files. Report actionable findings only, including anything not covered by tests.

reasoning_effort: high


text:
Script completed
Wall time 0.5 seconds
Output:

text: {"i":0,"agent_id":"01a021ae-46e6-7403-b288-76b3738f772b","nickname":"Ramanujan"}

text: {"i":1,"agent_id":"01a021ae-4641-7d70-97fa-a13af2f3ed44","nickname":"Lovelace"}

text: {"i":2,"agent_id":"01a021ae-45c6-7540-8912-baba502a2606","nickname":"Meitner"}


text: Three independent audits are running in parallel across schema/business logic, API/security, and UI/E2E requirements. While they run, I’m doing a local route/spec diff and inspecting the highest-risk contracts so the final review is evidence-based rather than test-count-based.


status: completed

input:
const results = await Promise.all([
  tools.exec_command({cmd:"rg -n '^#### (GET|POST|PUT|PATCH|DELETE)|^\\| (GET|POST|PUT|PATCH|DELETE)' specs/02-API-ROUTES.md > /tmp/spec_api_routes.txt; sed -n '1,260p' /tmp/spec_api_routes.txt", workdir:"/Users/wesner/Herd/shop", yield_time_ms:10000, max_output_tokens:30000}),
  tools.exec_command({cmd:"rg -n '^## |^### |^#### |Acceptance|Test |Scenario|must |should ' specs/03-ADMIN-UI.md specs/04-STOREFRONT-UI.md specs/08-PLAYWRIGHT-E2E-PLAN.md | head -420", workdir:"/Users/wesner/Herd/shop", yield_time_ms:10000, max_output_tokens:30000}),
  tools.exec_command({cmd:"rg -n '^## |^### |^#### |^\\| ' specs/01-DATABASE-SCHEMA.md specs/05-BUSINESS-LOGIC.md specs/06-AUTH-AND-SECURITY.md specs/07-SEEDERS-AND-TEST-DATA.md | head -520", workdir:"/Users/wesner/Herd/shop", yield_time_ms:10000, max_output_tokens:40000}),
  tools.exec_command({cmd:"php artisan route:list --except-vendor --json", workdir:"/Users/wesner/Herd/shop", yield_time_ms:1000, max_output_tokens:30000})
]);
results.forEach((r,i)=>text(`---${i}---\n${r.output ?? JSON.stringify(r)}`));


command: rg -n '^#### (GET|POST|PUT|PATCH|DELETE)|^\| (GET|POST|PUT|PATCH|DELETE)' specs/02-API-ROUTES.md > /tmp/spec_api_routes.txt; sed -n '1,260p' /tmp/spec_api_routes.txt

stdout:
17:| GET | `/admin/login` | Admin login page | `Livewire: Admin\Auth\Login` |
18:| POST | `/admin/login` | Process admin login | Handled by Livewire action |
19:| POST | `/admin/logout` | Logout and invalidate session | Handled by Livewire action |
20:| GET | `/admin/forgot-password` | Show forgot password form | `Livewire: Admin\Auth\ForgotPassword` |
21:| POST | `/admin/forgot-password` | Send password reset link | Handled by Livewire action |
22:| GET | `/admin/reset-password/{token}` | Show reset password form | `Livewire: Admin\Auth\ResetPassword` |
23:| POST | `/admin/reset-password` | Reset password with token | Handled by Livewire action |
42:| GET | `/admin` | Dashboard with KPI tiles, orders chart, conversion funnel | `Admin\Dashboard` |
48:| GET | `/admin/products` | Product list - searchable, filterable by status, bulk actions | `Admin\Products\Index` |
49:| GET | `/admin/products/create` | Create product form | `Admin\Products\Create` |
50:| GET | `/admin/products/{product}/edit` | Edit product form with variants, media, options | `Admin\Products\Edit` |
56:| GET | `/admin/inventory` | Inventory management page | `Admin\Inventory\Index` |
62:| GET | `/admin/collections` | Collection list | `Admin\Collections\Index` |
63:| GET | `/admin/collections/create` | Create collection form | `Admin\Collections\Create` |
64:| GET | `/admin/collections/{collection}/edit` | Edit collection form | `Admin\Collections\Edit` |
70:| GET | `/admin/orders` | Order list with status filters | `Admin\Orders\Index` |
71:| GET | `/admin/orders/{order}` | Order detail with timeline, payments, fulfillments | `Admin\Orders\Show` |
77:| GET | `/admin/customers` | Customer list | `Admin\Customers\Index` |
78:| GET | `/admin/customers/{customer}` | Customer detail with order history, addresses | `Admin\Customers\Show` |
84:| GET | `/admin/discounts` | Discount list | `Admin\Discounts\Index` |
85:| GET | `/admin/discounts/create` | Create discount form with rules builder | `Admin\Discounts\Create` |
86:| GET | `/admin/discounts/{discount}/edit` | Edit discount form | `Admin\Discounts\Edit` |
92:| GET | `/admin/settings` | Store settings (tabs: General, Domains, Shipping, Taxes, Checkout, Notifications) | `Admin\Settings\Index` |
93:| GET | `/admin/settings/shipping` | Shipping zones and rates configuration | `Admin\Settings\Shipping` |
94:| GET | `/admin/settings/taxes` | Tax settings - mode, provider config, rates | `Admin\Settings\Taxes` |
100:| GET | `/admin/themes` | Theme management - cards with actions (Customize, Preview, Publish, Duplicate, Delete) | `Admin\Themes\Index` |
101:| GET | `/admin/themes/{theme}/editor` | Theme editor - left panel sections, center preview iframe, right panel settings | `Admin\Themes\Editor` |
107:| GET | `/admin/pages` | Content pages list | `Admin\Pages\Index` |
108:| GET | `/admin/pages/create` | Create content page | `Admin\Pages\Create` |
109:| GET | `/admin/pages/{page}/edit` | Edit content page | `Admin\Pages\Edit` |
115:| GET | `/admin/navigation` | Navigation menus management | `Admin\Navigation\Index` |
121:| GET | `/admin/apps` | Apps directory - list installed and available apps | `Admin\Apps\Index` |
122:| GET | `/admin/apps/{installation}` | Installed app detail - scopes, webhooks, usage | `Admin\Apps\Show` |
128:| GET | `/admin/developers` | Developer settings - API keys/tokens, webhook management | `Admin\Developers\Index` |
136:| GET | `/admin/analytics` | Analytics dashboard - sales, traffic, funnel, exports | `Admin\Analytics\Index` |
142:| GET | `/admin/search/settings` | Search settings - synonyms, stopwords, reindex | `Admin\Search\Settings` |
154:| GET | `/` | Home page | `Storefront\Home` |
155:| GET | `/collections` | All collections listing | `Storefront\Collections\Index` |
156:| GET | `/collections/{handle}` | Single collection page with product grid and filters | `Storefront\Collections\Show` |
157:| GET | `/products/{handle}` | Product page - gallery, variant selector, add-to-cart | `Storefront\Products\Show` |
158:| GET | `/cart` | Full cart page - line items, quantity controls, discount input, totals | `Storefront\Cart\Show` |
159:| GET | `/search` | Search results page with filter panel, sort dropdown, product grid | `Storefront\Search\Index` |
160:| GET | `/pages/{handle}` | Static content page (About, FAQ, etc.) | `Storefront\Pages\Show` |
168:| GET | `/account` | Customer account overview | `Storefront\Account\Dashboard` |
169:| GET | `/account/orders` | Order history list | `Storefront\Account\Orders\Index` |
170:| GET | `/account/orders/{orderNumber}` | Order detail | `Storefront\Account\Orders\Show` |
171:| GET | `/account/addresses` | Address book management | `Storefront\Account\Addresses\Index` |
177:| GET | `/account/login` | Customer login page | `Storefront\Account\Auth\Login` |
178:| GET | `/account/register` | Customer registration page | `Storefront\Account\Auth\Register` |
179:| GET | `/forgot-password` | Forgot password page | `Storefront\Account\Auth\ForgotPassword` |
180:| POST | `/forgot-password` | Send reset link | Handled by Livewire action |
181:| GET | `/reset-password/{token}` | Reset password form | `Storefront\Account\Auth\ResetPassword` |
182:| POST | `/reset-password` | Reset password | Handled by Livewire action |
192:| GET | `/checkout/{checkoutId}` | Checkout page - stepper UI (Contact -> Shipping -> Payment) | `Storefront\Checkout\Show` |
193:| GET | `/checkout/{checkoutId}/confirmation` | Order confirmation page - order number, items, totals | `Storefront\Checkout\Confirmation` |
209:#### POST /api/storefront/v1/carts
255:#### GET /api/storefront/v1/carts/{cartId}
313:#### POST /api/storefront/v1/carts/{cartId}/lines
354:#### PUT /api/storefront/v1/carts/{cartId}/lines/{lineId}
386:#### DELETE /api/storefront/v1/carts/{cartId}/lines/{lineId}
458:#### POST /api/storefront/v1/checkouts
524:#### GET /api/storefront/v1/checkouts/{checkoutId}
541:#### PUT /api/storefront/v1/checkouts/{checkoutId}/address
661:#### PUT /api/storefront/v1/checkouts/{checkoutId}/shipping-method
721:#### PUT /api/storefront/v1/checkouts/{checkoutId}/payment-method
767:#### POST /api/storefront/v1/checkouts/{checkoutId}/apply-discount
829:#### DELETE /api/storefront/v1/checkouts/{checkoutId}/discount
848:#### POST /api/storefront/v1/checkouts/{checkoutId}/pay
958:#### GET /api/storefront/v1/orders/{orderNumber}
1019:#### GET /api/storefront/v1/search
1097:#### GET /api/storefront/v1/search/suggest
1143:#### POST /api/storefront/v1/analytics/events
1222:#### POST /api/admin/v1/platform/organizations
1263:#### POST /api/admin/v1/platform/stores
1316:#### POST /api/admin/v1/stores/{storeId}/invites
1357:#### GET /api/admin/v1/stores/{storeId}/me
1399:| GET | `/api/admin/v1/stores/{storeId}/products` | `read-products` | List products with filtering and pagination | `api.admin` (60/min) |
1400:| POST | `/api/admin/v1/stores/{storeId}/products` | `write-products` | Create a new product | `api.admin` (60/min) |
1401:| GET | `/api/admin/v1/stores/{storeId}/products/{productId}` | `read-products` | Get single product with all relations | `api.admin` (60/min) |
1402:| PUT | `/api/admin/v1/stores/{storeId}/products/{productId}` | `write-products` | Update a product (partial updates supported) | `api.admin` (60/min) |
1403:| DELETE | `/api/admin/v1/stores/{storeId}/products/{productId}` | `write-products` | Archive a product (soft delete) | `api.admin` (60/min) |
1404:| POST | `/api/admin/v1/stores/{storeId}/products/{productId}/media/presign-upload` | `write-products` | Generate presigned URL for media upload | `api.admin` (60/min) |
1406:#### GET /api/admin/v1/stores/{storeId}/products
1457:#### POST /api/admin/v1/stores/{storeId}/products
1547:#### GET /api/admin/v1/stores/{storeId}/products/{productId}
1645:#### PUT /api/admin/v1/stores/{storeId}/products/{productId}
1672:#### DELETE /api/admin/v1/stores/{storeId}/products/{productId}
1694:#### POST /api/admin/v1/stores/{storeId}/products/{productId}/media/presign-upload
1742:| GET | `/api/admin/v1/stores/{storeId}/collections` | `read-collections` | List collections | `api.admin` (60/min) |
1743:| POST | `/api/admin/v1/stores/{storeId}/collections` | `write-collections` | Create a collection | `api.admin` (60/min) |
1744:| PUT | `/api/admin/v1/stores/{storeId}/collections/{collectionId}` | `write-collections` | Update a collection | `api.admin` (60/min) |
1745:| DELETE | `/api/admin/v1/stores/{storeId}/collections/{collectionId}` | `write-collections` | Delete a collection | `api.admin` (60/min) |
1747:#### GET /api/admin/v1/stores/{storeId}/collections
1789:#### POST /api/admin/v1/stores/{storeId}/collections
1825:#### PUT /api/admin/v1/stores/{storeId}/collections/{collectionId}
1840:#### DELETE /api/admin/v1/stores/{storeId}/collections/{collectionId}
1866:| GET | `/api/admin/v1/stores/{storeId}/orders` | `read-orders` | List orders with filtering and pagination | `api.admin` (60/min) |
1867:| GET | `/api/admin/v1/stores/{storeId}/orders/{orderId}` | `read-orders` | Get full order details | `api.admin` (60/min) |
1868:| POST | `/api/admin/v1/stores/{storeId}/orders/{orderId}/fulfillments` | `write-orders` | Create a fulfillment (ship items) | `api.admin` (60/min) |
1869:| POST | `/api/admin/v1/stores/{storeId}/orders/{orderId}/refunds` | `write-orders` | Create a refund (partial or full) | `api.admin` (60/min) |
1871:#### GET /api/admin/v1/stores/{storeId}/orders
1928:#### GET /api/admin/v1/stores/{storeId}/orders/{orderId}
2016:#### POST /api/admin/v1/stores/{storeId}/orders/{orderId}/fulfillments
2077:#### POST /api/admin/v1/stores/{storeId}/orders/{orderId}/refunds
2138:| GET | `/api/admin/v1/stores/{storeId}/discounts` | `read-discounts` | List discounts | `api.admin` (60/min) |
2139:| POST | `/api/admin/v1/stores/{storeId}/discounts` | `write-discounts` | Create a discount | `api.admin` (60/min) |
2140:| PUT | `/api/admin/v1/stores/{storeId}/discounts/{discountId}` | `write-discounts` | Update a discount | `api.admin` (60/min) |
2141:| DELETE | `/api/admin/v1/stores/{storeId}/discounts/{discountId}` | `write-discounts` | Delete a discount | `api.admin` (60/min) |
2143:#### GET /api/admin/v1/stores/{storeId}/discounts
2192:#### POST /api/admin/v1/stores/{storeId}/discounts
2243:#### PUT /api/admin/v1/stores/{storeId}/discounts/{discountId}
2258:#### DELETE /api/admin/v1/stores/{storeId}/discounts/{discountId}
2284:| GET | `/api/admin/v1/stores/{storeId}/shipping/zones` | `read-settings` | List shipping zones with rates | `api.admin` (60/min) |
2285:| POST | `/api/admin/v1/stores/{storeId}/shipping/zones` | `write-settings` | Create a shipping zone | `api.admin` (60/min) |
2286:| PUT | `/api/admin/v1/stores/{storeId}/shipping/zones/{zoneId}` | `write-settings` | Update a shipping zone | `api.admin` (60/min) |
2287:| POST | `/api/admin/v1/stores/{storeId}/shipping/zones/{zoneId}/rates` | `write-settings` | Add a shipping rate to a zone | `api.admin` (60/min) |
2289:#### GET /api/admin/v1/stores/{storeId}/shipping/zones
2337:#### POST /api/admin/v1/stores/{storeId}/shipping/zones
2365:#### PUT /api/admin/v1/stores/{storeId}/shipping/zones/{zoneId}
2380:#### POST /api/admin/v1/stores/{storeId}/shipping/zones/{zoneId}/rates
2420:| GET | `/api/admin/v1/stores/{storeId}/tax/settings` | `read-settings` | Get tax configuration | `api.admin` (60/min) |
2421:| PUT | `/api/admin/v1/stores/{storeId}/tax/settings` | `write-settings` | Update tax configuration | `api.admin` (60/min) |
2423:#### GET /api/admin/v1/stores/{storeId}/tax/settings
2460:#### PUT /api/admin/v1/stores/{storeId}/tax/settings
2498:| POST | `/api/admin/v1/stores/{storeId}/themes` | `write-themes` | Upload or install a new theme | `api.admin` (60/min) |
2499:| POST | `/api/admin/v1/stores/{storeId}/themes/{themeId}/publish` | `write-themes` | Publish a theme (make active) | `api.admin` (60/min) |
2500:| PUT | `/api/admin/v1/stores/{storeId}/themes/{themeId}/settings` | `write-themes` | Update theme customization settings | `api.admin` (60/min) |
2502:#### POST /api/admin/v1/stores/{storeId}/themes
2535:#### POST /api/admin/v1/stores/{storeId}/themes/{themeId}/publish
2558:#### PUT /api/admin/v1/stores/{storeId}/themes/{themeId}/settings
2604:| GET | `/api/admin/v1/stores/{storeId}/pages` | `read-content` | List content pages | `api.admin` (60/min) |
2605:| POST | `/api/admin/v1/stores/{storeId}/pages` | `write-content` | Create a content page | `api.admin` (60/min) |
2606:| PUT | `/api/admin/v1/stores/{storeId}/pages/{pageId}` | `write-content` | Update a content page | `api.admin` (60/min) |
2607:| DELETE | `/api/admin/v1/stores/{storeId}/pages/{pageId}` | `write-content` | Delete a content page | `api.admin` (60/min) |
2609:#### GET /api/admin/v1/stores/{storeId}/pages
2648:#### POST /api/admin/v1/stores/{storeId}/pages
2678:#### PUT /api/admin/v1/stores/{storeId}/pages/{pageId}
2693:#### DELETE /api/admin/v1/stores/{storeId}/pages/{pageId}
2719:| POST | `/api/admin/v1/stores/{storeId}/search/reindex` | `write-settings` | Trigger full search reindex (async) | `api.admin` (60/min) |
2720:| GET | `/api/admin/v1/stores/{storeId}/search/status` | `read-settings` | Get current search index status | `api.admin` (60/min) |
2722:#### POST /api/admin/v1/stores/{storeId}/search/reindex
2743:#### GET /api/admin/v1/stores/{storeId}/search/status
2770:| GET | `/api/admin/v1/stores/{storeId}/analytics/summary` | `read-analytics` | Get analytics summary for date range | `api.admin` (60/min) |
2771:| POST | `/api/admin/v1/stores/{storeId}/exports/orders` | `read-orders` | Queue an order export job (async) | `api.admin` (60/min) |
2772:| GET | `/api/admin/v1/stores/{storeId}/exports/{exportId}` | `read-orders` | Check export status and get download URL | `api.admin` (60/min) |
2774:#### GET /api/admin/v1/stores/{storeId}/analytics/summary
2834:#### POST /api/admin/v1/stores/{storeId}/exports/orders
2868:#### GET /api/admin/v1/stores/{storeId}/exports/{exportId}
2983:| GET | `/api/apps/v1/stores/{storeId}/products` | `read-products` | List products (same schema as admin API) |
2984:| GET | `/api/apps/v1/stores/{storeId}/orders` | `read-orders` | List orders |
2985:| GET | `/api/apps/v1/stores/{storeId}/customers` | `read-customers` | List customers |


command: rg -n '^## |^### |^#### |Acceptance|Test |Scenario|must |should ' specs/03-ADMIN-UI.md specs/04-STOREFRONT-UI.md specs/08-PLAYWRIGHT-E2E-PLAN.md | head -420

type: search

cmd: rg -n '^## |''^### |''^#### |Acceptance|Test |Scenario|must |should ' specs/03-ADMIN-UI.md specs/04-STOREFRONT-UI.md specs/08-PLAYWRIGHT-E2E-PLAN.md

query: ^## |^### |^#### |Acceptance|Test |Scenario|must |should

stdout:
specs/04-STOREFRONT-UI.md:7:## Conventions
specs/04-STOREFRONT-UI.md:21:## Currency Formatting
specs/04-STOREFRONT-UI.md:23:All monetary amounts are stored as integers in minor units (cents) and must be formatted for display according to these rules:
specs/04-STOREFRONT-UI.md:43:## 1. Theme System Architecture
specs/04-STOREFRONT-UI.md:45:### 1.1 View Organization
specs/04-STOREFRONT-UI.md:58:### 1.2 Layout Hierarchy
specs/04-STOREFRONT-UI.md:62:### 1.3 Theme Settings
specs/04-STOREFRONT-UI.md:74:### 1.4 Section-Based Architecture
specs/04-STOREFRONT-UI.md:86:### 1.5 Blade Components
specs/04-STOREFRONT-UI.md:92:## 2. Base Layout
specs/04-STOREFRONT-UI.md:94:### 2.1 Document Head
specs/04-STOREFRONT-UI.md:110:### 2.2 Skip Link
specs/04-STOREFRONT-UI.md:116:### 2.3 Announcement Bar
specs/04-STOREFRONT-UI.md:129:### 2.4 Header
specs/04-STOREFRONT-UI.md:181:### 2.5 Main Content Area
specs/04-STOREFRONT-UI.md:185:### 2.6 Footer
specs/04-STOREFRONT-UI.md:210:### 2.7 Cart Drawer (Livewire)
specs/04-STOREFRONT-UI.md:214:### 2.8 Dark Mode
specs/04-STOREFRONT-UI.md:237:## 3. Home Page (GET /)
specs/04-STOREFRONT-UI.md:247:### 3.1 Hero Banner Section
specs/04-STOREFRONT-UI.md:282:### 3.2 Featured Collections Section
specs/04-STOREFRONT-UI.md:317:### 3.3 Featured Products Section
specs/04-STOREFRONT-UI.md:332:### 3.4 Newsletter Signup Section
specs/04-STOREFRONT-UI.md:364:### 3.5 Rich Text Section
specs/04-STOREFRONT-UI.md:376:## 4. Collection Page (GET /collections/{handle})
specs/04-STOREFRONT-UI.md:380:### 4.1 Collection Header
specs/04-STOREFRONT-UI.md:389:### 4.2 Toolbar
specs/04-STOREFRONT-UI.md:424:### 4.3 Filter Sidebar
specs/04-STOREFRONT-UI.md:463:### 4.4 Product Grid
specs/04-STOREFRONT-UI.md:471:### 4.5 Product Card (Component)
specs/04-STOREFRONT-UI.md:521:### 4.6 Pagination
specs/04-STOREFRONT-UI.md:532:### 4.7 Empty State
specs/04-STOREFRONT-UI.md:555:## 5. Product Page (GET /products/{handle})
specs/04-STOREFRONT-UI.md:559:### 5.1 Layout
specs/04-STOREFRONT-UI.md:582:### 5.2 Image Gallery (Left Column)
specs/04-STOREFRONT-UI.md:621:### 5.3 Product Info (Right Column)
specs/04-STOREFRONT-UI.md:623:#### Breadcrumbs
specs/04-STOREFRONT-UI.md:627:#### Product Title
specs/04-STOREFRONT-UI.md:631:#### Price Display
specs/04-STOREFRONT-UI.md:641:#### Variant Selector
specs/04-STOREFRONT-UI.md:675:#### Stock Messaging
specs/04-STOREFRONT-UI.md:688:#### Quantity Selector
specs/04-STOREFRONT-UI.md:705:#### Add to Cart Button
specs/04-STOREFRONT-UI.md:723:#### Product Description
specs/04-STOREFRONT-UI.md:728:#### Tags
specs/04-STOREFRONT-UI.md:734:### 5.4 Accessibility Summary
specs/04-STOREFRONT-UI.md:746:## 6. Cart Drawer
specs/04-STOREFRONT-UI.md:750:### 6.1 Trigger and Animation
specs/04-STOREFRONT-UI.md:760:### 6.2 Drawer Header
specs/04-STOREFRONT-UI.md:775:### 6.3 Cart Line Items
specs/04-STOREFRONT-UI.md:801:### 6.4 Discount Code Section
specs/04-STOREFRONT-UI.md:829:### 6.5 Totals Section
specs/04-STOREFRONT-UI.md:848:### 6.6 Action Buttons
specs/04-STOREFRONT-UI.md:855:### 6.7 Empty Cart State
specs/04-STOREFRONT-UI.md:874:### 6.8 Accessibility
specs/04-STOREFRONT-UI.md:887:## 7. Full Cart Page (GET /cart)
specs/04-STOREFRONT-UI.md:893:### 7.1 Desktop Layout
specs/04-STOREFRONT-UI.md:924:### 7.2 Totals and Actions
specs/04-STOREFRONT-UI.md:932:### 7.3 Empty State
specs/04-STOREFRONT-UI.md:938:## 8. Checkout Page (GET /checkout/{checkoutId})
specs/04-STOREFRONT-UI.md:942:### 8.1 Layout
specs/04-STOREFRONT-UI.md:964:### 8.2 Checkout Steps
specs/04-STOREFRONT-UI.md:978:#### Step 1 - Contact Information
specs/04-STOREFRONT-UI.md:986:#### Step 2 - Shipping Address
specs/04-STOREFRONT-UI.md:1021:#### Step 3 - Shipping Method
specs/04-STOREFRONT-UI.md:1042:#### Step 4 - Payment Method & Pay
specs/04-STOREFRONT-UI.md:1116:### 8.3 Order Summary Sidebar (Right Column)
specs/04-STOREFRONT-UI.md:1147:### 8.4 Accessibility
specs/04-STOREFRONT-UI.md:1160:## 9. Order Confirmation (GET /checkout/{checkoutId}/confirmation)
specs/04-STOREFRONT-UI.md:1162:### 9.1 Layout
specs/04-STOREFRONT-UI.md:1198:### 9.2 Order Details
specs/04-STOREFRONT-UI.md:1207:#### Bank Transfer Instructions (shown only when `payment_method = bank_transfer`)
specs/04-STOREFRONT-UI.md:1230:### 9.3 Actions
specs/04-STOREFRONT-UI.md:1240:## 10. Customer Account Pages
specs/04-STOREFRONT-UI.md:1244:### 10.1 Login (GET /account/login)
specs/04-STOREFRONT-UI.md:1274:### 10.2 Register (GET /account/register)
specs/04-STOREFRONT-UI.md:1306:### 10.3 Account Dashboard (GET /account)
specs/04-STOREFRONT-UI.md:1332:### 10.4 Order History (GET /account/orders)
specs/04-STOREFRONT-UI.md:1342:### 10.5 Order Detail (GET /account/orders/{orderNumber})
specs/04-STOREFRONT-UI.md:1379:### 10.6 Address Book (GET /account/addresses)
specs/04-STOREFRONT-UI.md:1408:## 11. Search
specs/04-STOREFRONT-UI.md:1410:### 11.1 Search Modal
specs/04-STOREFRONT-UI.md:1448:### 11.2 Search Results Page (GET /search?q=)
specs/04-STOREFRONT-UI.md:1466:## 12. Content Pages (GET /pages/{handle})
specs/04-STOREFRONT-UI.md:1468:### 12.1 Layout
specs/04-STOREFRONT-UI.md:1479:## 13. Error Pages
specs/04-STOREFRONT-UI.md:1481:### 13.1 404 Page
specs/04-STOREFRONT-UI.md:1504:### 13.2 503 / Maintenance Page
specs/04-STOREFRONT-UI.md:1525:## 14. Responsive Breakpoints
specs/04-STOREFRONT-UI.md:1537:### Key Responsive Behaviors
specs/04-STOREFRONT-UI.md:1550:### Touch Considerations
specs/04-STOREFRONT-UI.md:1560:## 15. Accessibility Checklist
specs/04-STOREFRONT-UI.md:1562:### Global (All Pages)
specs/04-STOREFRONT-UI.md:1576:### Page-Specific Accessibility
specs/04-STOREFRONT-UI.md:1587:### Keyboard Interactions
specs/04-STOREFRONT-UI.md:1605:## 16. Component Library
specs/04-STOREFRONT-UI.md:1607:### storefront-layout
specs/04-STOREFRONT-UI.md:1616:### storefront-product-card
specs/04-STOREFRONT-UI.md:1628:### storefront-price
specs/04-STOREFRONT-UI.md:1640:### storefront-badge
specs/04-STOREFRONT-UI.md:1660:### storefront-quantity-selector
specs/04-STOREFRONT-UI.md:1672:### storefront-address-form
specs/04-STOREFRONT-UI.md:1681:### storefront-order-summary
specs/04-STOREFRONT-UI.md:1690:### storefront-breadcrumbs
specs/04-STOREFRONT-UI.md:1705:### storefront-pagination
specs/04-STOREFRONT-UI.md:1723:## 17. Livewire Component Summary
specs/04-STOREFRONT-UI.md:1742:## 18. Browser Event Communication
specs/04-STOREFRONT-UI.md:1757:## 19. SEO and Structured Data
specs/04-STOREFRONT-UI.md:1759:### Meta Tags
specs/04-STOREFRONT-UI.md:1771:### Open Graph Tags
specs/04-STOREFRONT-UI.md:1785:### JSON-LD Structured Data
specs/04-STOREFRONT-UI.md:1795:## 20. User Flow Diagrams
specs/04-STOREFRONT-UI.md:1797:### Browse to Purchase Flow
specs/04-STOREFRONT-UI.md:1826:### Account Management Flow
specs/04-STOREFRONT-UI.md:1847:### Cart Management Flow
specs/04-STOREFRONT-UI.md:1872:### Component State Diagram
specs/04-STOREFRONT-UI.md:1908:## 21. Flash / Toast Messages
specs/08-PLAYWRIGHT-E2E-PLAN.md:1:# 08 - Playwright E2E Test Plan
specs/08-PLAYWRIGHT-E2E-PLAN.md:7:## Test Suite Summary
specs/08-PLAYWRIGHT-E2E-PLAN.md:33:## Test Infrastructure Requirements
specs/08-PLAYWRIGHT-E2E-PLAN.md:35:### Framework
specs/08-PLAYWRIGHT-E2E-PLAN.md:37:- **Test runner:** Pest v4 with browser testing capabilities (Playwright under the hood)
specs/08-PLAYWRIGHT-E2E-PLAN.md:38:- **Test traits:** Each browser test file must use `TestCase` and `RefreshDatabase`
specs/08-PLAYWRIGHT-E2E-PLAN.md:42:### Pest v4 Browser Testing API Reference
specs/08-PLAYWRIGHT-E2E-PLAN.md:44:The coding agent should use these Pest v4 browser methods:
specs/08-PLAYWRIGHT-E2E-PLAN.md:58:### Environment Configuration
specs/08-PLAYWRIGHT-E2E-PLAN.md:60:The `.env.testing` file must contain the following keys:
specs/08-PLAYWRIGHT-E2E-PLAN.md:72:### Prerequisites Before Running
specs/08-PLAYWRIGHT-E2E-PLAN.md:81:## Seeded Data Dependency Table
specs/08-PLAYWRIGHT-E2E-PLAN.md:85:Each browser test file must set `protected bool $seed = true;` on the test class (or call `$this->seed(DatabaseSeeder::class)` in `beforeEach`) to ensure the database is populated after RefreshDatabase clears it. Laravel's `RefreshDatabase` trait does NOT automatically run seeders unless explicitly configured.
specs/08-PLAYWRIGHT-E2E-PLAN.md:94:| **Product #15** | Status: `draft` - must NOT appear on storefront | 3, 7 |
specs/08-PLAYWRIGHT-E2E-PLAN.md:108:## Test Execution Matrix
specs/08-PLAYWRIGHT-E2E-PLAN.md:110:Tests should be executed in the order shown below. Later suites depend on the infrastructure and pages verified by earlier suites.
specs/08-PLAYWRIGHT-E2E-PLAN.md:144:## Test Directory Structure
specs/08-PLAYWRIGHT-E2E-PLAN.md:172:## Suite 1: Smoke Tests
specs/08-PLAYWRIGHT-E2E-PLAN.md:180:### Test 1.1: Loads the storefront home page
specs/08-PLAYWRIGHT-E2E-PLAN.md:193:### Test 1.2: Loads a collection page
specs/08-PLAYWRIGHT-E2E-PLAN.md:206:### Test 1.3: Loads a product page
specs/08-PLAYWRIGHT-E2E-PLAN.md:220:### Test 1.4: Loads the cart page
specs/08-PLAYWRIGHT-E2E-PLAN.md:233:### Test 1.5: Loads the customer login page
specs/08-PLAYWRIGHT-E2E-PLAN.md:246:### Test 1.6: Loads the admin login page
specs/08-PLAYWRIGHT-E2E-PLAN.md:259:### Test 1.7: Loads the about page
specs/08-PLAYWRIGHT-E2E-PLAN.md:272:### Test 1.8: Loads the search page
specs/08-PLAYWRIGHT-E2E-PLAN.md:285:### Test 1.9: Loads all collections listing
specs/08-PLAYWRIGHT-E2E-PLAN.md:298:### Test 1.10: Has no errors on critical pages (batch)
specs/08-PLAYWRIGHT-E2E-PLAN.md:312:## Suite 2: Admin Authentication
specs/08-PLAYWRIGHT-E2E-PLAN.md:318:### Authentication Flow
specs/08-PLAYWRIGHT-E2E-PLAN.md:338:### Test 2.1: Can log in as admin
specs/08-PLAYWRIGHT-E2E-PLAN.md:354:### Test 2.2: Shows error for invalid credentials
specs/08-PLAYWRIGHT-E2E-PLAN.md:370:### Test 2.3: Shows error for empty email
specs/08-PLAYWRIGHT-E2E-PLAN.md:385:### Test 2.4: Shows error for empty password
specs/08-PLAYWRIGHT-E2E-PLAN.md:400:### Test 2.5: Redirects unauthenticated users to login from dashboard
specs/08-PLAYWRIGHT-E2E-PLAN.md:413:### Test 2.6: Redirects unauthenticated users to login from products
specs/08-PLAYWRIGHT-E2E-PLAN.md:426:### Test 2.7: Can log out
specs/08-PLAYWRIGHT-E2E-PLAN.md:444:### Test 2.8: Can navigate through admin sidebar sections
specs/08-PLAYWRIGHT-E2E-PLAN.md:470:### Test 2.9: Can navigate to analytics from sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:487:### Test 2.10: Can navigate to themes from sidebar
specs/08-PLAYWRIGHT-E2E-PLAN.md:502:**Login Helper Pattern:** Tests 2.7-2.10 require the admin to be logged in first. Each test should perform the full login sequence (visit login page, fill credentials, click sign in, assert dashboard) before proceeding. This ensures test independence.
specs/08-PLAYWRIGHT-E2E-PLAN.md:508:## Suite 3: Admin Product Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:514:### Product Lifecycle States
specs/08-PLAYWRIGHT-E2E-PLAN.md:528:### Test 3.1: Shows the product list with seeded products
specs/08-PLAYWRIGHT-E2E-PLAN.md:546:### Test 3.2: Can create a new product
specs/08-PLAYWRIGHT-E2E-PLAN.md:555:5. Enter title: `Test Product Created by E2E`
specs/08-PLAYWRIGHT-E2E-PLAN.md:557:7. Enter vendor: `Test Vendor`
specs/08-PLAYWRIGHT-E2E-PLAN.md:567:- After step 13: page displays "Test Product Created by E2E" in the list
specs/08-PLAYWRIGHT-E2E-PLAN.md:571:### Test 3.3: Can edit an existing product title
specs/08-PLAYWRIGHT-E2E-PLAN.md:591:### Test 3.4: Can archive a product
specs/08-PLAYWRIGHT-E2E-PLAN.md:615:- After step 15: with default "Active" filter, the archived product should not appear in the list
specs/08-PLAYWRIGHT-E2E-PLAN.md:619:### Test 3.5: Shows draft products only in admin, not storefront
specs/08-PLAYWRIGHT-E2E-PLAN.md:640:### Test 3.6: Can search products in admin
specs/08-PLAYWRIGHT-E2E-PLAN.md:656:### Test 3.7: Can filter products by status in admin
specs/08-PLAYWRIGHT-E2E-PLAN.md:676:## Suite 4: Admin Order Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:682:### Order State Transitions (via admin actions)
specs/08-PLAYWRIGHT-E2E-PLAN.md:700:### Test 4.1: Shows the order list with seeded orders
specs/08-PLAYWRIGHT-E2E-PLAN.md:715:### Test 4.2: Can filter orders by status
specs/08-PLAYWRIGHT-E2E-PLAN.md:735:### Test 4.3: Shows order detail with line items and totals
specs/08-PLAYWRIGHT-E2E-PLAN.md:755:### Test 4.4: Shows order timeline events
specs/08-PLAYWRIGHT-E2E-PLAN.md:772:### Test 4.5: Can create a fulfillment
specs/08-PLAYWRIGHT-E2E-PLAN.md:793:### Test 4.6: Can process a refund
specs/08-PLAYWRIGHT-E2E-PLAN.md:814:### Test 4.7: Shows customer information in order detail
specs/08-PLAYWRIGHT-E2E-PLAN.md:830:### Test 4.8: Can confirm bank transfer payment
specs/08-PLAYWRIGHT-E2E-PLAN.md:851:### Test 4.9: Shows fulfillment guard for unpaid order
specs/08-PLAYWRIGHT-E2E-PLAN.md:868:### Test 4.10: Can mark fulfillment as shipped
specs/08-PLAYWRIGHT-E2E-PLAN.md:886:### Test 4.11: Can mark fulfillment as delivered
specs/08-PLAYWRIGHT-E2E-PLAN.md:906:## Suite 5: Admin Discount Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:912:### Discount Types
specs/08-PLAYWRIGHT-E2E-PLAN.md:922:### Test 5.1: Shows seeded discount codes
specs/08-PLAYWRIGHT-E2E-PLAN.md:939:### Test 5.2: Can create a new percentage discount code
specs/08-PLAYWRIGHT-E2E-PLAN.md:962:### Test 5.3: Can create a fixed amount discount code
specs/08-PLAYWRIGHT-E2E-PLAN.md:982:### Test 5.4: Can create a free shipping discount code
specs/08-PLAYWRIGHT-E2E-PLAN.md:1001:### Test 5.5: Can edit a discount
specs/08-PLAYWRIGHT-E2E-PLAN.md:1019:### Test 5.6: Shows discount status indicators
specs/08-PLAYWRIGHT-E2E-PLAN.md:1037:## Suite 6: Admin Settings
specs/08-PLAYWRIGHT-E2E-PLAN.md:1043:### Settings Page Structure
specs/08-PLAYWRIGHT-E2E-PLAN.md:1056:> **Note:** Domains tab is covered by Test 6.7. Checkout and Notifications tabs follow the same tabbed navigation pattern; E2E coverage for these tabs should be added when their functionality is implemented.
specs/08-PLAYWRIGHT-E2E-PLAN.md:1060:### Test 6.1: Can view store settings
specs/08-PLAYWRIGHT-E2E-PLAN.md:1076:### Test 6.2: Can update store name
specs/08-PLAYWRIGHT-E2E-PLAN.md:1094:### Test 6.3: Can view shipping zones
specs/08-PLAYWRIGHT-E2E-PLAN.md:1112:### Test 6.4: Can add a new shipping rate to existing zone
specs/08-PLAYWRIGHT-E2E-PLAN.md:1133:### Test 6.5: Can view tax settings
specs/08-PLAYWRIGHT-E2E-PLAN.md:1149:### Test 6.6: Can update tax inclusion setting
specs/08-PLAYWRIGHT-E2E-PLAN.md:1167:### Test 6.7: Can view domain settings
specs/08-PLAYWRIGHT-E2E-PLAN.md:1185:## Suite 7: Storefront Browsing
specs/08-PLAYWRIGHT-E2E-PLAN.md:1191:### Storefront Page Map
specs/08-PLAYWRIGHT-E2E-PLAN.md:1207:### Test 7.1: Shows featured products on home page
specs/08-PLAYWRIGHT-E2E-PLAN.md:1222:### Test 7.2: Shows collection with product grid
specs/08-PLAYWRIGHT-E2E-PLAN.md:1236:### Test 7.3: Can navigate from collection to product
specs/08-PLAYWRIGHT-E2E-PLAN.md:1252:### Test 7.4: Shows product detail with variant options
specs/08-PLAYWRIGHT-E2E-PLAN.md:1268:### Test 7.5: Shows size and color option values
specs/08-PLAYWRIGHT-E2E-PLAN.md:1282:### Test 7.6: Updates price when variant changes on product with compare-at pricing
specs/08-PLAYWRIGHT-E2E-PLAN.md:1298:### Test 7.7: Shows search results for valid query
specs/08-PLAYWRIGHT-E2E-PLAN.md:1311:### Test 7.8: Shows no results message for invalid query
specs/08-PLAYWRIGHT-E2E-PLAN.md:1324:### Test 7.9: Does not show draft products on storefront collections
specs/08-PLAYWRIGHT-E2E-PLAN.md:1332:- Product #15 (draft) must NOT appear anywhere in the listing
specs/08-PLAYWRIGHT-E2E-PLAN.md:1337:### Test 7.10: Does not show draft products in search results
specs/08-PLAYWRIGHT-E2E-PLAN.md:1350:### Test 7.11: Shows out of stock messaging for deny-policy product
specs/08-PLAYWRIGHT-E2E-PLAN.md:1364:### Test 7.12: Shows backorder messaging for continue-policy product
specs/08-PLAYWRIGHT-E2E-PLAN.md:1378:### Test 7.13: Shows new arrivals collection
specs/08-PLAYWRIGHT-E2E-PLAN.md:1391:### Test 7.14: Shows static about page
specs/08-PLAYWRIGHT-E2E-PLAN.md:1404:### Test 7.15: Navigates between pages using the main navigation
specs/08-PLAYWRIGHT-E2E-PLAN.md:1421:## Suite 8: Cart Flow
specs/08-PLAYWRIGHT-E2E-PLAN.md:1427:### Cart Interaction Flow
specs/08-PLAYWRIGHT-E2E-PLAN.md:1443:### Discount Code Validation Matrix
specs/08-PLAYWRIGHT-E2E-PLAN.md:1456:### Test 8.1: Can add product to cart
specs/08-PLAYWRIGHT-E2E-PLAN.md:1473:### Test 8.2: Can view cart with added item
specs/08-PLAYWRIGHT-E2E-PLAN.md:1492:### Test 8.3: Can update quantity in cart
specs/08-PLAYWRIGHT-E2E-PLAN.md:1513:### Test 8.4: Can remove item from cart
specs/08-PLAYWRIGHT-E2E-PLAN.md:1532:### Test 8.5: Can add multiple different products
specs/08-PLAYWRIGHT-E2E-PLAN.md:1552:### Test 8.6: Can apply valid discount code WELCOME10
specs/08-PLAYWRIGHT-E2E-PLAN.md:1574:### Test 8.7: Shows error for invalid discount code
specs/08-PLAYWRIGHT-E2E-PLAN.md:1593:### Test 8.8: Shows error for expired discount code
specs/08-PLAYWRIGHT-E2E-PLAN.md:1612:### Test 8.9: Shows error for maxed out discount code
specs/08-PLAYWRIGHT-E2E-PLAN.md:1631:### Test 8.10: Can apply free shipping discount
specs/08-PLAYWRIGHT-E2E-PLAN.md:1651:### Test 8.11: Can apply FLAT5 discount for fixed amount off
specs/08-PLAYWRIGHT-E2E-PLAN.md:1671:### Test 8.12: Shows subtotal and total in cart
specs/08-PLAYWRIGHT-E2E-PLAN.md:1691:## Suite 9: Checkout Flow
specs/08-PLAYWRIGHT-E2E-PLAN.md:1697:### Checkout Step Flow
specs/08-PLAYWRIGHT-E2E-PLAN.md:1720:### Checkout Step Detail
specs/08-PLAYWRIGHT-E2E-PLAN.md:1730:### Totals Calculation Reference
specs/08-PLAYWRIGHT-E2E-PLAN.md:1752:### Test 9.1: Completes full checkout with credit card
specs/08-PLAYWRIGHT-E2E-PLAN.md:1777:21. Enter cardholder name: `Test Buyer`
specs/08-PLAYWRIGHT-E2E-PLAN.md:1790:### Test 9.2: Shows shipping methods based on German address
specs/08-PLAYWRIGHT-E2E-PLAN.md:1818:### Test 9.3: Shows international shipping methods for non-DE address
specs/08-PLAYWRIGHT-E2E-PLAN.md:1845:### Test 9.4: Applies discount during checkout
specs/08-PLAYWRIGHT-E2E-PLAN.md:1879:### Test 9.5: Validates required contact email
specs/08-PLAYWRIGHT-E2E-PLAN.md:1898:### Test 9.6: Validates required shipping address fields
specs/08-PLAYWRIGHT-E2E-PLAN.md:1919:### Test 9.7: Validates invalid postal code format
specs/08-PLAYWRIGHT-E2E-PLAN.md:1946:### Test 9.8: Prevents checkout with empty cart
specs/08-PLAYWRIGHT-E2E-PLAN.md:1960:### Test 9.9: Completes checkout with PayPal
specs/08-PLAYWRIGHT-E2E-PLAN.md:1982:### Test 9.10: Completes checkout with bank transfer
specs/08-PLAYWRIGHT-E2E-PLAN.md:2005:### Test 9.11: Shows error for declined credit card (magic number)
specs/08-PLAYWRIGHT-E2E-PLAN.md:2019:10. Enter cardholder name: `Test Buyer`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2031:### Test 9.12: Shows error for insufficient funds (magic number)
specs/08-PLAYWRIGHT-E2E-PLAN.md:2044:9. Enter cardholder name: `Test Buyer`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2056:### Test 9.13: Switches between payment method forms
specs/08-PLAYWRIGHT-E2E-PLAN.md:2078:## Suite 10: Customer Account
specs/08-PLAYWRIGHT-E2E-PLAN.md:2084:### Customer Account Flow
specs/08-PLAYWRIGHT-E2E-PLAN.md:2103:### Test 10.1: Can register a new customer
specs/08-PLAYWRIGHT-E2E-PLAN.md:2121:### Test 10.2: Shows validation errors for duplicate email registration
specs/08-PLAYWRIGHT-E2E-PLAN.md:2139:### Test 10.3: Shows validation errors for mismatched passwords
specs/08-PLAYWRIGHT-E2E-PLAN.md:2145:2. Enter name: `Test Customer`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2157:### Test 10.4: Can log in as existing customer
specs/08-PLAYWRIGHT-E2E-PLAN.md:2174:### Test 10.5: Shows error for invalid customer credentials
specs/08-PLAYWRIGHT-E2E-PLAN.md:2190:### Test 10.6: Redirects unauthenticated customers to login
specs/08-PLAYWRIGHT-E2E-PLAN.md:2203:### Test 10.7: Shows order history for logged-in customer
specs/08-PLAYWRIGHT-E2E-PLAN.md:2222:### Test 10.8: Shows order detail for customer order
specs/08-PLAYWRIGHT-E2E-PLAN.md:2240:### Test 10.9: Can view addresses
specs/08-PLAYWRIGHT-E2E-PLAN.md:2255:### Test 10.10: Can add a new address
specs/08-PLAYWRIGHT-E2E-PLAN.md:2280:### Test 10.11: Can edit an existing address
specs/08-PLAYWRIGHT-E2E-PLAN.md:2299:### Test 10.12: Can log out
specs/08-PLAYWRIGHT-E2E-PLAN.md:2319:## Suite 11: Inventory Enforcement
specs/08-PLAYWRIGHT-E2E-PLAN.md:2325:### Inventory Policy Decision Matrix
specs/08-PLAYWRIGHT-E2E-PLAN.md:2336:### Test 11.1: Blocks add-to-cart for out-of-stock deny-policy product
specs/08-PLAYWRIGHT-E2E-PLAN.md:2350:### Test 11.2: Allows add-to-cart for out-of-stock continue-policy product
specs/08-PLAYWRIGHT-E2E-PLAN.md:2368:### Test 11.3: Shows correct stock status for in-stock product
specs/08-PLAYWRIGHT-E2E-PLAN.md:2383:### Test 11.4: Prevents adding more than available stock for deny-policy product
specs/08-PLAYWRIGHT-E2E-PLAN.md:2403:## Suite 12: Tenant Isolation
specs/08-PLAYWRIGHT-E2E-PLAN.md:2409:### Isolation Requirements
specs/08-PLAYWRIGHT-E2E-PLAN.md:2428:Dashed X lines indicate these must NEVER cross. No data from Store 2 should ever appear when browsing Store 1, and vice versa.
specs/08-PLAYWRIGHT-E2E-PLAN.md:2432:### Test 12.1: Store 1 only shows Store 1 products
specs/08-PLAYWRIGHT-E2E-PLAN.md:2447:### Test 12.2: Store 1 collections only contain Store 1 products
specs/08-PLAYWRIGHT-E2E-PLAN.md:2461:### Test 12.3: Admin cannot access other store data
specs/08-PLAYWRIGHT-E2E-PLAN.md:2481:### Test 12.4: Search only returns current store products
specs/08-PLAYWRIGHT-E2E-PLAN.md:2495:### Test 12.5: Customer accounts are scoped to their store
specs/08-PLAYWRIGHT-E2E-PLAN.md:2514:## Suite 13: Responsive / Mobile
specs/08-PLAYWRIGHT-E2E-PLAN.md:2520:### Viewport Definitions
specs/08-PLAYWRIGHT-E2E-PLAN.md:2529:### Test 13.1: Storefront home works on mobile viewport
specs/08-PLAYWRIGHT-E2E-PLAN.md:2546:### Test 13.2: Product page stacks layout on mobile
specs/08-PLAYWRIGHT-E2E-PLAN.md:2561:### Test 13.3: Can add to cart on mobile
specs/08-PLAYWRIGHT-E2E-PLAN.md:2578:### Test 13.4: Cart page works on mobile
specs/08-PLAYWRIGHT-E2E-PLAN.md:2597:### Test 13.5: Checkout flow works on mobile
specs/08-PLAYWRIGHT-E2E-PLAN.md:2626:### Test 13.6: Admin login works on tablet viewport
specs/08-PLAYWRIGHT-E2E-PLAN.md:2643:### Test 13.7: Admin sidebar navigation works on tablet
specs/08-PLAYWRIGHT-E2E-PLAN.md:2662:### Test 13.8: Collection page works on mobile with filters
specs/08-PLAYWRIGHT-E2E-PLAN.md:2680:## Suite 14: Accessibility
specs/08-PLAYWRIGHT-E2E-PLAN.md:2686:### Accessibility Requirements Checklist
specs/08-PLAYWRIGHT-E2E-PLAN.md:2700:### Test 14.1: Home page has no JavaScript errors or console warnings
specs/08-PLAYWRIGHT-E2E-PLAN.md:2713:### Test 14.2: Home page has proper heading hierarchy
specs/08-PLAYWRIGHT-E2E-PLAN.md:2728:### Test 14.3: Product page has proper ARIA labels for variant selector
specs/08-PLAYWRIGHT-E2E-PLAN.md:2742:### Test 14.4: Product page images have alt text
specs/08-PLAYWRIGHT-E2E-PLAN.md:2755:### Test 14.5: Customer login form has accessible labels
specs/08-PLAYWRIGHT-E2E-PLAN.md:2769:### Test 14.6: Admin login form has accessible labels
specs/08-PLAYWRIGHT-E2E-PLAN.md:2783:### Test 14.7: Checkout form has accessible labels
specs/08-PLAYWRIGHT-E2E-PLAN.md:2802:### Test 14.8: Checkout validation errors are accessible
specs/08-PLAYWRIGHT-E2E-PLAN.md:2822:### Test 14.9: Can navigate storefront with keyboard only
specs/08-PLAYWRIGHT-E2E-PLAN.md:2838:### Test 14.10: Cart page has no console errors or warnings
specs/08-PLAYWRIGHT-E2E-PLAN.md:2851:### Test 14.11: Search page has proper form labels
specs/08-PLAYWRIGHT-E2E-PLAN.md:2866:## Suite 15: Admin Collections Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:2874:### Test 15.1: Shows the collection list with seeded collections
specs/08-PLAYWRIGHT-E2E-PLAN.md:2890:### Test 15.2: Can create a new collection
specs/08-PLAYWRIGHT-E2E-PLAN.md:2899:5. Enter title: `E2E Test Collection`
specs/08-PLAYWRIGHT-E2E-PLAN.md:2906:- After step 8: page displays "E2E Test Collection" in the list
specs/08-PLAYWRIGHT-E2E-PLAN.md:2910:### Test 15.3: Can edit a collection
specs/08-PLAYWRIGHT-E2E-PLAN.md:2930:## Suite 16: Admin Customer Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:2938:### Test 16.1: Shows the customer list
specs/08-PLAYWRIGHT-E2E-PLAN.md:2954:### Test 16.2: Shows customer detail with order history
specs/08-PLAYWRIGHT-E2E-PLAN.md:2972:### Test 16.3: Shows customer addresses
specs/08-PLAYWRIGHT-E2E-PLAN.md:2990:## Suite 17: Admin Pages Management
specs/08-PLAYWRIGHT-E2E-PLAN.md:2998:### Test 17.1: Shows the pages list
specs/08-PLAYWRIGHT-E2E-PLAN.md:3013:### Test 17.2: Can create a new page
specs/08-PLAYWRIGHT-E2E-PLAN.md:3032:### Test 17.3: Can edit an existing page
specs/08-PLAYWRIGHT-E2E-PLAN.md:3052:## Suite 18: Admin Analytics Dashboard
specs/08-PLAYWRIGHT-E2E-PLAN.md:3058:### Analytics Dashboard Sections
specs/08-PLAYWRIGHT-E2E-PLAN.md:3060:The dashboard at `/admin/analytics` should display:
specs/08-PLAYWRIGHT-E2E-PLAN.md:3070:### Test 18.1: Shows the analytics dashboard
specs/08-PLAYWRIGHT-E2E-PLAN.md:3085:### Test 18.2: Shows sales data
specs/08-PLAYWRIGHT-E2E-PLAN.md:3101:### Test 18.3: Shows conversion funnel data
specs/08-PLAYWRIGHT-E2E-PLAN.md:3118:## Test Count Summary
specs/08-PLAYWRIGHT-E2E-PLAN.md:3144:## Test Execution Commands
specs/08-PLAYWRIGHT-E2E-PLAN.md:3157:## Implementation Notes for the Coding Agent
specs/08-PLAYWRIGHT-E2E-PLAN.md:3159:1. **Test independence:** Every test must be independently runnable. Use `RefreshDatabase` to ensure clean state. The login helper sequence (visit login, fill credentials, click sign in, assert dashboard) must be repeated per test that requires admin/customer auth.
specs/08-PLAYWRIGHT-E2E-PLAN.md:3169:6. **Viewport testing (Suite 13):** The coding agent should use Pest v4 / Playwright's viewport configuration to set browser dimensions. The exact API for setting viewport in Pest v4 browser tests should be looked up via documentation search.
specs/08-PLAYWRIGHT-E2E-PLAN.md:3171:7. **Form field names:** The field names used in `fill()` calls (e.g., "email", "password", "first_name", "variants.0.price") are logical names. The coding agent must use the actual HTML field names/labels as rendered by the Livewire components.
specs/08-PLAYWRIGHT-E2E-PLAN.md:3173:8. **Product handles for inventory tests:** Product #17 and #18 handles are placeholders. The coding agent should use the actual handles from the seeder data or create products with known handles in the test setup.
specs/03-ADMIN-UI.md:11:## 1. Admin Layout Shell
specs/03-ADMIN-UI.md:15:### 1.1 Route Prefix
specs/03-ADMIN-UI.md:19:### 1.2 Sidebar Navigation
specs/03-ADMIN-UI.md:25:#### Component Requirements
specs/03-ADMIN-UI.md:36:#### Wireframe
specs/03-ADMIN-UI.md:77:#### Navigation Structure
specs/03-ADMIN-UI.md:103:#### Flux Component Mapping
specs/03-ADMIN-UI.md:111:#### Responsive Behavior
specs/03-ADMIN-UI.md:116:### 1.3 Top Bar
specs/03-ADMIN-UI.md:122:#### Component Requirements
specs/03-ADMIN-UI.md:134:#### Wireframe
specs/03-ADMIN-UI.md:153:#### Interaction Flows
specs/03-ADMIN-UI.md:159:#### Flux Component Mapping
specs/03-ADMIN-UI.md:171:### 1.4 Main Content Area
specs/03-ADMIN-UI.md:179:### 1.5 Toast Notifications
specs/03-ADMIN-UI.md:194:### 1.6 Dark Mode
specs/03-ADMIN-UI.md:196:The admin supports dark mode via Tailwind's `dark:` variant. The mode follows the user's system preference by default. A toggle can be added in the profile dropdown later. All components and custom markup must include dark mode variants.
specs/03-ADMIN-UI.md:202:## 2. Dashboard
specs/03-ADMIN-UI.md:210:### Component Requirements
specs/03-ADMIN-UI.md:242:### Wireframe
specs/03-ADMIN-UI.md:271:### Layout Description
specs/03-ADMIN-UI.md:277:### KPI Tiles Row
specs/03-ADMIN-UI.md:288:### Orders Chart
specs/03-ADMIN-UI.md:296:### Top Products Table
specs/03-ADMIN-UI.md:304:### Conversion Funnel
specs/03-ADMIN-UI.md:313:### Flux Component Mapping
specs/03-ADMIN-UI.md:326:### View States
specs/03-ADMIN-UI.md:337:## 3. Products List
specs/03-ADMIN-UI.md:345:### Component Requirements
specs/03-ADMIN-UI.md:374:### Wireframe
specs/03-ADMIN-UI.md:396:### Table Column Definitions
specs/03-ADMIN-UI.md:409:### Bulk Action Bar
specs/03-ADMIN-UI.md:417:### Empty State
specs/03-ADMIN-UI.md:425:### Delete Confirmation Modal
specs/03-ADMIN-UI.md:436:### Flux Component Mapping
specs/03-ADMIN-UI.md:453:### View States
specs/03-ADMIN-UI.md:464:## 4. Product Create/Edit
specs/03-ADMIN-UI.md:472:### Component Requirements
specs/03-ADMIN-UI.md:511:### Validation Rules
specs/03-ADMIN-UI.md:527:### Two-Column Layout Wireframe
specs/03-ADMIN-UI.md:579:### Left Column Sections
specs/03-ADMIN-UI.md:581:#### Title Input
specs/03-ADMIN-UI.md:586:#### Description
specs/03-ADMIN-UI.md:591:#### Media Section
specs/03-ADMIN-UI.md:603:#### Variants Section
specs/03-ADMIN-UI.md:626:#### SEO Section
specs/03-ADMIN-UI.md:631:### Right Column Sections
specs/03-ADMIN-UI.md:633:#### Status Card
specs/03-ADMIN-UI.md:637:#### Publishing Card
specs/03-ADMIN-UI.md:641:#### Product Organization Card
specs/03-ADMIN-UI.md:646:#### Collections Card
specs/03-ADMIN-UI.md:651:### Sticky Save Bar
specs/03-ADMIN-UI.md:658:### Delete Confirmation Modal (Edit Only)
specs/03-ADMIN-UI.md:669:### Flux Component Mapping
specs/03-ADMIN-UI.md:688:### View States
specs/03-ADMIN-UI.md:700:## 5. Collections List and Edit
specs/03-ADMIN-UI.md:702:### 5.1 Collections List
specs/03-ADMIN-UI.md:710:#### Component Requirements
specs/03-ADMIN-UI.md:726:#### Layout
specs/03-ADMIN-UI.md:733:#### Table Columns
specs/03-ADMIN-UI.md:744:### 5.2 Collection Edit/Create
specs/03-ADMIN-UI.md:752:#### Component Requirements
specs/03-ADMIN-UI.md:776:#### Layout Wireframe
specs/03-ADMIN-UI.md:819:## 6. Inventory Management
specs/03-ADMIN-UI.md:827:### Component Requirements
specs/03-ADMIN-UI.md:838:### Wireframe
specs/03-ADMIN-UI.md:854:### Layout
specs/03-ADMIN-UI.md:862:## 7. Orders List
specs/03-ADMIN-UI.md:870:### Component Requirements
specs/03-ADMIN-UI.md:889:### Wireframe
specs/03-ADMIN-UI.md:908:### Filter Tabs
specs/03-ADMIN-UI.md:912:### Table Column Definitions
specs/03-ADMIN-UI.md:925:### Flux Component Mapping
specs/03-ADMIN-UI.md:936:## 8. Order Detail
specs/03-ADMIN-UI.md:944:### Component Requirements
specs/03-ADMIN-UI.md:968:### Two-Column Layout Wireframe
specs/03-ADMIN-UI.md:1007:### Left Column Sections
specs/03-ADMIN-UI.md:1009:#### Order Heading
specs/03-ADMIN-UI.md:1015:#### Action Buttons
specs/03-ADMIN-UI.md:1021:#### Fulfillment Guard
specs/03-ADMIN-UI.md:1025:> **Cannot create fulfillment.** Payment must be confirmed before items can be fulfilled. Current financial status: *{financial_status}*.
specs/03-ADMIN-UI.md:1029:#### Timeline
specs/03-ADMIN-UI.md:1034:#### Order Lines Table
specs/03-ADMIN-UI.md:1044:#### Order Summary
specs/03-ADMIN-UI.md:1049:#### Payment Details
specs/03-ADMIN-UI.md:1057:#### Fulfillment Cards