Script completed
Wall time 0.1 seconds
Output:

/Users/fabianwesner/Herd/shop
## 2026-07-12-codex-gpt-5-6-sol-ultra
783fdf45 (HEAD -> 2026-07-12-codex-gpt-5-6-sol-ultra) inital
fc0e4141 (origin/main, origin/HEAD, main) Revert "Add sonar-project.properties" - exclusions configured in SonarCloud UI instead
a29d6a2d Add sonar-project.properties to suppress S5332 false positives in tests
5cd42872 (origin/codex-spark, opencode-glm-5, codex-spark) Initial
  2026-03-18-claude-code-team
  2026-03-20-claude-code-team
  2026-04-12-claude-code-team
  2026-04-13-opencode-minimax-2-5
  2026-04-16-claude-code-opus-4-7
  2026-04-16-claude-code-opus-4-7-xhigh
  2026-04-25-claude-and-codex
  2026-04-25-codex-gpt-5-5
  2026-05-03-codex-5-5-goal
  2026-05-04-codex-5-5-goal
  2026-05-15-qwen-3-6-plus-free
  2026-05-30-claude-code-team-4-8-xhigh
  2026-06-05-claude-code-deepseek-v4-pro
  2026-06-09-claude-code-fable-5
  2026-07-11-codex-gpt-5-6-sol-xhigh
* 2026-07-12-codex-gpt-5-6-sol-ultra
  agent-claude-team
  claude-code-ralph
  claude-code-team-2
  claude-code-team-2026-03-17
  claude-code-team-3
  claude-code-team-5
  claude-subagents
  claue-code-team-4
  codex
  codex-2026-03-17
  codex-spark
  codex-subagents-2
  main
  opencode-glm-5
  remotes/origin/2026-03-18-claude-code-team
  remotes/origin/2026-03-20-claude-code-team
  remotes/origin/2026-04-12-claude-code-team
  remotes/origin/2026-04-16-claude-code-opus-4-7
  remotes/origin/2026-04-16-claude-code-opus-4-7-strict-prompt
  remotes/origin/2026-04-16-claude-code-opus-4-7-xhigh
  remotes/origin/2026-04-25-codex-gpt-5-5
  remotes/origin/2026-05-03-codex-5-5-goal
  remotes/origin/2026-05-04-codex-5-5-goal
  remotes/origin/2026-05-30-claude-code-team-4-8-xhigh
  remotes/origin/2026-06-09-claude-code-fable-5
  remotes/origin/2026-07-11-codex-gpt-5-6-sol-xhigh
  remotes/origin/HEAD -> origin/main
  remotes/origin/claude-code-team
  remotes/origin/claude-code-team-2
  remotes/origin/claude-code-team-3
  remotes/origin/claude-code-team-5
  remotes/origin/claude-subagents
  remotes/origin/claue-code-team-4
  remotes/origin/codex-spark
  remotes/origin/codex-subagents
  remotes/origin/codex-subagents-2
  remotes/origin/main
composer.json
CLAUDE.md
routes/web.php
routes/console.php
routes/settings.php
AGENTS.md
package.json
package-lock.json
public/favicon.svg
public/robots.txt
public/apple-touch-icon.png
public/index.php
public/favicon.ico
artisan
pint.json
README.md
storage/logs/.gitignore
phpunit.xml
composer.lock
specs/01-DATABASE-SCHEMA.md
specs/06-AUTH-AND-SECURITY.md
specs/02-API-ROUTES.md
specs/09-IMPLEMENTATION-ROADMAP.md
specs/07-SEEDERS-AND-TEST-DATA.md
specs/03-ADMIN-UI.md
specs/05-BUSINESS-LOGIC.md
specs/04-STOREFRONT-UI.md
specs/08-PLAYWRIGHT-E2E-PLAN.md
config/filesystems.php
config/logging.php
config/queue.php
config/session.php
config/cache.php
config/database.php
config/services.php
config/mail.php
config/app.php
config/auth.php
config/fortify.php
vite.config.js
bootstrap/providers.php
tests/TestCase.php
tests/Pest.php
tests/Feature/DashboardTest.php
storage/app/private/.gitignore
storage/app/.gitignore
tests/Feature/Auth/PasswordResetTest.php
tests/Feature/Auth/AuthenticationTest.php
tests/Feature/Auth/RegistrationTest.php
tests/Feature/Auth/TwoFactorChallengeTest.php
tests/Feature/Auth/EmailVerificationTest.php
tests/Feature/Auth/PasswordConfirmationTest.php
resources/views/partials/settings-heading.blade.php
tests/Feature/ExampleTest.php
resources/views/partials/head.blade.php
bootstrap/app.php
tests/Feature/Settings/ProfileUpdateTest.php
tests/Feature/Settings/PasswordUpdateTest.php
tests/Feature/Settings/TwoFactorAuthenticationTest.php
database/factories/UserFactory.php
resources/views/layouts/app.blade.php
storage/app/public/.gitignore
storage/framework/views/.gitignore
tests/Unit/ExampleTest.php
database/seeders/DatabaseSeeder.php
resources/views/layouts/auth/split.blade.php
resources/views/layouts/auth/simple.blade.php
resources/views/layouts/auth/card.blade.php
resources/js/app.js
resources/views/layouts/app/sidebar.blade.php
resources/views/layouts/app/header.blade.php
database/migrations/2025_08_14_170933_add_two_factor_columns_to_users_table.php
database/migrations/0001_01_01_000002_create_jobs_table.php
database/migrations/0001_01_01_000001_create_cache_table.php
database/migrations/0001_01_01_000000_create_users_table.php
resources/views/livewire/auth/login.blade.php
resources/views/livewire/auth/verify-email.blade.php
resources/views/livewire/auth/forgot-password.blade.php
resources/views/livewire/auth/confirm-password.blade.php
resources/views/livewire/auth/two-factor-challenge.blade.php
resources/views/livewire/auth/register.blade.php
resources/views/livewire/auth/reset-password.blade.php
resources/css/app.css
resources/views/welcome.blade.php
resources/views/layouts/auth.blade.php
app/Concerns/PasswordValidationRules.php
app/Concerns/ProfileValidationRules.php
resources/views/components/auth-session-status.blade.php
resources/views/components/placeholder-pattern.blade.php
resources/views/components/app-logo.blade.php
resources/views/components/action-message.blade.php
resources/views/components/auth-header.blade.php
resources/views/components/app-logo-icon.blade.php
resources/views/components/desktop-user-menu.blade.php
resources/views/livewire/settings/two-factor/recovery-codes.blade.php
resources/views/livewire/settings/profile.blade.php
resources/views/livewire/settings/appearance.blade.php
resources/views/livewire/settings/password.blade.php
resources/views/livewire/settings/two-factor.blade.php
resources/views/livewire/settings/delete-user-form.blade.php
resources/views/dashboard.blade.php
resources/views/components/settings/layout.blade.php
app/Models/User.php
storage/framework/sessions/.gitignore
resources/views/flux/navlist/group.blade.php
app/Actions/Fortify/CreateNewUser.php
app/Actions/Fortify/ResetUserPassword.php
app/Providers/FortifyServiceProvider.php
app/Providers/AppServiceProvider.php
resources/views/flux/icon/book-open-text.blade.php
resources/views/flux/icon/chevrons-up-down.blade.php
resources/views/flux/icon/folder-git-2.blade.php
resources/views/flux/icon/layout-grid.blade.php
storage/framework/cache/.gitignore
bootstrap/cache/.gitignore
app/Http/Controllers/Controller.php
storage/framework/cache/data/.gitignore
app/Livewire/Actions/Logout.php
storage/framework/testing/.gitignore
app/Livewire/Settings/Appearance.php
app/Livewire/Settings/Profile.php
app/Livewire/Settings/Password.php
app/Livewire/Settings/TwoFactor.php
app/Livewire/Settings/DeleteUserForm.php
app/Livewire/Settings/TwoFactor/RecoveryCodes.php

SPEC LINE COUNTS
    1683 specs/01-DATABASE-SCHEMA.md
    3240 specs/02-API-ROUTES.md
    2428 specs/03-ADMIN-UI.md
    1922 specs/04-STOREFRONT-UI.md
    1709 specs/05-BUSINESS-LOGIC.md
    1110 specs/06-AUTH-AND-SECURITY.md
    2245 specs/07-SEEDERS-AND-TEST-DATA.md
    3173 specs/08-PLAYWRIGHT-E2E-PLAN.md
    2065 specs/09-IMPLEMENTATION-ROADMAP.md
   19575 total

PROJECT MANIFESTS
{
    "$schema": "https://getcomposer.org/schema.json",
    "name": "laravel/livewire-starter-kit",
    "type": "project",
    "description": "The official Laravel starter kit for Livewire.",
    "keywords": [
        "laravel",
        "framework"
    ],
    "license": "MIT",
    "require": {
        "php": "^8.2",
        "laravel/fortify": "^1.30",
        "laravel/framework": "^12.0",
        "laravel/tinker": "^2.10.1",
        "livewire/flux": "^2.9.0",
        "livewire/livewire": "^4.0"
    },
    "require-dev": {
        "fakerphp/faker": "^1.23",
        "laravel/boost": "^1.0",
        "laravel/pail": "^1.2.2",
        "laravel/pint": "^1.24",
        "laravel/sail": "^1.41",
        "mockery/mockery": "^1.6",
        "nunomaduro/collision": "^8.6",
        "pestphp/pest": "^4.3",
        "pestphp/pest-plugin-laravel": "^4.0"
    },
    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Database\\Factories\\": "database/factories/",
            "Database\\Seeders\\": "database/seeders/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "Tests\\": "tests/"
        }
    },
    "scripts": {
        "setup": [
            "composer install",
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"",
            "@php artisan key:generate",
            "@php artisan migrate --force",
            "npm install",
            "npm run build"
        ],
        "dev": [
            "Composer\\Config::disableProcessTimeout",
            "npx concurrently -c \"#93c5fd,#c4b5fd,#fb7185,#fdba74\" \"php artisan serve\" \"php artisan queue:listen --tries=1 --timeout=0\" \"php artisan pail --timeout=0\" \"npm run dev\" --names=server,queue,logs,vite --kill-others"
        ],
        "lint": [
            "pint --parallel"
        ],
        "test:lint": [
            "pint --parallel --test"
        ],
        "test": [
            "@php artisan config:clear --ansi",
            "@test:lint",
            "@php artisan test"
        ],
        "post-autoload-dump": [
            "Illuminate\\Foundation\\ComposerScripts::postAutoloadDump",
            "@php artisan package:discover --ansi"
        ],
        "post-update-cmd": [
            "@php artisan vendor:publish --tag=laravel-assets --ansi --force"
        ],
        "post-root-package-install": [
            "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
        ],
        "post-create-project-cmd": [
            "@php artisan key:generate --ansi",
            "@php -r \"file_exists('database/database.sqlite') || touch('database/database.sqlite');\"",
            "@php artisan migrate --graceful --ansi"
        ],
        "pre-package-uninstall": [
            "Illuminate\\Foundation\\ComposerScripts::prePackageUninstall"
        ]
    },
    "extra": {
        "laravel": {
            "dont-discover": []
        }
    },
    "config": {
        "optimize-autoloader": true,
        "preferred-install": "dist",
        "sort-packages": true,
        "allow-plugins": {
            "pestphp/pest-plugin": true,
            "php-http/discovery": true
        }
    },
    "minimum-stability": "stable",
    "prefer-stable": true
}
{
    "$schema": "https://www.schemastore.org/package.json",
    "private": true,
    "type": "module",
    "scripts": {
        "build": "vite build",
        "dev": "vite"
    },
    "dependencies": {
        "@tailwindcss/vite": "^4.1.11",
        "autoprefixer": "^10.4.20",
        "axios": "^1.7.4",
        "concurrently": "^9.0.1",
        "laravel-vite-plugin": "^2.0",
        "tailwindcss": "^4.0.7",
        "vite": "^7.0.4"
    },
    "optionalDependencies": {
        "@rollup/rollup-linux-x64-gnu": "4.9.5",
        "@tailwindcss/oxide-linux-x64-gnu": "^4.0.1",
        "lightningcss-linux-x64-gnu": "^1.29.1"
    }
}

QUALITY CHECKER CONTRACT
# Checker Reference

## Command

```bash
php artisan code-quality:check [paths...] [options]
```

Important options:

- `--checks=*`: check IDs or groups. Supports repeated and comma-separated values.
- `--changed`: use changed files from `git diff`.
- `--staged`: use staged files from `git diff --cached`.
- `--format=pretty|json|jsonl`: choose output format.
- `--output=path`: write a JSON report file.
- `--fail-on=info|warning|error|critical`: blocking threshold.
- `--ai`: enable the configured AI reviewer adapter.
- `--no-ai`: remove AI checks even when selecting `all`.

## Exit Codes

- `0`: passed.
- `1`: completed with blocking findings.
- `2`: invalid input.
- `3`: checker execution error.
- `4`: timeout.
- `5`: AI unavailable.

## Generic Configuration

`config/code_quality.php` is intentionally app-neutral:

- `domain.multi_tenant`: enable tenant model boundary checks.
- `domain.tenant_keys`: tenant columns/identifiers to accept.
- `domain.ai_free_path_keywords`: path keywords for deterministic areas that must never reference AI infrastructure.
- `frontend.route_helper_names`: route helper names used by the app.
- `allowlists.global_models`: model classes that are globally scoped.

## Check Groups

- `all`
- `deterministic`
- `ai`
- `security`
- `stability`
- `laravel`
- `frontend`
- `worker`
- `tests`

## Deterministic Checks

- `deterministic.tenancy`
- `deterministic.secrets`
- `deterministic.llm-boundaries`
- `deterministic.ai-free-boundaries`
- `deterministic.request-validation`
- `deterministic.authorization`
- `deterministic.config-env`
- `deterministic.http-client`
- `deterministic.queue-stability`
- `deterministic.migrations`
- `deterministic.frontend-routes`
- `deterministic.dependencies`

## AI Checks

- `ai.architecture`
- `ai.clean-code`
- `ai.security-review`
- `ai.stability`
- `ai.test-quality`
- `ai.frontend-ux`

## Agent-Assisted Review

For broad reviews, prefer focused sub-agents/review workers when the host environment provides them. This skill should work in Codex, Claude Code, opencode, and similar tools, so phrase assignments generically and avoid depending on one product's terminology unless invoking that product's specific CLI adapter.

Split by risk area rather than by an arbitrary fixed count. Typical slices include API/auth, worker/internal protocol, billing/webhooks, public funnel/heartbeat, app-domain tenancy, frontend UX, and checker/skill packaging. Merge results, dedupe by file/risk, and write each accepted finding with:

- `Status: open`
- source/check category
- severity and confidence
- file and line
- concrete evidence
- recommendation
- stable dedupe key


The repository is a clean Laravel starter on a dedicated branch, so there’s no inherited shop implementation to unwind. The specifications are unusually comprehensive (about 19,500 lines); I’m extracting the build order and traceability map first, while the three role specialists independently cross-check backend, UI, and acceptance requirements.


exec

Input:
const r = await tools.exec_command({cmd:"printf 'ALL SPEC HEADINGS\\n'\nrg -n '^#{1,4} ' specs/*.md\nprintf '\\nIMPLEMENTATION ROADMAP PART 1\\n'\nsed -n '1,1050p' specs/09-IMPLEMENTATION-ROADMAP.md\nprintf '\\nIMPLEMENTATION ROADMAP PART 2\\n'\nsed -n '1051,2200p' specs/09-IMPLEMENTATION-ROADMAP.md","workdir":"/Users/fabianwesner/Herd/shop","yield_time_ms":10000,"max_output_tokens":120000});
text(r.output);


Script completed
Wall time 0.1 seconds
Output:

Warning: truncated output (original token count: 46847)
Total output lines: 3154

ALL SPEC HEADINGS
specs/07-SEEDERS-AND-TEST-DATA.md:1:# 07 - Seeders and Test Data Specification
specs/07-SEEDERS-AND-TEST-DATA.md:7:## 1. DatabaseSeeder Orchestration
specs/07-SEEDERS-AND-TEST-DATA.md:69:## 2. Factory Definitions
specs/07-SEEDERS-AND-TEST-DATA.md:75:### 2.1 OrganizationFactory
specs/07-SEEDERS-AND-TEST-DATA.md:90:### 2.2 StoreFactory
specs/07-SEEDERS-AND-TEST-DATA.md:114:### 2.3 StoreDomainFactory
specs/07-SEEDERS-AND-TEST-DATA.md:138:### 2.4 UserFactory
specs/07-SEEDERS-AND-TEST-DATA.md:160:### 2.5 ProductFactory
specs/07-SEEDERS-AND-TEST-DATA.md:194:### 2.6 ProductVariantFactory
specs/07-SEEDERS-AND-TEST-DATA.md:225:### 2.7 InventoryItemFactory
specs/07-SEEDERS-AND-TEST-DATA.md:249:### 2.8 CollectionFactory
specs/07-SEEDERS-AND-TEST-DATA.md:274:### 2.9 CartFactory
specs/07-SEEDERS-AND-TEST-DATA.md:298:### 2.10 CartLineFactory
specs/07-SEEDERS-AND-TEST-DATA.md:318:### 2.11 CheckoutFactory
specs/07-SEEDERS-AND-TEST-DATA.md:352:### 2.12 OrderFactory
specs/07-SEEDERS-AND-TEST-DATA.md:394:### 2.13 OrderLineFactory
specs/07-SEEDERS-AND-TEST-DATA.md:417:### 2.14 PaymentFactory
specs/07-SEEDERS-AND-TEST-DATA.md:447:### 2.15 RefundFactory
specs/07-SEEDERS-AND-TEST-DATA.md:471:### 2.16 FulfillmentFactory
specs/07-SEEDERS-AND-TEST-DATA.md:495:### 2.16b FulfillmentLineFactory
specs/07-SEEDERS-AND-TEST-DATA.md:511:### 2.17 CustomerFactory
specs/07-SEEDERS-AND-TEST-DATA.md:534:### 2.18 CustomerAddressFactory
specs/07-SEEDERS-AND-TEST-DATA.md:555:### 2.19 DiscountFactory
specs/07-SEEDERS-AND-TEST-DATA.md:591:### 2.20 ShippingZoneFactory
specs/07-SEEDERS-AND-TEST-DATA.md:608:### 2.21 ShippingRateFactory
specs/07-SEEDERS-AND-TEST-DATA.md:631:### 2.22 ThemeFactory
specs/07-SEEDERS-AND-TEST-DATA.md:653:### 2.23 PageFactory
specs/07-SEEDERS-AND-TEST-DATA.md:677:### 2.24 NavigationMenuFactory
specs/07-SEEDERS-AND-TEST-DATA.md:693:### 2.25 NavigationItemFactory
specs/07-SEEDERS-AND-TEST-DATA.md:718:### 2.26 AnalyticsEventFactory
specs/07-SEEDERS-AND-TEST-DATA.md:743:## 3. Demo Seed Scenario (Exact Data)
specs/07-SEEDERS-AND-TEST-DATA.md:749:### 3.1 OrganizationSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:760:### 3.2 StoreSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:788:### 3.3 StoreDomainSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:807:### 3.4 UserSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:819:### 3.5 StoreUserSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:831:### 3.6 StoreSettingsSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:853:### 3.7 TaxSettingsSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:870:### 3.8 ShippingSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:910:### 3.9 CollectionSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:930:### 3.10 ProductSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:932:#### Acme Fashion - 20 Products
specs/07-SEEDERS-AND-TEST-DATA.md:1388:#### Product Summary Table (Acme Fashion)
specs/07-SEEDERS-AND-TEST-DATA.md:1417:#### Acme Electronics - 5 Products (minimal seed for tenant isolation)
specs/07-SEEDERS-AND-TEST-DATA.md:1435:### 3.11 DiscountSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:1456:### 3.12 CustomerSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:1499:### 3.13 OrderSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:1853:#### Order Summary Table (Acme Fashion)
specs/07-SEEDERS-AND-TEST-DATA.md:1885:### 3.14 ThemeSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:1939:### 3.15 PageSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:1971:### 3.16 NavigationSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:2003:### 3.17 AnalyticsSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:2075:### 3.18 SearchSettingsSeeder
specs/07-SEEDERS-AND-TEST-DATA.md:2093:## 4. Collection-Product Assignments Summary
specs/07-SEEDERS-AND-TEST-DATA.md:2115:## 5. Test Credentials Summary
specs/07-SEEDERS-AND-TEST-DATA.md:2192:## 6. Implementation Notes
specs/07-SEEDERS-AND-TEST-DATA.md:2194:### Idempotency
specs/07-SEEDERS-AND-TEST-DATA.md:2198:### Performance
specs/07-SEEDERS-AND-TEST-DATA.md:2202:### Timestamps
specs/07-SEEDERS-AND-TEST-DATA.md:2206:### Variant-Option Wiring
specs/07-SEEDERS-AND-TEST-DATA.md:2216:### Inventory Items
specs/07-SEEDERS-AND-TEST-DATA.md:2220:### Order Line Snapshots
specs/07-SEEDERS-AND-TEST-DATA.md:2224:### Address JSON Structure
specs/07-SEEDERS-AND-TEST-DATA.md:2243:### Discount Allocation on Order Lines
specs/05-BUSINESS-LOGIC.md:1:# 05 - Business Logic Specification
specs/05-BUSINESS-LOGIC.md:7:## Conventions
specs/05-BUSINESS-LOGIC.md:20:## 1. Multi-Tenancy and Store Isolation
specs/05-BUSINESS-LOGIC.md:22:### 1.1 Tenant Resolution Middleware
specs/05-BUSINESS-LOGIC.md:28:#### Storefront Route Resolution (from request hostname)
specs/05-BUSINESS-LOGIC.md:37:#### Admin Route Resolution (from session)
specs/05-BUSINESS-LOGIC.md:66:### 1.2 Store Scoping
specs/05-BUSINESS-LOGIC.md:82:### 1.3 Role-Based Access Control
specs/05-BUSINESS-LOGIC.md:111:## 2. Product Lifecycle
specs/05-BUSINESS-LOGIC.md:113:### 2.1 Status Transitions
specs/05-BUSINESS-LOGIC.md:148:### 2.2 Variant and Option Matrix
specs/05-BUSINESS-LOGIC.md:180:### 2.3 SKU Uniqueness
specs/05-BUSINESS-LOGIC.md:187:### 2.4 Handle/Slug Generation
specs/05-BUSINESS-LOGIC.md:199:## 3. Inventory Management
specs/05-BUSINESS-LOGIC.md:201:### 3.1 Tracking Model
specs/05-BUSINESS-LOGIC.md:211:### 3.2 Inventory Policy
specs/05-BUSINESS-LOGIC.md:220:### 3.3 Inventory Operations
specs/05-BUSINESS-LOGIC.md:245:### 3.4 Concurrency
specs/05-BUSINESS-LOGIC.md:251:## 4. Cart Service
specs/05-BUSINESS-LOGIC.md:253:### 4.1 Cart Lifecycle
specs/05-BUSINESS-LOGIC.md:285:### 4.2 Cart Operations
specs/05-BUSINESS-LOGIC.md:314:### 4.3 Cart Version (Optimistic Concurrency)
specs/05-BUSINESS-LOGIC.md:326:### 4.4 Line Amount Calculation
specs/05-BUSINESS-LOGIC.md:336:### 4.5 Cart Expiration
specs/05-BUSINESS-LOGIC.md:347:## 5. Pricing Engine
specs/05-BUSINESS-LOGIC.md:349:### 5.1 Calculation Order (deterministic pipeline)
specs/05-BUSINESS-LOGIC.md:374:### 5.2 Output Structure
specs/05-BUSINESS-LOGIC.md:396:### 5.3 Rounding Strategy
specs/05-BUSINESS-LOGIC.md:403:### 5.4 Determinism and Snapshotting
specs/05-BUSINESS-LOGIC.md:411:## 6. Checkout State Machine
specs/05-BUSINESS-LOGIC.md:413:### 6.1 States
specs/05-BUSINESS-LOGIC.md:437:### 6.2 Transitions and Validation
specs/05-BUSINESS-LOGIC.md:441:#### Transition: started -> addressed
specs/05-BUSINESS-LOGIC.md:471:#### Transition: addressed -> shipping_selected
specs/05-BUSINESS-LOGIC.md:487:#### Transition: shipping_selected -> payment_selected
specs/05-BUSINESS-LOGIC.md:502:#### Transition: payment_selected -> completed
specs/05-BUSINESS-LOGIC.md:578:#### Transition: Any active state -> expired
specs/05-BUSINESS-LOGIC.md:589:### 6.3 Events
specs/05-BUSINESS-LOGIC.md:600:## 7. Discount Engine
specs/05-BUSINESS-LOGIC.md:602:### 7.1 Discount Types
specs/05-BUSINESS-LOGIC.md:615:### Discount Status Lifecycle
specs/05-BUSINESS-LOGIC.md:630:### 7.2 Value Types
specs/05-BUSINESS-LOGIC.md:640:### 7.3 Rules
specs/05-BUSINESS-LOGIC.md:653:### 7.4 Validation Flow
specs/05-BUSINESS-LOGIC.md:679:### 7.5 Error Codes
specs/05-BUSINESS-LOGIC.md:690:### 7.6 Discount Allocation
specs/05-BUSINESS-LOGIC.md:722:### 7.7 Usage Tracking
specs/05-BUSINESS-LOGIC.md:730:## 8. Tax Calculation
specs/05-BUSINESS-LOGIC.md:732:### 8.1 Tax Provider Architecture
specs/05-BUSINESS-LOGIC.md:746:### 8.2 Manual Tax Mode
specs/05-BUSINESS-LOGIC.md:761:### 8.3 Prices Include Tax
specs/05-BUSINESS-LOGIC.md:765:#### Tax-inclusive pricing (prices_include_tax = true)
specs/05-BUSINESS-LOGIC.md:782:#### Tax-exclusive pricing (prices_include_tax = false)
specs/05-BUSINESS-LOGIC.md:796:### 8.4 Stripe Tax Provider (Stub)
specs/05-BUSINESS-LOGIC.md:809:### 8.5 Discount-Before-Tax Semantics
specs/05-BUSINESS-LOGIC.md:823:## 9. Shipping Calculation
specs/05-BUSINESS-LOGIC.md:825:### 9.1 Zone Matching
specs/05-BUSINESS-LOGIC.md:860:### 9.2 Rate Types
specs/05-BUSINESS-LOGIC.md:864:#### Flat rate
specs/05-BUSINESS-LOGIC.md:870:#### Weight-based rate
specs/05-BUSINESS-LOGIC.md:888:#### Price-based rate
specs/05-BUSINESS-LOGIC.md:904:#### Carrier-calculated rate (stub)
specs/05-BUSINESS-LOGIC.md:911:### 9.3 Requires Shipping Check
specs/05-BUSINESS-LOGIC.md:921:### 9.4 Free Shipping Discount Override
specs/05-BUSINESS-LOGIC.md:929:## 10. Payment Processing (Mock PSP)
specs/05-BUSINESS-LOGIC.md:931:### 10.1 Mock Payment Provider Architecture
specs/05-BUSINESS-LOGIC.md:945:### 10.2 Supported Payment Methods
specs/05-BUSINESS-LOGIC.md:955:### 10.3 Magic Card Numbers (Credit Card Testing)
specs/05-BUSINESS-LOGIC.md:968:### 10.4 Mock Payment Flow
specs/05-BUSINESS-LOGIC.md:1000:### 10.5 Payment State Machine
specs/05-BUSINESS-LOGIC.md:1014:### 10.6 Bank Transfer Instructions
specs/05-BUSINESS-LOGIC.md:1028:### 10.7 Admin: Confirm Payment (Bank Transfer)
specs/05-BUSINESS-LOGIC.md:1041:### 10.8 Auto-Cancel Unpaid Bank Transfer Orders
specs/05-BUSINESS-LOGIC.md:1058:## 11. Order Management
specs/05-BUSINESS-LOGIC.md:1060:### 11.1 Order Creation (from Completed Checkout)
specs/05-BUSINESS-LOGIC.md:1079:### 11.2 Order Numbering
specs/05-BUSINESS-LOGIC.md:1086:### 11.3 Order Statuses
specs/05-BUSINESS-LOGIC.md:1119:### 11.4 Refund Processing
specs/05-BUSINESS-LOGIC.md:1167:### 11.5 Fulfillment
specs/05-BUSINESS-LOGIC.md:1171:#### Fulfillment Guard
specs/05-BUSINESS-LOGIC.md:1186:#### Creating a Fulfillment
specs/05-BUSINESS-LOGIC.md:1223:#### Fulfillment Status Transitions (Admin Button Actions)
specs/05-BUSINESS-LOGIC.md:1253:### 11.6 Fulfillment Guard - Inventory Behavior per Payment Method
specs/05-BUSINESS-LOGIC.md:1264:### 11.7 Auto-Fulfillment for Digital Products
specs/05-BUSINESS-LOGIC.md:1279:### 11.6 Order Export
specs/05-BUSINESS-LOGIC.md:1289:## 12. Customer Accounts
specs/05-BUSINESS-LOGIC.md:1291:### 12.1 Registration
specs/05-BUSINESS-LOGIC.md:1307:### 12.2 Authentication
specs/05-BUSINESS-LOGIC.md:1319:### 12.3 Data Access
specs/05-BUSINESS-LOGIC.md:1325:### 12.4 Guest Cart to Customer Linking
specs/05-BUSINESS-LOGIC.md:1345:## 13. Webhook Delivery System
specs/05-BUSINESS-LOGIC.md:1347:### 13.1 Subscription Model
specs/05-BUSINESS-LOGIC.md:1364:### 13.2 Delivery Process
specs/05-BUSINESS-LOGIC.md:1401:### 13.3 Retry Logic
specs/05-BUSINESS-LOGIC.md:1418:### 13.4 Circuit Breaker
specs/05-BUSINESS-LOGIC.md:1430:## 14. Analytics
specs/05-BUSINESS-LOGIC.md:1432:### 14.1 Event Ingestion
specs/05-BUSINESS-LOGIC.md:1470:### 14.2 Aggregation
specs/05-BUSINESS-LOGIC.md:1490:## 15. Media Processing
specs/05-BUSINESS-LOGIC.md:1492:### 15.1 Upload Flow
specs/05-BUSINESS-LOGIC.md:1504:### 15.2 Processing
specs/05-BUSINESS-LOGIC.md:1525:### 15.3 Cleanup
specs/05-BUSINESS-LOGIC.md:1531:## 16. Search (SQLite FTS5)
specs/05-BUSINESS-LOGIC.md:1533:### 16.1 Index Setup
specs/05-BUSINESS-LOGIC.md:1547:### 16.2 Index Synchronization
specs/05-BUSINESS-LOGIC.md:1562:### 16.3 Search Query
specs/05-BUSINESS-LOGIC.md:1582:### 16.4 Search Logging
specs/05-BUSINESS-LOGIC.md:1588:## 17. Event and Listener Registry
specs/05-BUSINESS-LOGIC.md:1614:## 18. Scheduled Jobs Registry
specs/05-BUSINESS-LOGIC.md:1634:## 19. Service Class Registry
specs/05-BUSINESS-LOGIC.md:1660:## 20. Contracts (Interfaces)
specs/05-BUSINESS-LOGIC.md:1669:## 21. Enum Registry
specs/05-BUSINESS-LOGIC.md:1694:## 22. Value Object Registry
specs/09-IMPLEMENTATION-ROADMAP.md:1:# 09 - Implementation Roadmap and Pest Test Specification
specs/09-IMPLEMENTATION-ROADMAP.md:7:## 1. Technology Decisions (Final)
specs/09-IMPLEMENTATION-ROADMAP.md:33:## 2. Implementation Phases (Build Order)
specs/09-IMPLEMENTATION-ROADMAP.md:37:### Phase Dependency Graph
specs/09-IMPLEMENTATION-ROADMAP.md:74:### Phase 1: Foundation (Migrations, Models, Middleware, Auth)
specs/09-IMPLEMENTATION-ROADMAP.md:78:#### Step 1.1: Environment and Config
specs/09-IMPLEMENTATION-ROADMAP.md:100:#### Step 1.2: Core Migrations (Batch 1-2)
specs/09-IMPLEMENTATION-ROADMAP.md:113:#### Step 1.3: Core Models
specs/09-IMPLEMENTATION-ROADMAP.md:143:#### Step 1.4: Enums
specs/09-IMPLEMENTATION-ROADMAP.md:153:#### Step 1.5: Tenant Resolution Middleware
specs/09-IMPLEMENTATION-ROADMAP.md:167:#### Step 1.6: BelongsToStore Trait and Global Scope
specs/09-IMPLEMENTATION-ROADMAP.md:178:#### Step 1.7: Authentication
specs/09-IMPLEMENTATION-ROADMAP.md:204:#### Step 1.8: Authorization
specs/09-IMPLEMENTATION-ROADMAP.md:245:### Phase 2: Catalog (Products, Variants, Inventory, Collections, Media)
specs/09-IMPLEMENTATION-ROADMAP.md:249:#### Step 2.1: Migrations (Batch 3-5)
specs/09-IMPLEMENTATION-ROADMAP.md:263:#### Step 2.2: Models with Relationships
specs/09-IMPLEMENTATION-ROADMAP.md:300:#### Step 2.3: Product Service
specs/09-IMPLEMENTATION-ROADMAP.md:323:#### Step 2.4: Inventory Service
specs/09-IMPLEMENTATION-ROADMAP.md:337:#### Step 2.5: Media Upload
specs/09-IMPLEMENTATION-ROADMAP.md:349:### Phase 3: Themes, Pages, Navigation, Storefront Layout
specs/09-IMPLEMENTATION-ROADMAP.md:353:#### Step 3.1: Migrations (Batch 3)
specs/09-IMPLEMENTATION-ROADMAP.md:362:#### Step 3.2: Models
specs/09-IMPLEMENTATION-ROADMAP.md:394:#### Step 3.3: Storefront Blade Layout
specs/09-IMPLEMENTATION-ROADMAP.md:413:#### Step 3.4: Storefront Livewire Components
specs/09-IMPLEMENTATION-ROADMAP.md:429:#### Step 3.5: Navigation Service
specs/09-IMPLEMENTATION-ROADMAP.md:442:### Phase 4: Cart, Checkout, Discounts, Shipping, Taxes
specs/09-IMPLEMENTATION-ROADMAP.md:446:#### Step 4.1: Migrations (Batch 4-5)
specs/09-IMPLEMENTATION-ROADMAP.md:456:#### Step 4.2: Models
specs/09-IMPLEMENTATION-ROADMAP.md:494:#### Step 4.3: Cart Service
specs/09-IMPLEMENTATION-ROADMAP.md:509:#### Step 4.4: Discount Service
specs/09-IMPLEMENTATION-ROADMAP.md:520:#### Step 4.5: Shipping Calculator
specs/09-IMPLEMENTATION-ROADMAP.md:531:#### Step 4.6: Tax Calculator
specs/09-IMPLEMENTATION-ROADMAP.md:543:#### Step 4.7: Pricing Engine
specs/09-IMPLEMENTATION-ROADMAP.md:567:#### Step 4.8: Checkout State Machine
specs/09-IMPLEMENTATION-ROADMAP.md:586:#### Step 4.9: Storefront Cart/Checkout UI
specs/09-IMPLEMENTATION-ROADMAP.md:599:### Phase 5: Payments, Orders, Fulfillment
specs/09-IMPLEMENTATION-ROADMAP.md:603:#### Step 5.1: Migrations (Batch 5-7)
specs/09-IMPLEMENTATION-ROADMAP.md:614:#### Step 5.2: Models
specs/09-IMPLEMENTATION-ROADMAP.md:654:#### Step 5.3: Payment Service (Mock PSP)
specs/09-IMPLEMENTATION-ROADMAP.md:680:#### Step 5.3b: Admin Payment Confirmation
specs/09-IMPLEMENTATION-ROADMAP.md:696:#### Step 5.4: Order Service
specs/09-IMPLEMENTATION-ROADMAP.md:708:#### Step 5.5: Refund Service
specs/09-IMPLEMENTATION-ROADMAP.md:720:#### Step 5.6: Fulfillment Service
specs/09-IMPLEMENTATION-ROADMAP.md:746:### Phase 6: Customer Accounts
specs/09-IMPLEMENTATION-ROADMAP.md:750:#### Step 6.1: Customer Auth
specs/09-IMPLEMENTATION-ROADMAP.md:756:#### Step 6.2: Customer Account Pages (Livewire)
specs/09-IMPLEMENTATION-ROADMAP.md:773:### Phase 7: Admin Panel
specs/09-IMPLEMENTATION-ROADMAP.md:777:#### Step 7.1: Admin Layout
specs/09-IMPLEMENTATION-ROADMAP.md:791:#### Step 7.2: Dashboard
specs/09-IMPLEMENTATION-ROADMAP.md:801:#### Step 7.3: Product Management
specs/09-IMPLEMENTATION-ROADMAP.md:816:#### Step 7.4: Order Management
specs/09-IMPLEMENTATION-ROADMAP.md:828:#### Step 7.5: Other Admin Sections
specs/09-IMPLEMENTATION-ROADMAP.md:856:### Phase 8: Search
specs/09-IMPLEMENTATION-ROADMAP.md:860:#### Step 8.1: Migrations
specs/09-IMPLEMENTATION-ROADMAP.md:866:#### Step 8.2: Search Service
specs/09-IMPLEMENTATION-ROADMAP.md:879:#### Step 8.3: Search UI
specs/09-IMPLEMENTATION-ROADMAP.md:890:### Phase 9: Analytics
specs/09-IMPLEMENTATION-ROADMAP.md:894:#### Step 9.1: Migrations
specs/09-IMPLEMENTATION-ROADMAP.md:899:#### Step 9.2: Analytics Service
specs/09-IMPLEMENTATION-ROADMAP.md:919:### Phase 10: Apps and Webhooks
specs/09-IMPLEMENTATION-ROADMAP.md:923:#### Step 10.1: Migrations
specs/09-IMPLEMENTATION-ROADMAP.md:932:#### Step 10.2: Webhook Service
specs/09-IMPLEMENTATION-ROADMAP.md:953:### Phase 11: Polish
specs/09-IMPLEMENTATION-ROADMAP.md:966:### Phase 12: Full Test Suite Execution
specs/09-IMPLEMENTATION-ROADMAP.md:981:## 3. Pest Unit/Feature Test Specification
specs/09-IMPLEMENTATION-ROADMAP.md:985:### Test Directory Structure
specs/09-IMPLEMENTATION-ROADMAP.md:1007:### Unit Tests
specs/09-IMPLEMENTATION-ROADMAP.md:1011:#### tests/Unit/PricingEngineTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1034:#### tests/Unit/DiscountCalculatorTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1056:#### tests/Unit/TaxCalculatorTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1072:#### tests/Unit/ShippingCalculatorTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1090:#### tests/Unit/CartVersionTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1104:#### tests/Unit/HandleGeneratorTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1119:### Feature Tests
specs/09-IMPLEMENTATION-ROADMAP.md:1130:#### tests/Feature/Tenancy/TenantResolutionTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1143:#### tests/Feature/Tenancy/StoreIsolationTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1155:#### tests/Feature/Auth/AdminAuthTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1172:#### tests/Feature/Auth/CustomerAuthTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1189:#### tests/Feature/Auth/SanctumTokenTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1201:#### tests/Feature/Products/ProductCrudTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1221:#### tests/Feature/Products/VariantTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1236:#### tests/Feature/Products/InventoryTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1251:#### tests/Feature/Products/CollectionTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1265:#### tests/Feature/Products/MediaUploadTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1278:#### tests/Feature/Cart/CartServiceTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1297:#### tests/Feature/Cart/CartApiTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1312:#### tests/Feature/Checkout/CheckoutFlowTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1324:#### tests/Feature/Checkout/CheckoutStateTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1340:#### tests/Feature/Checkout/PricingIntegrationTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1352:#### tests/Feature/Checkout/DiscountTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1365:#### tests/Feature/Checkout/ShippingTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1377:#### tests/Feature/Checkout/TaxTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1388:#### tests/Feature/Orders/OrderCreationTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1404:#### tests/Feature/Orders/RefundTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1418:#### tests/Feature/Orders/FulfillmentTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1437:#### tests/Feature/Payments/MockPaymentProviderTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1450:#### tests/Feature/Payments/PaymentServiceTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1462:#### tests/Feature/Payments/BankTransferConfirmationTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1475:#### tests/Feature/Customers/CustomerAccountTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1488:#### tests/Feature/Customers/AddressManagementTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1502:#### tests/Feature/Admin/DashboardTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1513:#### tests/Feature/Admin/ProductManagementTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1528:#### tests/Feature/Admin/OrderManagementTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1540:#### tests/Feature/Admin/DiscountManagementTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1553:#### tests/Feature/Admin/SettingsTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1566:#### tests/Feature/Search/SearchTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1578:#### tests/Feature/Search/AutocompleteTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1588:#### tests/Feature/Analytics/EventIngestionTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1600:#### tests/Feature/Analytics/AggregationTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1610:#### tests/Feature/Webhooks/WebhookDeliveryTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1622:#### tests/Feature/Webhooks/WebhookSignatureTest.php
specs/09-IMPLEMENTATION-ROADMAP.md:1633:#### tests/Feature/Api/StorefrontCartApiTest.php
specs/0…36847 tokens truncated…selects a shipping method | PUT /api/storefront/v1/checkouts/{id}/shipping-method | 200 response, status=shipping_selected, available rates returned in response | happy path |
| applies a discount code | POST /api/storefront/v1/checkouts/{id}/apply-discount with code | 200 response, discount applied in totals | happy path |
| retrieves checkout with totals | GET /api/storefront/v1/checkouts/{id} | 200 response, includes totals_json fields | happy path |
| selects a payment method | PUT /api/storefront/v1/checkouts/{id}/payment-method with method=credit_card | 200 response, status=payment_selected, payment_method stored | happy path |
| completes checkout with credit card payment | POST /api/storefront/v1/checkouts/{id}/pay with card fields | 200 response, status=completed, order created | happy path |
| rejects payment with declined card | POST /api/storefront/v1/checkouts/{id}/pay with magic decline number | 422 response, payment declined message | validation |
| validates required address fields | PUT address with missing city | 422 response | validation |

---

#### tests/Feature/Api/AdminProductApiTest.php

| Test Name | Setup / Preconditions | Key Assertions | Category |
|-----------|----------------------|----------------|----------|
| lists products with authentication | GET /api/admin/v1/stores/{storeId}/products with Bearer token | 200 response, paginated product list | happy path |
| creates a product via API | POST /api/admin/v1/stores/{storeId}/products with product data | 201 response, product in response | happy path |
| updates a product via API | PUT /api/admin/v1/stores/{storeId}/products/{id} with updated data | 200 response, product updated | happy path |
| deletes a draft product via API | DELETE /api/admin/v1/stores/{storeId}/products/{id} | 200 response | happy path |
| requires write-products ability for mutations | token with only read-products; POST /api/admin/v1/stores/{storeId}/products | 403 response | authorization |
| returns 401 without token | GET /api/admin/v1/stores/{storeId}/products without auth header | 401 response | authorization |
| paginates results | 25 products, default page size 15 | first page has 15 items, meta has total=25 | happy path |

---

#### tests/Feature/Api/AdminOrderApiTest.php

| Test Name | Setup / Preconditions | Key Assertions | Category |
|-----------|----------------------|----------------|----------|
| lists orders with authentication | GET /api/admin/v1/stores/{storeId}/orders with Bearer token | 200 response, order list | happy path |
| retrieves a single order | GET /api/admin/v1/stores/{storeId}/orders/{id} | 200 response, order with lines, payments, fulfillments | happy path |
| filters orders by status | GET /api/admin/v1/stores/{storeId}/orders?status=paid | only paid orders returned | happy path |
| creates a fulfillment via API | POST /api/admin/v1/stores/{storeId}/orders/{id}/fulfillments | 201 response, fulfillment created | happy path |
| creates a refund via API | POST /api/admin/v1/stores/{storeId}/orders/{id}/refunds | 201 response, refund created | happy path |
| requires write-orders ability for mutations | token with only read-orders; POST fulfillment | 403 response | authorization |

---

## 4. Files to Create Inventory

### Models (with migration, factory, seeder)

| Name | Purpose |
|------|---------|
| `Organization` | Top-level tenant entity |
| `Store` | Individual store within an organization |
| `StoreDomain` | Domain mapping for a store |
| `StoreUser` | Pivot model with role attribute |
| `StoreSettings` | Per-store configuration |
| `Product` | Product entity |
| `ProductOption` | Product option definition |
| `ProductOptionValue` | Option value entry |
| `ProductVariant` | Product variant (SKU-level) |
| `InventoryItem` | Inventory tracking per variant |
| `Collection` | Product collection/category |
| `ProductMedia` | Product images and videos |
| `Theme` | Store theme entity |
| `ThemeFile` | Individual theme file |
| `ThemeSettings` | Theme configuration |
| `Page` | CMS page |
| `NavigationMenu` | Navigation menu entity |
| `NavigationItem` | Individual navigation item |
| `Cart` | Shopping cart entity |
| `CartLine` | Individual cart line item |
| `Checkout` | Checkout session entity |
| `ShippingZone` | Shipping zone configuration |
| `ShippingRate` | Shipping rate within a zone |
| `TaxSettings` | Per-store tax configuration |
| `Discount` | Discount code or automatic discount |
| `Customer` | Store customer entity |
| `CustomerAddress` | Customer address |
| `Order` | Order entity |
| `OrderLine` | Order line item |
| `Payment` | Payment record |
| `Refund` | Refund record |
| `Fulfillment` | Fulfillment record |
| `FulfillmentLine` | Fulfillment line item |
| `App` | Third-party app entity |
| `AppInstallation` | App installation per store |
| `OauthClient` | OAuth client for app |
| `OauthToken` | OAuth token for installation |
| `WebhookSubscription` | Webhook subscription per store |
| `WebhookDelivery` | Webhook delivery log |
| `AnalyticsEvent` | Raw analytics event |
| `AnalyticsDaily` | Pre-aggregated daily analytics |
| `SearchSettings` | Per-store search configuration |
| `SearchQuery` | Search query log |

### Livewire Components - Admin

| Name | Purpose |
|------|---------|
| `Admin/Auth/Login` | Admin login form |
| `Admin/Dashboard` | Admin dashboard |
| `Admin/Layout/Sidebar` | Admin sidebar navigation |
| `Admin/Layout/TopBar` | Admin top bar with store selector |
| `Admin/Products/Index` | Product list |
| `Admin/Products/Form` | Shared product form (create/edit mode) |
| `Admin/Collections/Index` | Collection list |
| `Admin/Collections/Form` | Shared collection form (create/edit mode) |
| `Admin/Orders/Index` | Order list |
| `Admin/Orders/Show` | Order detail |
| `Admin/Customers/Index` | Customer list |
| `Admin/Customers/Show` | Customer detail |
| `Admin/Discounts/Index` | Discount list |
| `Admin/Discounts/Form` | Shared discount form (create/edit mode) |
| `Admin/Settings/Index` | Settings tabs |
| `Admin/Settings/Shipping` | Shipping zone/rate management |
| `Admin/Settings/Taxes` | Tax settings |
| `Admin/Inventory/Index` | Inventory management - list and filter inventory items, adjust quantities (Spec 03 Section 8) |
| `Admin/Themes/Index` | Theme list |
| `Admin/Themes/Editor` | Theme editor |
| `Admin/Pages/Index` | Page list |
| `Admin/Pages/Form` | Shared page form (create/edit mode) |
| `Admin/Navigation/Index` | Navigation menu management |
| `Admin/Analytics/Index` | Analytics dashboard |
| `Admin/Search/Settings` | Search settings |
| `Admin/Apps/Index` | App directory |
| `Admin/Apps/Show` | Installed app detail |
| `Admin/Developers/Index` | API token and webhook management |

### Livewire Components - Storefront

| Name | Purpose |
|------|---------|
| `Storefront/Home` | Storefront home page |
| `Storefront/Collections/Index` | All collections grid |
| `Storefront/Collections/Show` | Collection product grid |
| `Storefront/Products/Show` | Product detail page |
| `Storefront/Cart/Show` | Full cart page |
| `Storefront/CartDrawer` | Slide-out cart drawer |
| `Storefront/Search/Index` | Search results page |
| `Storefront/Search/Modal` | Search autocomplete modal |
| `Storefront/Pages/Show` | CMS page renderer |
| `Storefront/Checkout/Show` | Multi-step checkout |
| `Storefront/Checkout/Confirmation` | Order confirmation |
| `Storefront/Account/Auth/Login` | Customer login |
| `Storefront/Account/Auth/Register` | Customer registration |
| `Storefront/Account/Dashboard` | Customer dashboard |
| `Storefront/Account/Orders/Index` | Customer order history |
| `Storefront/Account/Orders/Show` | Customer order detail |
| `Storefront/Account/Addresses/Index` | Customer address management |

### Middleware

| Name | Purpose |
|------|---------|
| `ResolveStore` | Resolves current store from hostname or session |
| `CheckStoreRole` | Validates user has required store role |
| `CustomerAuthenticate` | Customer guard authentication |

### Policies

| Name | Model |
|------|-------|
| `ProductPolicy` | Product |
| `OrderPolicy` | Order |
| `CollectionPolicy` | Collection |
| `DiscountPolicy` | Discount |
| `CustomerPolicy` | Customer |
| `StorePolicy` | Store |
| `PagePolicy` | Page |
| `ThemePolicy` | Theme |
| `FulfillmentPolicy` | Fulfillment |
| `RefundPolicy` | Refund |

### Form Requests

| Name | Purpose |
|------|---------|
| `StoreProductRequest` | Validate product creation |
| `UpdateProductRequest` | Validate product update |
| `StoreCollectionRequest` | Validate collection creation |
| `UpdateCollectionRequest` | Validate collection update |
| `StoreDiscountRequest` | Validate discount creation |
| `UpdateDiscountRequest` | Validate discount update |
| `SetCheckoutAddressRequest` | Validate checkout address |
| `SetCheckoutShippingRequest` | Validate checkout shipping selection |
| `CreateFulfillmentRequest` | Validate fulfillment creation |
| `CreateRefundRequest` | Validate refund creation |
| `StorePageRequest` | Validate page creation |
| `UpdatePageRequest` | Validate page update |
| `RegisterCustomerRequest` | Validate customer registration |
| `StoreShippingZoneRequest` | Validate shipping zone creation |
| `StoreShippingRateRequest` | Validate shipping rate creation |
| `UpdateTaxSettingsRequest` | Validate tax settings update |
| `StoreCustomerAddressRequest` | Validate customer address creation |
| `UpdateCustomerAddressRequest` | Validate customer address update |

### Jobs

| Name | Purpose |
|------|---------|
| `ProcessMediaUpload` | Resize images, update media status |
| `DeliverWebhook` | HTTP POST webhook with retry logic |
| `AggregateAnalytics` | Daily analytics aggregation |
| `CleanupAbandonedCarts` | Mark old active carts as abandoned |
| `ExpireAbandonedCheckouts` | Expire timed-out checkouts, release inventory |

### Events

| Name | Purpose |
|------|---------|
| `OrderCreated` | Dispatched when order is created |
| `OrderPaid` | Dispatched when payment is captured |
| `OrderFulfilled` | Dispatched when all lines fulfilled |
| `OrderCancelled` | Dispatched when order is cancelled |
| `OrderRefunded` | Dispatched when refund is processed |
| `CheckoutCompleted` | Dispatched when checkout completes |
| `CheckoutAddressed` | Dispatched when address is set |
| `CheckoutShippingSelected` | Dispatched when shipping is selected |
| `ProductStatusChanged` | Dispatched when product status transitions |
| `CartUpdated` | Dispatched when cart is mutated |

### Tests

**Unit tests to create (6 files):**

| Name | Purpose |
|------|---------|
| `PricingEngineTest` | Pricing pipeline unit tests |
| `DiscountCalculatorTest` | Discount validation and calculation unit tests |
| `TaxCalculatorTest` | Tax calculation unit tests |
| `ShippingCalculatorTest` | Shipping rate calculation unit tests |
| `CartVersionTest` | Cart versioning unit tests |
| `HandleGeneratorTest` | Slug generation unit tests |

**Feature tests to create (28 files):**

| Name | Purpose |
|------|---------|
| `Tenancy/TenantResolutionTest` | Tenant resolution feature tests |
| `Tenancy/StoreIsolationTest` | Store isolation feature tests |
| `Auth/AdminAuthTest` | Admin authentication feature tests |
| `Auth/CustomerAuthTest` | Customer authentication feature tests |
| `Auth/SanctumTokenTest` | API token feature tests |
| `Products/ProductCrudTest` | Product CRUD feature tests |
| `Products/VariantTest` | Variant management feature tests |
| `Products/InventoryTest` | Inventory management feature tests |
| `Products/CollectionTest` | Collection feature tests |
| `Products/MediaUploadTest` | Media upload feature tests |
| `Cart/CartServiceTest` | Cart service feature tests |
| `Cart/CartApiTest` | Cart API feature tests |
| `Checkout/CheckoutFlowTest` | Checkout flow feature tests |
| `Checkout/CheckoutStateTest` | Checkout state machine feature tests |
| `Checkout/PricingIntegrationTest` | Pricing integration feature tests |
| `Checkout/DiscountTest` | Checkout discount feature tests |
| `Checkout/ShippingTest` | Checkout shipping feature tests |
| `Checkout/TaxTest` | Checkout tax feature tests |
| `Orders/OrderCreationTest` | Order creation feature tests |
| `Orders/RefundTest` | Refund feature tests |
| `Orders/FulfillmentTest` | Fulfillment feature tests |
| `Payments/MockPaymentProviderTest` | Mock PSP charge/decline feature tests |
| `Payments/PaymentServiceTest` | Payment service feature tests |
| `Payments/BankTransferConfirmationTest` | Bank transfer confirmation and auto-cancel tests |
| `Customers/CustomerAccountTest` | Customer account feature tests |
| `Customers/AddressManagementTest` | Address management feature tests |
| `Admin/DashboardTest` | Admin dashboard feature tests |
| `Admin/ProductManagementTest` | Admin product management feature tests |
| `Admin/OrderManagementTest` | Admin order management feature tests |
| `Admin/DiscountManagementTest` | Admin discount management feature tests |
| `Admin/SettingsTest` | Admin settings feature tests |
| `Search/SearchTest` | Search feature tests |
| `Search/AutocompleteTest` | Autocomplete feature tests |
| `Analytics/EventIngestionTest` | Analytics event ingestion feature tests |
| `Analytics/AggregationTest` | Analytics aggregation feature tests |
| `Webhooks/WebhookDeliveryTest` | Webhook delivery feature tests |
| `Webhooks/WebhookSignatureTest` | Webhook signature feature tests |
| `Api/StorefrontCartApiTest` | Storefront cart API feature tests |
| `Api/StorefrontCheckoutApiTest` | Storefront checkout API feature tests |
| `Api/AdminProductApiTest` | Admin product API feature tests |
| `Api/AdminOrderApiTest` | Admin order API feature tests |

---

## 5. Config File Changes

| Config File | Change | Value | Purpose |
|-------------|--------|-------|---------|
| `config/database.php` | SQLite pragmas | WAL, foreign keys, busy_timeout 5000, synchronous normal | Optimized SQLite configuration |
| `config/auth.php` | Customer guard | Add customer guard, customer provider, customer password broker | Customer storefront auth |
| `config/session.php` | Driver | File driver, lifetime 120 | Session configuration |
| `config/cache.php` | Driver | File driver | Cache configuration |
| `config/queue.php` | Driver | Sync driver | Queue configuration |
| `config/filesystems.php` | Public disk | Media storage configuration | Public disk for media |
| `config/logging.php` | JSON channel | Structured JSON channel | Structured logging |

### bootstrap/app.php Changes

- Register middleware aliases: `store.resolve`, `role.check`, `auth:customer`
- Register middleware groups for `storefront` and `admin` route groups
- Configure rate limiters: `login` (5/min per IP), `api.admin` (60/min per token), `api.storefront` (120/min per IP), `checkout` (10/min per session), `search` (30/min per IP), `analytics` (60/min per IP), `webhooks` (100/min per IP)
- Configure exception handling

### Routes Files

| File | Contents |
|------|----------|
| `routes/web.php` | Admin auth routes, admin routes (prefix `/admin`), storefront routes, checkout routes, customer account routes |
| `routes/api.php` | Storefront API (prefix `/api/storefront/v1`), Admin API (prefix `/api/admin/v1`), Webhook receiver routes |
| `routes/console.php` | Scheduled jobs: `CleanupAbandonedCarts` daily, `ExpireAbandonedCheckouts` every 15 minutes, `AggregateAnalytics` daily, `CancelUnpaidBankTransferOrders` daily |

### Service Providers

**AppServiceProvider::boot() responsibilities:**
- Bind services to container (PaymentProvider, CartService, PricingEngine, etc.)
- Register rate limiters
- Register global scopes
- Register model observers (ProductObserver for FTS5 sync)

### Services Directory

| Service | Responsibility |
|---------|---------------|
| `CartService` | Cart CRUD, line management, version control, session binding |
| `CheckoutService` | State machine, transitions, address/shipping/payment coordination |
| `PricingEngine` | Deterministic pricing pipeline: subtotal -> discount -> shipping -> tax -> total |
| `DiscountService` | Discount validation, amount calculation, line allocation |
| `ShippingCalculator` | Zone matching, rate calculation |
| `TaxCalculator` | Tax calculation (exclusive/inclusive), rate lookup |
| `InventoryService` | Reserve, release, commit, restock operations |
| `ProductService` | Product CRUD, status transitions |
| `VariantMatrixService` | Cartesian product generation, variant lifecycle |
| `OrderService` | Order creation from checkout, numbering, inventory commit |
| `RefundService` | Refund creation, provider API, inventory restock |
| `FulfillmentService` | Fulfillment CRUD, tracking, status management |
| `NavigationService` | Menu tree building, URL resolution, caching |
| `SearchService` | FTS5 index management, query execution, autocomplete |
| `AnalyticsService` | Event tracking, daily aggregation |
| `WebhookService` | Event dispatch, HMAC signing, delivery management |
| `Payments\MockPaymentProvider` | In-process mock PSP: credit card (magic numbers), PayPal, bank transfer |

---

## 6. File Count Estimate

| Category | Estimated Files |
|----------|-----------------|
| Migrations | 28-32 |
| Models | 32-36 |
| Livewire Components (Admin) | 28-30 |
| Livewire Components (Storefront) | 15-17 |
| Blade Views (Admin) | 28-30 |
| Blade Views (Storefront) | 18-22 |
| Blade Components (Storefront) | 8-10 |
| Services | 14-16 |
| Policies | 10 |
| Form Requests | 18-20 |
| Jobs | 5 |
| Events | 10 |
| Middleware | 3 |
| Enums | 18-20 |
| Factories | 25-28 |
| Seeders | 20-22 |
| Config changes | 6-7 |
| Routes | 3 |
| Value Objects | 3-4 |
| Contracts/Interfaces | 2-3 |
| Traits/Concerns | 2-3 |
| Scopes | 1 |
| Observers | 1 |
| Support classes | 2-3 |
| Tests (Unit) | 6 |
| Tests (Feature) | 28-30 |
| Tests (Browser) | 18 files (143 tests) |
| CSS/JS | 3-5 |
| **Total** | **~320-380 files** |

---

## 7. Verification Checklist

1. Install Composer dependencies and confirm no errors
2. Install npm dependencies and run the Vite build; confirm it succeeds
3. Run a fresh migration on a clean SQLite database and confirm all migrations complete without errors
4. Run all seeders and confirm demo data is created without errors
5. Run all unit tests and confirm they pass
6. Run all feature tests and confirm they pass
7. Run all browser tests and confirm they pass (requires browser driver)
8. Run the code style formatter/checker and confirm code conforms to project standards
9. Manual smoke: visit the storefront domain and confirm it renders with products
10. Manual smoke: visit the admin login page and confirm it renders; authenticate as the demo admin user
11. Manual smoke: add a product to the cart, proceed through the full checkout flow
12. Manual smoke: in admin, create a product, manage an order, and process a fulfillment
13. List all registered routes and confirm they are correct with no duplicates
14. Run the config cache command and confirm it works (verifying no `env()` calls outside config files)

---

## 8. Seeder Execution Order

Seeders must run in dependency order. The `DatabaseSeeder` should call them sequentially in this order:

1. `OrganizationSeeder`
2. `StoreSeeder`
3. `StoreDomainSeeder`
4. `UserSeeder`
5. `StoreUserSeeder`
6. `StoreSettingsSeeder`
7. `TaxSettingsSeeder`
8. `ShippingSeeder` - creates shipping zones and rates
9. `CollectionSeeder` - creates collections (before products so products can be linked)
10. `ProductSeeder` - creates products with options, variants, inventory, media, and collection associations
11. `DiscountSeeder`
12. `CustomerSeeder` - creates customers and their addresses
13. `OrderSeeder` - creates sample orders with lines, payments, fulfillments
14. `ThemeSeeder` - creates themes with files and settings
15. `PageSeeder`
16. `NavigationSeeder` - creates navigation menus and items
17. `AnalyticsSeeder`
18. `SearchSettingsSeeder`

See spec `07-SEEDERS-AND-TEST-DATA.md` for detailed seeder data definitions.


Input:
const r = await tools.exec_command({cmd:"sed -n '1,520p' specs/09-IMPLEMENTATION-ROADMAP.md","workdir":"/Users/fabianwesner/Herd/shop","yield_time_ms":10000,"max_output_tokens":35000});
text(r.output);


Script completed
Wall time 0.1 seconds
Output:

# 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 |
|-------|-------------------|
| `Product` | `hasMany(ProductVariant)`, `hasMany(ProductOption)`, `hasMany(ProductMedia)`, `belongsToMany(Collection)` via `collection_products` |
| `ProductOption` | `belongsTo(Product)`, `hasMany(ProductOptionValue)` |
| `ProductOptionValue` | `belongsTo(ProductOption)` |
| `ProductVariant` | `belongsTo(Product)`, `hasOne(InventoryItem)`, `belongsToMany(ProductOptionValue)` via `variant_option_values` |
| `InventoryItem` | `belongsTo(ProductVariant)` |
| `Collection` | `belongsToMany(Product)` via `collection_products` |
| `ProductMedia` | `belongsTo(Product)` |

**Enums to create:**

| Enum | Values |
|------|--------|
| `ProductStatus` | `Draft`, `Active`, `Archived` |
| `VariantStatus` | `Active`, `Archived` |
| `CollectionStatus` | `Draft`, `Active`, `Archived` |
| `MediaType` | `Image`, `Video` |
| `MediaStatus` | `Processing`, `Ready`, `Failed` |
| `InventoryPolicy` | `Deny`, `Continue` |

#### Step 2.3: Product Service

**File to create:** `App\Services\ProductService`

| Method | Description |
|--------|-------------|
| `create(Store $store, array $data): Product` | Creates product with nested variants/options |
| `update(Product $product, array $data): Product` | Updates product |
| `transitionStatus(Product $product, ProductStatus $newStatus): void` | Validates transitions per state machine |
| `delete(Product $product): void` | Hard delete only if draft with no order references; otherwise throws |

**File to create:** `App\Services\VariantMatrixService`

| Method | Description |
|--------|-------------|
| `rebuildMatrix(Product $product): void` | Computes cartesian product, creates missing variants, archives orphaned ones |

**File to create:** `App\Support\HandleGenerator`

| Method | Description |
|--------|-------------|
| `generate(string $title, string $table, int $storeId, ?int $excludeId = null): string` | Generates unique slugs |

#### Step 2.4: Inventory Service

**File to create:** `App\Services\InventoryService`

| Method | Description |
|--------|-------------|
| `checkAvailability(InventoryItem $item, int $quantity): bool` | Checks if sufficient available inventory exists |
| `reserve(InventoryItem $item, int $quantity): void` | Increments `quantity_reserved` |
| `release(InventoryItem $item, int $quantity): void` | Decrements `quantity_reserved` |
| `commit(InventoryItem $item, int $quantity): void` | Decrements both `on_hand` and `reserved` |
| `restock(InventoryItem $item, int $quantity): void` | Increments `quantity_on_hand` |

All operations wrapped in database transactions. Throws `InsufficientInventoryException` when policy is `deny` and available < quantity.

#### Step 2.5: Media Upload

**File to create:** `App\Jobs\ProcessMediaUpload`

Requirements:
- Resizes images to standard sizes (thumbnail 150x150, medium 600x600, large 1200x1200)
- Updates `ProductMedia` status from `processing` to `ready` (or `failed`)

Livewire file upload via `WithFileUploads` trait. Stored on local `public` disk.

---

### Phase 3: Themes, Pages, Navigation, Storefront Layout

**Priority:** HIGH - storefront rendering depends on this.

#### Step 3.1: Migrations (Batch 3)

1. `create_themes_table` - FK: `store_id`
2. `create_theme_files_table` - FK: `theme_id`
3. `create_theme_settings_table` - PK: `theme_id`
4. `create_pages_table` - FK: `store_id`
5. `create_navigation_menus_table` - FK: `store_id`
6. `create_navigation_items_table` - FK: `menu_id`

#### Step 3.2: Models

**Files to create:**

| Type | Name | Purpose |
|------|------|---------|
| Model (with migration, factory, seeder) | `Theme` | Store theme entity |
| Model (with migration, factory, seeder) | `ThemeFile` | Individual theme file |
| Model (with migration, factory, seeder) | `ThemeSettings` | Theme configuration |
| Model (with migration, factory, seeder) | `Page` | CMS page |
| Model (with migration, factory, seeder) | `NavigationMenu` | Navigation menu entity |
| Model (with migration, factory, seeder) | `NavigationItem` | Individual navigation item |

**Relationship definitions:**

| Model | Key Relationships |
|-------|-------------------|
| `Theme` | `belongsTo(Store)`, `hasMany(ThemeFile)`, `hasOne(ThemeSettings)` |
| `ThemeFile` | `belongsTo(Theme)` |
| `ThemeSettings` | `belongsTo(Theme)` |
| `Page` | `belongsTo(Store)` |
| `NavigationMenu` | `belongsTo(Store)`, `hasMany(NavigationItem)` |
| `NavigationItem` | `belongsTo(NavigationMenu)` |

**Enums to create:**

| Enum | Values |
|------|--------|
| `ThemeStatus` | `Draft`, `Published` |
| `PageStatus` | `Draft`, `Published`, `Archived` |
| `NavigationItemType` | `Link`, `Page`, `Collection`, `Product` |

#### Step 3.3: Storefront Blade Layout

**Directory structure for `resources/views/storefront/`:**

| Directory | Files |
|-----------|-------|
| `layouts/` | `app.blade.php` |
| `pages/` | `home.blade.php`, `collection.blade.php`, `product.blade.php`, `cart.blade.php`, `search.blade.php`, `page.blade.php` |
| `checkout/` | `index.blade.php`, `confirmation.blade.php` |
| `account/` | `login.blade.php`, `register.blade.php`, `dashboard.blade.php` |
| `account/orders/` | `index.blade.php`, `show.blade.php` |
| `account/addresses/` | `index.blade.php` |
| `errors/` | `404.blade.php`, `503.blade.php` |
| `components/` | `product-card.blade.php`, `price.blade.php`, `badge.blade.php`, `quantity-selector.blade.php`, `address-form.blade.php`, `order-summary.blade.php`, `breadcrumbs.blade.php`, `pagination.blade.php` |

Base layout (`app.blade.php`): header with nav, announcement bar, main content, footer, cart drawer. All with dark mode support via `dark:` prefix.

**ThemeSettings Service:** Singleton registered in `AppServiceProvider`, loads and caches active theme settings for the current store.

#### Step 3.4: Storefront Livewire Components

**Files to create:**

| Component | Purpose |
|-----------|---------|
| `Storefront\Home` | Dynamic sections based on theme settings |
| `Storefront\Collections\Index` | All collections grid |
| `Storefront\Collections\Show` | Product grid with filters/sort/pagination |
| `Storefront\Products\Show` | Variant selection, image gallery, add-to-cart |
| `Storefront\Cart\Show` | Full cart page with line items and totals |
| `Storefront\CartDrawer` | Slide-out cart drawer (always in layout) |
| `Storefront\Search\Index` | Search results with filters |
| `Storefront\Search\Modal` | Search modal with autocomplete |
| `Storefront\Pages\Show` | Static CMS page rendering |

#### Step 3.5: Navigation Service

**File to create:** `App\Services\NavigationService`

| Method | Description |
|--------|-------------|
| `buildTree(NavigationMenu $menu): array` | Builds navigation trees from navigation_menus / navigation_items |
| `resolveUrl(NavigationItem $item): string` | Resolves URLs for page, collection, product type items |

Caches per store with 5-minute TTL.

---

### Phase 4: Cart, Checkout, Discounts, Shipping, Taxes

**Priority:** HIGH - core shopping flow.

#### Step 4.1: Migrations (Batch 4-5)

1. `create_carts_table` - FK: `store_id`, `customer_id`
2. `create_cart_lines_table` - FK: `cart_id`, `variant_id`
3. `create_checkouts_table` - FK: `store_id`, `cart_id`, `customer_id`
4. `create_shipping_zones_table` - FK: `store_id`
5. `create_shipping_rates_table` - FK: `zone_id`
6. `create_tax_settings_table` - PK: `store_id`
7. `create_discounts_table` - FK: `store_id`

#### Step 4.2: Models

**Files to create:**

| Type | Name | Purpose |
|------|------|---------|
| Model (with migration, factory, seeder) | `Cart` | Shopping cart entity |
| Model (with migration, factory, seeder) | `CartLine` | Individual cart line item |
| Model (with migration, factory, seeder) | `Checkout` | Checkout session entity |
| Model (with migration, factory, seeder) | `ShippingZone` | Shipping zone configuration |
| Model (with migration, factory, seeder) | `ShippingRate` | Shipping rate within a zone |
| Model (with migration, factory, seeder) | `TaxSettings` | Per-store tax configuration |
| Model (with migration, factory, seeder) | `Discount` | Discount code or automatic discount |

**Relationship definitions:**

| Model | Key Relationships |
|-------|-------------------|
| `Cart` | `belongsTo(Store)`, `belongsTo(Customer)`, `hasMany(CartLine)`, `hasMany(Checkout)` |
| `CartLine` | `belongsTo(Cart)`, `belongsTo(ProductVariant)` |
| `Checkout` | `belongsTo(Store)`, `belongsTo(Cart)`, `belongsTo(Customer)` |
| `ShippingZone` | `belongsTo(Store)`, `hasMany(ShippingRate)` |
| `ShippingRate` | `belongsTo(ShippingZone)` |
| `TaxSettings` | `belongsTo(Store)` |
| `Discount` | `belongsTo(Store)` |

**Enums to create:**

| Enum | Values |
|------|--------|
| `CartStatus` | `Active`, `Converted`, `Abandoned` |
| `CheckoutStatus` | `Started`, `Addressed`, `ShippingSelected`, `PaymentPending`, `Completed`, `Expired` |
| `DiscountType` | `Code`, `Automatic` |
| `DiscountValueType` | `Percent` (`percent`), `Fixed` (`fixed`), `FreeShipping` (`free_shipping`) -- PascalCase cases backed by lowercase string values stored in DB |
| `DiscountStatus` | `Draft`, `Active`, `Expired`, `Disabled` |
| `ShippingRateType` | `Flat`, `Weight`, `Price`, `Carrier` |
| `TaxMode` | `Manual`, `Provider` |

#### Step 4.3: Cart Service

**File to create:** `App\Services\CartService`

| Method | Description |
|--------|-------------|
| `create(Store, ?Customer): Cart` | Creates cart with store currency, version 1 |
| `addLine(Cart, int $variantId, int $qty): CartLine` | Validates variant/product active, inventory, increments existing line or creates new |
| `updateLineQuantity(Cart, int $lineId, int $qty): CartLine` | Validates quantity, recalculates amounts |
| `removeLine(Cart, int $lineId): void` | Deletes line, increments version |
| `getOrCreateForSession(Store, ?Customer): Cart` | Session-based cart binding |
| `mergeOnLogin(Cart $guest, Cart $customer): Cart` | Merges guest cart into customer cart |

All mutations increment `cart_version`. API clients must send `expected_version` or receive 409 Conflict.

#### Step 4.4: Discount Service

**File to create:** `App\Services\DiscountService`

| Method | Description |
|--------|-------------|
| `validate(string $code, Store $store, Cart $cart): Discount` | Validates code exists, is active, dates valid, usage limit not reached, minimum purchase met |
| `calculate(Discount $discount, int $subtotal, array $lines): DiscountResult` | Calculates amount, allocates proportionally across qualifying lines |

Case-insensitive code lookup. Throws `InvalidDiscountException` with specific reason codes.

#### Step 4.5: Shipping Calculator


Input:
const r = await tools.exec_command({cmd:"sed -n '521,1040p' specs/09-IMPLEMENTATION-ROADMAP.md","workdir":"/Users/fabianwesner/Herd/shop","yield_time_ms":10000,"max_output_tokens":40000});
text(r.output);