content:
     1→# 07 - Seeders and Test Data Specification
     2→
     3→> Complete seeder and factory specification for populating the platform with realistic demo data. Laravel 12, SQLite. All monetary amounts in cents (INTEGER). All seed data supports Playwright E2E tests.
     4→
     5→---
     6→
     7→## 1. DatabaseSeeder Orchestration
     8→
     9→The main `DatabaseSeeder` calls child seeders in a strict order that respects foreign key dependencies. Each seeder targets a specific entity type. The ordering ensures parent records exist before children are created.
    10→
    11→**Execution order:**
    12→
    13→| Step | Seeder Class | Depends On | Purpose |
    14→|------|-------------|------------|---------|
    15→| 1 | OrganizationSeeder | (none) | Creates billing organizations |
    16→| 2 | StoreSeeder | Organizations | Creates stores under organizations |
    17→| 3 | StoreDomainSeeder | Stores | Attaches hostnames to stores |
    18→| 4 | UserSeeder | (none) | Creates admin/staff user accounts |
    19→| 5 | StoreUserSeeder | Stores, Users | Links users to stores with roles (pivot) |
    20→| 6 | StoreSettingsSeeder | Stores | Inserts per-store JSON settings |
    21→| 7 | TaxSettingsSeeder | Stores | Configures tax mode and rates |
    22→| 8 | ShippingSeeder | Stores | Creates shipping zones and rates |
    23→| 9 | CollectionSeeder | Stores | Creates product collections |
    24→| 10 | ProductSeeder | Stores, Collections | Creates products, options, variants, inventory, collection assignments |
    25→| 11 | DiscountSeeder | Stores | Creates discount codes |
    26→| 12 | CustomerSeeder | Stores | Creates customer accounts with addresses |
    27→| 13 | OrderSeeder | Stores, Customers, Products, Variants, Discounts | Creates orders with lines, payments, fulfillments, refunds |
    28→| 14 | ThemeSeeder | Stores | Creates themes with settings |
    29→| 15 | PageSeeder | Stores | Creates content pages |
    30→| 16 | NavigationSeeder | Stores, Collections, Pages | Creates menus linking to collections and pages |
    31→| 17 | AnalyticsSeeder | Stores, Customers | Creates daily aggregates and event stream |
    32→| 18 | SearchSettingsSeeder | Stores | Configures search synonyms and stop words |
    33→
    34→**Dependency diagram (Mermaid):**
    35→
    36→```mermaid
    37→graph TD
    38→    A[OrganizationSeeder] --> B[StoreSeeder]
    39→    B --> C[StoreDomainSeeder]
    40→    B --> F[StoreSettingsSeeder]
    41→    B --> G[TaxSettingsSeeder]
    42→    B --> H[ShippingSeeder]
    43→    B --> I[CollectionSeeder]
    44→    D[UserSeeder] --> E[StoreUserSeeder]
    45→    B --> E
    46→    B --> J[ProductSeeder]
    47→    I --> J
    48→    B --> K[DiscountSeeder]
    49→    B --> L[CustomerSeeder]
    50→    J --> M[OrderSeeder]
    51→    L --> M
    52→    K --> M
    53→    B --> N[ThemeSeeder]
    54→    B --> O[PageSeeder]
    55→    I --> P[NavigationSeeder]
    56→    O --> P
    57→    B --> Q[AnalyticsSeeder]
    58→    L --> Q
    59→    B --> R[SearchSettingsSeeder]
    60→```
    61→
    62→**Running seeders:**
    63→- All seeders: `php artisan db:seed`
    64→- Single seeder: `php artisan db:seed --class=ProductSeeder`
    65→- Fresh database with seed data: `php artisan migrate:fresh --seed`
    66→
    67→---
    68→
    69→## 2. Factory Definitions
    70→
    71→Each factory below lists the model, default field generation rules, named states (overrides), and relationship hooks. The coding agent should create corresponding Laravel factory classes.
    72→
    73→---
    74→
    75→### 2.1 OrganizationFactory
    76→
    77→**Model:** Organization
    78→
    79→**Default definition:**
    80→
    81→| Field | Generation Rule |
    82→|-------|----------------|
    83→| name | Faker company name |
    84→| billing_email | Faker company email |
    85→
    86→**States:** None.
    87→
    88→---
    89→
    90→### 2.2 StoreFactory
    91→
    92→**Model:** Store
    93→
    94→**Default definition:**
    95→
    96→| Field | Generation Rule |
    97→|-------|----------------|
    98→| organization_id | Creates a new Organization via its factory |
    99→| name | Faker company name + " Store" suffix |
   100→| handle | Faker unique slug (2 words) |
   101→| status | "active" |
   102→| default_currency | "EUR" |
   103→| default_locale | "en" |
   104→| timezone | "Europe/Berlin" |
   105→
   106→**States:**
   107→
   108→| State Name | Overrides |
   109→|-----------|-----------|
   110→| `suspended` | status = "suspended" |
   111→
   112→---
   113→
   114→### 2.3 StoreDomainFactory
   115→
   116→**Model:** StoreDomain
   117→
   118→**Default definition:**
   119→
   120→| Field | Generation Rule |
   121→|-------|----------------|
   122→| store_id | Creates a new Store via its factory |
   123→| hostname | Faker unique domain name |
   124→| type | "storefront" |
   125→| is_primary | 1 |
   126→| tls_mode | "managed" |
   127→
   128→**States:**
   129→
   130→| State Name | Overrides |
   131→|-----------|-----------|
   132→| `admin` | type = "admin" |
   133→| `api` | type = "api" |
   134→| `secondary` | is_primary = 0 |
   135→
   136→---
   137→
   138→### 2.4 UserFactory
   139→
   140→**Model:** User
   141→
   142→**Default definition:**
   143→
   144→| Field | Generation Rule |
   145→|-------|----------------|
   146→| email | Faker unique safe email |
   147→| password_hash | bcrypt of "password" |
   148→| name | Faker full name |
   149→| status | "active" |
   150→| last_login_at | Random date within the last 30 days |
   151→
   152→**States:**
   153→
   154→| State Name | Overrides |
   155→|-----------|-----------|
   156→| `disabled` | status = "disabled" |
   157→
   158→---
   159→
   160→### 2.5 ProductFactory
   161→
   162→**Model:** Product
   163→
   164→**Default definition:**
   165→
   166→| Field | Generation Rule |
   167→|-------|----------------|
   168→| store_id | Creates a new Store via its factory |
   169→| title | Faker 3 random words joined |
   170→| handle | URL-slug of the title |
   171→| status | "active" |
   172→| description_html | Faker 2 paragraphs wrapped in `<p>` tags |
   173→| vendor | Faker company name |
   174→| product_type | Random from: Shirts, Pants, Shoes, Accessories, Electronics, Books |
   175→| tags | JSON array of 1-3 random picks from: new, sale, trending, popular, limited |
   176→| published_at | Current timestamp |
   177→
   178→**States:**
   179→
   180→| State Name | Overrides |
   181→|-----------|-----------|
   182→| `draft` | status = "draft", published_at = null |
   183→| `archived` | status = "archived" |
   184→
   185→**Relationship hooks:**
   186→
   187→| Hook Name | Behavior |
   188→|-----------|----------|
   189→| `withVariants(count)` | After creating the product, create `count` ProductVariant records associated with the product |
   190→| `withDefaultVariant(price)` | After creating the product, create one ProductVariant marked as default at the given price in EUR |
   191→
   192→---
   193→
   194→### 2.6 ProductVariantFactory
   195→
   196→**Model:** ProductVariant
   197→
   198→**Default definition:**
   199→
   200→| Field | Generation Rule |
   201→|-------|----------------|
   202→| product_id | Creates a new Product via its factory |
   203→| sku | Faker unique, pattern: "SKU-####-???" (digits and letters) |
   204→| barcode | Faker EAN-13 |
   205→| price_amount | Random integer 999-19999 (9.99 to 199.99 EUR) |
   206→| compare_at_amount | null |
   207→| currency | "EUR" |
   208→| weight_g | Random integer 100-5000 |
   209→| requires_shipping | 1 |
   210→| is_default | 0 |
   211→| position | 0 |
   212→| status | "active" |
   213→
   214→**States:**
   215→
   216→| State Name | Overrides |
   217→|-----------|-----------|
   218→| `onSale` | compare_at_amount = random 20000-39999, price_amount = random 9999-19999 |
   219→| `digital` | requires_shipping = 0, weight_g = 0 |
   220→| `default` | is_default = 1 |
   221→| `archived` | status = "archived" |
   222→
   223→---
   224→
   225→### 2.7 InventoryItemFactory
   226→
   227→**Model:** InventoryItem
   228→
   229→**Default definition:**
   230→
   231→| Field | Generation Rule |
   232→|-------|----------------|
   233→| store_id | Creates a new Store via its factory |
   234→| variant_id | Creates a new ProductVariant via its factory |
   235→| quantity_on_hand | Random integer 0-100 |
   236→| quantity_reserved | 0 |
   237→| policy | "deny" |
   238→
   239→**States:**
   240→
   241→| State Name | Overrides |
   242→|-----------|-----------|
   243→| `outOfStock` | quantity_on_hand = 0 |
   244→| `continuePolicy` | policy = "continue" |
   245→| `lowStock` | quantity_on_hand = random 1-3 |
   246→
   247→---
   248→
   249→### 2.8 CollectionFactory
   250→
   251→**Model:** Collection
   252→
   253→**Default definition:**
   254→
   255→| Field | Generation Rule |
   256→|-------|----------------|
   257→| store_id | Creates a new Store via its factory |
   258→| title | Faker 2 random words joined |
   259→| handle | URL-slug of the title |
   260→| description_html | Faker sentence wrapped in `<p>` tags |
   261→| type | "manual" |
   262→| status | "active" |
   263→
   264→**States:**
   265→
   266→| State Name | Overrides |
   267→|-----------|-----------|
   268→| `draft` | status = "draft" |
   269→| `archived` | status = "archived" |
   270→| `automated` | type = "automated" |
   271→
   272→---
   273→
   274→### 2.9 CartFactory
   275→
   276→**Model:** Cart
   277→
   278→**Default definition:**
   279→
   280→| Field | Generation Rule |
   281→|-------|----------------|
   282→| store_id | Creates a new Store via its factory |
   283→| customer_id | null |
   284→| currency | "EUR" |
   285→| cart_version | 1 |
   286→| status | "active" |
   287→
   288→**States:**
   289→
   290→| State Name | Overrides |
   291→|-----------|-----------|
   292→| `forCustomer` | customer_id = creates a new Customer via its factory |
   293→| `converted` | status = "converted" |
   294→| `abandoned` | status = "abandoned" |
   295→
   296→---
   297→
   298→### 2.10 CartLineFactory
   299→
   300→**Model:** CartLine
   301→
   302→**Default definition:**
   303→
   304→| Field | Generation Rule |
   305→|-------|----------------|
   306→| cart_id | Creates a new Cart via its factory |
   307→| variant_id | Creates a new ProductVariant via its factory |
   308→| quantity | Random 1-5 |
   309→| unit_price_amount | Random 999-19999 |
   310→| line_subtotal_amount | Computed: unit_price_amount * quantity |
   311→| line_discount_amount | 0 |
   312→| line_total_amount | Computed: line_subtotal_amount - line_discount_amount |
   313→
   314→**States:** None.
   315→
   316→---
   317→
   318→### 2.11 CheckoutFactory
   319→
   320→**Model:** Checkout
   321→
   322→**Default definition:**
   323→
   324→| Field | Generation Rule |
   325→|-------|----------------|
   326→| store_id | Creates a new Store via its factory |
   327→| cart_id | Creates a new Cart via its factory |
   328→| customer_id | null |
   329→| status | "started" |
   330→| email | Faker safe email |
   331→| shipping_address_json | JSON object with Faker first_name, last_name, address1, city, country_code "DE", zip |
   332→| billing_address_json | null |
   333→| shipping_method_id | null |
   334→| payment_method | null |
   335→| discount_code | null |
   336→| tax_provider_snapshot_json | null |
   337→| totals_json | null |
   338→| expires_at | 24 hours from now |
   339→
   340→**States:**
   341→
   342→| State Name | Overrides |
   343→|-----------|-----------|
   344→| `completed` | status = "completed" |
   345→| `expired` | status = "expired", expires_at = 1 hour ago |
   346→| `withCreditCard` | payment_method = "credit_card" |
   347→| `withPaypal` | payment_method = "paypal" |
   348→| `withBankTransfer` | payment_method = "bank_transfer" |
   349→
   350→---
   351→
   352→### 2.12 OrderFactory
   353→
   354→**Model:** Order
   355→
   356→**Default definition:**
   357→
   358→| Field | Generation Rule |
   359→|-------|----------------|
   360→| store_id | Creates a new Store via its factory |
   361→| customer_id | Creates a new Customer via its factory |
   362→| order_number | "#" + Faker unique integer 1001-9999 |
   363→| payment_method | "credit_card" |
   364→| status | "paid" |
   365→| financial_status | "paid" |
   366→| fulfillment_status | "unfulfilled" |
   367→| currency | "EUR" |
   368→| subtotal_amount | 4998 |
   369→| discount_amount | 0 |
   370→| shipping_amount | 499 |
   371→| tax_amount | 798 |
   372→| total_amount | 5497 |
   373→| email | Faker safe email |
   374→| billing_address_json | JSON address object with German Faker data |
   375→| shipping_address_json | JSON address object with German Faker data |
   376→| placed_at | Current timestamp |
   377→
   378→**States:**
   379→
   380→| State Name | Overrides |
   381→|-----------|-----------|
   382→| `pending` | status = "pending", financial_status = "pending" |
   383→| `pendingBankTransfer` | status = "pending", financial_status = "pending", payment_method = "bank_transfer" |
   384→| `fulfilled` | status = "fulfilled", fulfillment_status = "fulfilled" |
   385→| `cancelled` | status = "cancelled", financial_status = "refunded" |
   386→| `refunded` | status = "refunded", financial_status = "refunded" |
   387→| `partiallyFulfilled` | fulfillment_status = "partial" |
   388→| `creditCard` | payment_method = "credit_card" |
   389→| `paypal` | payment_method = "paypal" |
   390→| `bankTransfer` | payment_method = "bank_transfer" |
   391→
   392→---
   393→
   394→### 2.13 OrderLineFactory
   395→
   396→**Model:** OrderLine
   397→
   398→**Default definition:**
   399→
   400→| Field | Generation Rule |
   401→|-------|----------------|
   402→| order_id | Creates a new Order via its factory |
   403→| product_id | Creates a new Product via its factory |
   404→| variant_id | Creates a new ProductVariant via its factory |
   405→| title_snapshot | Faker 3 words |
   406→| sku_snapshot | Faker pattern "SKU-####-???" |
   407→| quantity | Random 1-3 |
   408→| unit_price_amount | Random 999-19999 |
   409→| total_amount | Computed: unit_price_amount * quantity |
   410→| tax_lines_json | Empty JSON array |
   411→| discount_allocations_json | Empty JSON array |
   412→
   413→**States:** None.
   414→
   415→---
   416→
   417→### 2.14 PaymentFactory
   418→
   419→**Model:** Payment
   420→
   421→**Default definition:**
   422→
   423→| Field | Generation Rule |
   424→|-------|----------------|
   425→| order_id | Creates a new Order via its factory |
   426→| provider | "mock" |
   427→| method | "credit_card" |
   428→| provider_payment_id | "mock_" + Faker 20 random alphanumeric characters |
   429→| status | "captured" |
   430→| amount | Random 999-99999 |
   431→| currency | "EUR" |
   432→| raw_json_encrypted | null |
   433→
   434→**States:**
   435→
   436→| State Name | Overrides |
   437→|-----------|-----------|
   438→| `pending` | status = "pending" |
   439→| `failed` | status = "failed" |
   440→| `refunded` | status = "refunded" |
   441→| `creditCard` | method = "credit_card" |
   442→| `paypal` | method = "paypal" |
   443→| `bankTransfer` | method = "bank_transfer" |
   444→
   445→---
   446→
   447→### 2.15 RefundFactory
   448→
   449→**Model:** Refund
   450→
   451→**Default definition:**
   452→
   453→| Field | Generation Rule |
   454→|-------|----------------|
   455→| order_id | Creates a new Order via its factory |
   456→| payment_id | Creates a new Payment via its factory |
   457→| amount | Random 999-19999 |
   458→| reason | Faker sentence |
   459→| status | "processed" |
   460→| provider_refund_id | "mock_re_" + Faker 20 random alphanumeric characters |
   461→
   462→**States:**
   463→
   464→| State Name | Overrides |
   465→|-----------|-----------|
   466→| `pending` | status = "pending", provider_refund_id = null |
   467→| `failed` | status = "failed" |
   468→
   469→---
   470→
   471→### 2.16 FulfillmentFactory
   472→
   473→**Model:** Fulfillment
   474→
   475→**Default definition:**
   476→
   477→| Field | Generation Rule |
   478→|-------|----------------|
   479→| order_id | Creates a new Order via its factory |
   480→| status | "shipped" |
   481→| tracking_company | Random from: DHL, UPS, FedEx, DPD |
   482→| tracking_number | Faker pattern "??########" (2 letters + 8 digits) |
   483→| tracking_url | "https://tracking.example.com/" + tracking_number |
   484→| shipped_at | Current timestamp |
   485→
   486→**States:**
   487→
   488→| State Name | Overrides |
   489→|-----------|-----------|
   490→| `pending` | status = "pending", tracking_number = null, tracking_url = null, shipped_at = null |
   491→| `delivered` | status = "delivered" |
   492→
   493→---
   494→
   495→### 2.16b FulfillmentLineFactory
   496→
   497→**Model:** FulfillmentLine
   498→
   499→**Default definition:**
   500→
   501→| Field | Rule | Notes |
   502→|-------|------|-------|
   503→| fulfillment_id | FK | Parent fulfillment |
   504→| order_line_id | FK | The order line being fulfilled |
   505→| quantity | integer, 1..max | Quantity fulfilled for this line (must not exceed order line quantity) |
   506→
   507→**States:** None.
   508→
   509→---
   510→
   511→### 2.17 CustomerFactory
   512→
   513→**Model:** Customer
   514→
   515→**Default definition:**
   516→
   517→| Field | Generation Rule |
   518→|-------|----------------|
   519→| store_id | Creates a new Store via its factory |
   520→| email | Faker unique safe email |
   521→| password_hash | bcrypt of "password" |
   522→| name | Faker full name |
   523→| marketing_opt_in | 30% chance of 1, otherwise 0 |
   524→
   525→**States:**
   526→
   527→| State Name | Overrides |
   528→|-----------|-----------|
   529→| `guest` | password_hash = null |
   530→| `optedInMarketing` | marketing_opt_in = 1 |
   531→
   532→---
   533→
   534→### 2.18 CustomerAddressFactory
   535→
   536→**Model:** CustomerAddress
   537→
   538→**Default definition:**
   539→
   540→| Field | Generation Rule |
   541→|-------|----------------|
   542→| customer_id | Creates a new Customer via its factory |
   543→| label | Random from: Home, Work, Other |
   544→| address_json | JSON object (see Address JSON Structure in Section 6) |
   545→| is_default | 0 |
   546→
   547→**States:**
   548→
   549→| State Name | Overrides |
   550→|-----------|-----------|
   551→| `default` | is_default = 1 |
   552→
   553→---
   554→
   555→### 2.19 DiscountFactory
   556→
   557→**Model:** Discount
   558→
   559→**Default definition:**
   560→
   561→| Field | Generation Rule |
   562→|-------|----------------|
   563→| store_id | Creates a new Store via its factory |
   564→| type | "code" |
   565→| code | Faker unique uppercase pattern "????##" |
   566→| value_type | "percent" |
   567→| value_amount | 10 |
   568→| starts_at | 1 month ago |
   569→| ends_at | 1 year from now |
   570→| usage_limit | null |
   571→| usage_count | 0 |
   572→| rules_json | Empty JSON object |
   573→| status | "active" |
   574→
   575→**Note on value_amount for percent type:** Stored as whole number percentages. 10 = 10%, 20 = 20%.
   576→
   577→**States:**
   578→
   579→| State Name | Overrides |
   580→|-----------|-----------|
   581→| `fixed(amountCents)` | value_type = "fixed", value_amount = amountCents |
   582→| `freeShipping` | value_type = "free_shipping", value_amount = 0 |
   583→| `expired` | starts_at = 1 year ago, ends_at = yesterday, status = "expired" |
   584→| `maxedOut` | usage_limit = 5, usage_count = 5 |
   585→| `automatic` | type = "automatic", code = null |
   586→| `draft` | status = "draft" |
   587→| `disabled` | status = "disabled", starts_at = past date |
   588→
   589→---
   590→
   591→### 2.20 ShippingZoneFactory
   592→
   593→**Model:** ShippingZone
   594→
   595→**Default definition:**
   596→
   597→| Field | Generation Rule |
   598→|-------|----------------|
   599→| store_id | Creates a new Store via its factory |
   600→| name | Faker country name |
   601→| countries_json | JSON array: ["DE"] |
   602→| regions_json | Empty JSON array |
   603→
   604→**States:** None.
   605→
   606→---
   607→
   608→### 2.21 ShippingRateFactory
   609→
   610→**Model:** ShippingRate
   611→
   612→**Default definition:**
   613→
   614→| Field | Generation Rule |
   615→|-------|----------------|
   616→| zone_id | Creates a new ShippingZone via its factory |
   617→| name | Random from: Standard, Express, Economy |
   618→| type | "flat" |
   619→| config_json | JSON object with amount = 499 |
   620→| is_active | 1 |
   621→
   622→**States:**
   623→
   624→| State Name | Overrides |
   625→|-----------|-----------|
   626→| `inactive` | is_active = 0 |
   627→| `weightBased` | type = "weight", config_json has ranges array with tiers: 0-500g = 399, 501-2000g = 699, 2001g+ = 1299 |
   628→
   629→---
   630→
   631→### 2.22 ThemeFactory
   632→
   633→**Model:** Theme
   634→
   635→**Default definition:**
   636→
   637→| Field | Generation Rule |
   638→|-------|----------------|
   639→| store_id | Creates a new Store via its factory |
   640→| name | "Default Theme" |
   641→| version | "1.0.0" |
   642→| status | "published" |
   643→| published_at | Current timestamp |
   644→
   645→**States:**
   646→
   647→| State Name | Overrides |
   648→|-----------|-----------|
   649→| `draft` | status = "draft", published_at = null |
   650→
   651→---
   652→
   653→### 2.23 PageFactory
   654→
   655→**Model:** Page
   656→
   657→**Default definition:**
   658→
   659→| Field | Generation Rule |
   660→|-------|----------------|
   661→| store_id | Creates a new Store via its factory |
   662→| title | Faker 3 random words |
   663→| handle | URL-slug of the title |
   664→| body_html | Faker heading + 3 paragraphs in HTML tags |
   665→| status | "published" |
   666→| published_at | Current timestamp |
   667→
   668→**States:**
   669→
   670→| State Name | Overrides |
   671→|-----------|-----------|
   672→| `draft` | status = "draft", published_at = null |
   673→| `archived` | status = "archived" |
   674→
   675→---
   676→
   677→### 2.24 NavigationMenuFactory
   678→
   679→**Model:** NavigationMenu
   680→
   681→**Default definition:**
   682→
   683→| Field | Generation Rule |
   684→|-------|----------------|
   685→| store_id | Creates a new Store via its factory |
   686→| handle | Faker unique slug (2 words) |
   687→| title | Faker 2 words |
   688→
   689→**States:** None.
   690→
   691→---
   692→
   693→### 2.25 NavigationItemFactory
   694→
   695→**Model:** NavigationItem
   696→
   697→**Default definition:**
   698→
   699→| Field | Generation Rule |
   700→|-------|----------------|
   701→| menu_id | Creates a new NavigationMenu via its factory |
   702→| type | "link" |
   703→| label | Faker 2 words |
   704→| url | "/" |
   705→| resource_id | null |
   706→| position | 0 |
   707→
   708→**States:**
   709→
   710→| State Name | Overrides |
   711→|-----------|-----------|
   712→| `page(pageId)` | type = "page", url = null, resource_id = pageId |
   713→| `collection(collectionId)` | type = "collection", url = null, resource_id = collectionId |
   714→| `product(productId)` | type = "product", url = null, resource_id = productId |
   715→
   716→---
   717→
   718→### 2.26 AnalyticsEventFactory
   719→
   720→**Model:** AnalyticsEvent
   721→
   722→**Default definition:**
   723→
   724→| Field | Generation Rule |
   725→|-------|----------------|
   726→| store_id | Creates a new Store via its factory |
   727→| type | Random from: page_view, product_view, add_to_cart, remove_from_cart, checkout_started, checkout_completed, search |
   728→| session_id | Faker UUID |
   729→| customer_id | null |
   730→| properties_json | JSON with url (Faker slug) and referrer (40% chance Faker URL, otherwise null) |
   731→| created_at | Random timestamp within last 7 days |
   732→
   733→**States:**
   734→
   735→| State Name | Overrides |
   736→|-----------|-----------|
   737→| `pageView` | type = "page_view" |
   738→| `productView` | type = "product_view", properties_json includes product_id and product_title |
   739→| `addToCart` | type = "add_to_cart", properties_json includes variant_id and quantity |
   740→
   741→---
   742→
   743→## 3. Demo Seed Scenario (Exact Data)
   744→
   745→All seeders below create deterministic, named records required by E2E tests. References like "Product 1" in order lines refer to products by their seed position.
   746→
   747→---
   748→
   749→### 3.1 OrganizationSeeder
   750→
   751→Creates one organization.
   752→
   753→| Field | Value |
   754→|-------|-------|
   755→| name | Acme Corp |
   756→| billing_email | billing@acme.test |
   757→
   758→---
   759→
   760→### 3.2 StoreSeeder
   761→
   762→Creates two stores under "Acme Corp".
   763→
   764→**Store 1: Acme Fashion**
   765→
   766→| Field | Value |
   767→|-------|-------|
   768→| name | Acme Fashion |
   769→| handle | acme-fashion |
   770→| status | active |
   771→| default_currency | EUR |
   772→| default_locale | en |
   773→| timezone | Europe/Berlin |
   774→
   775→**Store 2: Acme Electronics**
   776→
   777→| Field | Value |
   778→|-------|-------|
   779→| name | Acme Electronics |
   780→| handle | acme-electronics |
   781→| status | active |
   782→| default_currency | EUR |
   783→| default_locale | en |
   784→| timezone | Europe/Berlin |
   785→
   786→---
   787→
   788→### 3.3 StoreDomainSeeder
   789→
   790→**Acme Fashion domains:**
   791→
   792→| Hostname | Type | is_primary | tls_mode |
   793→|----------|------|-----------|----------|
   794→| acme-fashion.test | storefront | 1 | managed |
   795→| admin.acme-fashion.test | admin | 0 | managed |
   796→
   797→**Note:** The admin domain (`admin.acme-fashion.test`) routes HTTP requests to the admin panel. However, the actual store context within the admin panel is determined by the session key `current_store_id`, set after login or via the store-switcher. The admin domain itself does not determine store scope.
   798→
   799→**Acme Electronics domains:**
   800→
   801→| Hostname | Type | is_primary | tls_mode |
   802→|----------|------|-----------|----------|
   803→| acme-electronics.test | storefront | 1 | managed |
   804→
   805→---
   806→
   807→### 3.4 UserSeeder
   808→
   809→| Email | Name | Password (plaintext, stored as bcrypt hash) | Status | last_login_at |
   810→|-------|------|----------------------------------------------|--------|---------------|
   811→| admin@acme.test | Admin User | password | active | now |
   812→| staff@acme.test | Staff User | password | active | 2 days ago |
   813→| support@acme.test | Support User | password | active | 1 day ago |
   814→| manager@acme.test | Store Manager | password | active | 1 day ago |
   815→| admin2@acme.test | Admin Two | password | active | 1 day ago |
   816→
   817→---
   818→
   819→### 3.5 StoreUserSeeder
   820→
   821→| User Email | Store | Role |
   822→|------------|-------|------|
   823→| admin@acme.test | Acme Fashion | owner |
   824→| staff@acme.test | Acme Fashion | staff |
   825→| support@acme.test | Acme Fashion | support |
   826→| manager@acme.test | Acme Fashion | admin |
   827→| admin2@acme.test | Acme Electronics | owner |
   828→
   829→---
   830→
   831→### 3.6 StoreSettingsSeeder
   832→
   833→**Acme Fashion - settings_json contents:**
   834→
   835→| Setting Key | Value |
   836→|-------------|-------|
   837→| store_name | Acme Fashion |
   838→| contact_email | hello@acme-fashion.test |
   839→| order_number_prefix | # |
   840→| order_number_start | 1001 |
   841→
   842→**Acme Electronics - settings_json contents:**
   843→
   844→| Setting Key | Value |
   845→|-------------|-------|
   846→| store_name | Acme Electronics |
   847→| contact_email | hello@acme-electronics.test |
   848→| order_number_prefix | # |
   849→| order_number_start | 5001 |
   850→
   851→---
   852→
   853→### 3.7 TaxSettingsSeeder
   854→
   855→**Acme Fashion:**
   856→
   857→| Field | Value |
   858→|-------|-------|
   859→| mode | manual |
   860→| provider | none |
   861→| prices_include_tax | 1 (prices shown to customers are gross/tax-inclusive) |
   862→| config_json | default_rate_bps: 1900 |
   863→
   864→Tax rate: 19% (1900 basis points) applied to all zones.
   865→
   866→**Acme Electronics:** Same as Acme Fashion.
   867→
   868→---
   869→
   870→### 3.8 ShippingSeeder
   871→
   872→**Acme Fashion - Shipping Zones and Rates:**
   873→
   874→**Zone 1: "Domestic"**
   875→- countries_json: ["DE"]
   876→- regions_json: []
   877→
   878→| Rate Name | Type | config_json (amount in cents) | is_active |
   879→|-----------|------|-------------------------------|-----------|
   880→| Standard Shipping | flat | amount: 499 (4.99 EUR) | 1 |
   881→| Express Shipping | flat | amount: 999 (9.99 EUR) | 1 |
   882→
   883→**Zone 2: "EU"**
   884→- countries_json: ["AT", "FR", "IT", "ES", "NL", "BE", "PL"]
   885→- regions_json: []
   886→
   887→| Rate Name | Type | config_json (amount in cents) | is_active |
   888→|-----------|------|-------------------------------|-----------|
   889→| EU Standard | flat | amount: 899 (8.99 EUR) | 1 |
   890→
   891→**Zone 3: "Rest of World"**
   892→- countries_json: ["US", "GB", "CA", "AU"]
   893→- regions_json: []
   894→
   895→| Rate Name | Type | config_json (amount in cents) | is_active |
   896→|-----------|------|-------------------------------|-----------|
   897→| International | flat | amount: 1499 (14.99 EUR) | 1 |
   898→
   899→**Acme Electronics - One zone:**
   900→
   901→**Zone: "Germany"**
   902→- countries_json: ["DE"]
   903→
   904→| Rate Name | Type | config_json | is_active |
   905→|-----------|------|-------------|-----------|
   906→| Standard | flat | amount: 0 (free) | 1 |
   907→
   908→---
   909→
   910→### 3.9 CollectionSeeder
   911→
   912→**Acme Fashion - 4 collections:**
   913→
   914→| # | Title | Handle | Type | Status | description_html |
   915→|---|-------|--------|------|--------|------------------|
   916→| 1 | New Arrivals | new-arrivals | manual | active | "Discover the latest additions to our store." in `<p>` tag |
   917→| 2 | T-Shirts | t-shirts | manual | active | "Premium cotton tees for every occasion." in `<p>` tag |
   918→| 3 | Pants & Jeans | pants-jeans | manual | active | "Find the perfect fit from our denim and trouser range." in `<p>` tag |
   919→| 4 | Sale | sale | manual | active | "Great deals on selected items." in `<p>` tag |
   920→
   921→**Acme Electronics - 2 collections:**
   922→
   923→| # | Title | Handle | Type | Status |
   924→|---|-------|--------|------|--------|
   925→| 1 | Featured | featured | manual | active |
   926→| 2 | Accessories | accessories | manual | active |
   927→
   928→---
   929→
   930→### 3.10 ProductSeeder
   931→
   932→#### Acme Fashion - 20 Products
   933→
   934→For each product the seeder creates the full entity graph: product record, product_options, product_option_values, product_variants (with variant_option_values pivot entries), and inventory_items.
   935→
   936→---
   937→
   938→**Product 1: "Classic Cotton T-Shirt"**
   939→
   940→| Field | Value |
   941→|-------|-------|
   942→| handle | classic-cotton-t-shirt |
   943→| status | active |
   944→| vendor | Acme Basics |
   945→| product_type | T-Shirts |
   946→| tags | ["new", "popular"] |
   947→| description_html | "A timeless classic cotton t-shirt. Comfortable, breathable, and perfect for everyday wear." in `<p>` tag |
   948→| published_at | now |
   949→
   950→Collections: New Arrivals, T-Shirts
   951→
   952→Options and values:
   953→
   954→| Option Name | Values (in position order) |
   955→|-------------|---------------------------|
   956→| Size | S, M, L, XL |
   957→| Color | White, Black, Navy |
   958→
   959→Variants (12 total - all size x color combinations):
   960→- SKU pattern: ACME-CTSH-{SIZE}-{COLOR} (e.g. ACME-CTSH-S-WHT, ACME-CTSH-S-BLK, etc.)
   961→- First variant (S/White) is marked is_default = 1
   962→- Position increments 0 through 11
   963→
   964→| Per-variant field | Value |
   965→|-------------------|-------|
   966→| price_amount | 2499 (24.99 EUR) |
   967→| compare_at_amount | null |
   968→| currency | EUR |
   969→| weight_g | 200 |
   970→| requires_shipping | 1 |
   971→
   972→Inventory per variant: quantity_on_hand = 15, policy = "deny"
   973→
   974→---
   975→
   976→**Product 2: "Premium Slim Fit Jeans"**
   977→
   978→| Field | Value |
   979→|-------|-------|
   980→| handle | premium-slim-fit-jeans |
   981→| status | active |
   982→| vendor | Acme Denim |
   983→| product_type | Pants |
   984→| tags | ["new", "sale"] |
   985→| description_html | "Slim fit jeans crafted from premium stretch denim. Comfortable all-day wear with a modern silhouette." in `<p>` tag |
   986→| published_at | now |
   987→
   988→Collections: New Arrivals, Pants & Jeans, Sale
   989→
   990→Options and values:
   991→
   992→| Option Name | Values |
   993→|-------------|--------|
   994→| Size | 28, 30, 32, 34, 36 |
   995→| Color | Blue, Black |
   996→
   997→Variants (10 total): First variant (28/Blue) is default.
   998→
   999→| Per-variant field | Value |
  1000→|-------------------|-------|
  1001→| price_amount | 7999 (79.99 EUR) |
  1002→| compare_at_amount | 9999 (99.99 EUR - on sale) |
  1003→| weight_g | 800 |
  1004→| requires_shipping | 1 |
  1005→
  1006→Inventory per variant: quantity_on_hand = 8, policy = "deny"
  1007→
  1008→---
  1009→
  1010→**Product 3: "Organic Hoodie"**
  1011→
  1012→| Field | Value |
  1013→|-------|-------|
  1014→| handle | organic-hoodie |
  1015→| status | active |
  1016→| vendor | Acme Basics |
  1017→| product_type | Hoodies |
  1018→| tags | ["new", "trending"] |
  1019→| description_html | "Made from 100% organic cotton. Warm, soft, and sustainably produced." |
  1020→| published_at | now |
  1021→
  1022→Collections: New Arrivals
  1023→
  1024→Options: Size (S, M, L, XL)
  1025→
  1026→Variants (4 total): price_amount = 5999, weight_g = 500, inventory = 20 each (deny)
  1027→
  1028→---
  1029→
  1030→**Product 4: "Leather Belt"**
  1031→
  1032→| Field | Value |
  1033→|-------|-------|
  1034→| handle | leather-belt |
  1035→| status | active |
  1036→| vendor | Acme Accessories |
  1037→| product_type | Accessories |
  1038→| tags | ["popular"] |
  1039→| description_html | "Genuine leather belt with brushed metal buckle. A wardrobe essential." |
  1040→| published_at | now |
  1041→
  1042→Collections: (none)
  1043→
  1044→Options: Size (S/M, L/XL), Color (Brown, Black)
  1045→
  1046→Variants (4 total): price_amount = 3499, weight_g = 150, inventory = 25 each (deny)
  1047→
  1048→---
  1049→
  1050→**Product 5: "Running Sneakers"**
  1051→
  1052→| Field | Value |
  1053→|-------|-------|
  1054→| handle | running-sneakers |
  1055→| status | active |
  1056→| vendor | Acme Sport |
  1057→| product_type | Shoes |
  1058→| tags | ["trending"] |
  1059→| description_html | "Lightweight running sneakers with responsive cushioning and breathable mesh upper." |
  1060→| published_at | now |
  1061→
  1062→Collections: New Arrivals
  1063→
  1064→Options: Size (EU 38, EU 39, EU 40, EU 41, EU 42, EU 43, EU 44), Color (White, Black)
  1065→
  1066→Variants (14 total): price_amount = 11999, weight_g = 600, inventory = 5 each (deny) - LOW STOCK
  1067→
  1068→---
  1069→
  1070→**Product 6: "Graphic Print Tee"**
  1071→
  1072→| Field | Value |
  1073→|-------|-------|
  1074→| handle | graphic-print-tee |
  1075→| status | active |
  1076→| vendor | Acme Basics |
  1077→| product_type | T-Shirts |
  1078→| tags | ["new"] |
  1079→| description_html | "Bold graphic print on soft cotton. Express yourself with this statement piece." |
  1080→| published_at | now |
  1081→
  1082→Collections: T-Shirts
  1083→
  1084→Options: Size (S, M, L, XL)
  1085→
  1086→Variants (4 total): price_amount = 2999, weight_g = 210, inventory = 18 each (deny)
  1087→
  1088→---
  1089→
  1090→**Product 7: "V-Neck Linen Tee"**
  1091→
  1092→| Field | Value |
  1093→|-------|-------|
  1094→| handle | v-neck-linen-tee |
  1095→| status | active |
  1096→| vendor | Acme Basics |
  1097→| product_type | T-Shirts |
  1098→| tags | ["popular"] |
  1099→| description_html | "Lightweight linen blend v-neck. Perfect for warm summer days." |
  1100→| published_at | now |
  1101→
  1102→Collections: T-Shirts
  1103→
  1104→Options: Size (S, M, L), Color (Beige, Olive, Sky Blue)
  1105→
  1106→Variants (9 total): price_amount = 3499, weight_g = 180, inventory = 12 each (deny)
  1107→
  1108→---
  1109→
  1110→**Product 8: "Striped Polo Shirt"**
  1111→
  1112→| Field | Value |
  1113→|-------|-------|
  1114→| handle | striped-polo-shirt |
  1115→| status | active |
  1116→| vendor | Acme Basics |
  1117→| product_type | T-Shirts |
  1118→| tags | ["sale"] |
  1119→| description_html | "Classic striped polo with a modern relaxed fit. Knitted collar and two-button placket." |
  1120→| published_at | now |
  1121→
  1122→Collections: T-Shirts, Sale
  1123→
  1124→Options: Size (S, M, L, XL)
  1125→
  1126→Variants (4 total): price_amount = 2799, compare_at_amount = 3999 (on sale), weight_g = 250, inventory = 10 each (deny)
  1127→
  1128→---
  1129→
  1130→**Product 9: "Cargo Pants"**
  1131→
  1132→| Field | Value |
  1133→|-------|-------|
  1134→| handle | cargo-pants |
  1135→| status | active |
  1136→| vendor | Acme Workwear |
  1137→| product_type | Pants |
  1138→| tags | ["popular"] |
  1139→| description_html | "Utility cargo pants with multiple pockets. Durable cotton twill construction." |
  1140→| published_at | now |
  1141→
  1142→Collections: Pants & Jeans
  1143→
  1144→Options: Size (30, 32, 34, 36), Color (Khaki, Olive, Black)
  1145→
  1146→Variants (12 total): price_amount = 5499, weight_g = 700, inventory = 14 each (deny)
  1147→
  1148→---
  1149→
  1150→**Product 10: "Chino Shorts"**
  1151→
  1152→| Field | Value |
  1153→|-------|-------|
  1154→| handle | chino-shorts |
  1155→| status | active |
  1156→| vendor | Acme Basics |
  1157→| product_type | Pants |
  1158→| tags | ["new", "trending"] |
  1159→| description_html | "Tailored chino shorts. Comfortable stretch fabric with a clean silhouette." |
  1160→| published_at | now |
  1161→
  1162→Collections: Pants & Jeans, New Arrivals
  1163→
  1164→Options: Size (30, 32, 34, 36), Color (Navy, Sand)
  1165→
  1166→Variants (8 total): price_amount = 3999, weight_g = 350, inventory = 16 each (deny)
  1167→
  1168→---
  1169→
  1170→**Product 11: "Wide Leg Trousers"**
  1171→
  1172→| Field | Value |
  1173→|-------|-------|
  1174→| handle | wide-leg-trousers |
  1175→| status | active |
  1176→| vendor | Acme Denim |
  1177→| product_type | Pants |
  1178→| tags | ["sale"] |
  1179→| description_html | "Relaxed wide leg trousers with a high waist. Flowing drape in premium woven fabric." |
  1180→| published_at | now |
  1181→
  1182→Collections: Pants & Jeans, Sale
  1183→
  1184→Options: Size (S, M, L)
  1185→
  1186→Variants (3 total): price_amount = 4999, compare_at_amount = 6999 (on sale), weight_g = 550, inventory = 7 each (deny)
  1187→
  1188→---
  1189→
  1190→**Product 12: "Wool Scarf"**
  1191→
  1192→| Field | Value |
  1193→|-------|-------|
  1194→| handle | wool-scarf |
  1195→| status | active |
  1196→| vendor | Acme Accessories |
  1197→| product_type | Accessories |
  1198→| tags | ["popular"] |
  1199→| description_html | "Warm merino wool scarf. Soft hand feel, naturally breathable and temperature regulating." |
  1200→| published_at | now |
  1201→
  1202→Collections: (none)
  1203→
  1204→Options: Color (Grey, Burgundy, Navy)
  1205→
  1206→Variants (3 total): price_amount = 2999, weight_g = 120, inventory = 30 each (deny)
  1207→
  1208→---
  1209→
  1210→**Product 13: "Canvas Tote Bag"**
  1211→
  1212→| Field | Value |
  1213→|-------|-------|
  1214→| handle | canvas-tote-bag |
  1215→| status | active |
  1216→| vendor | Acme Accessories |
  1217→| product_type | Accessories |
  1218→| tags | ["trending"] |
  1219→| description_html | "Heavy-duty canvas tote bag with reinforced handles. Spacious enough for daily essentials." |
  1220→| published_at | now |
  1221→
  1222→Collections: (none)
  1223→
  1224→Options: Color (Natural, Black)
  1225→
  1226→Variants (2 total): price_amount = 1999, weight_g = 300, inventory = 40 each (deny)
  1227→
  1228→---
  1229→
  1230→**Product 14: "Bucket Hat"**
  1231→
  1232→| Field | Value |
  1233→|-------|-------|
  1234→| handle | bucket-hat |
  1235→| status | active |
  1236→| vendor | Acme Accessories |
  1237→| product_type | Accessories |
  1238→| tags | ["new", "trending"] |
  1239→| description_html | "Lightweight bucket hat for sun protection. Packable design, washed cotton twill." |
  1240→| published_at | now |
  1241→
  1242→Collections: New Arrivals
  1243→
  1244→Options: Size (S/M, L/XL), Color (Beige, Black, Olive)
  1245→
  1246→Variants (6 total): price_amount = 2499, weight_g = 80, inventory = 22 each (deny)
  1247→
  1248→---
  1249→
  1250→**Product 15: "Unreleased Winter Jacket" -- DRAFT**
  1251→
  1252→| Field | Value |
  1253→|-------|-------|
  1254→| handle | unreleased-winter-jacket |
  1255→| status | **draft** |
  1256→| vendor | Acme Outerwear |
  1257→| product_type | Jackets |
  1258→| tags | ["limited"] |
  1259→| description_html | "Upcoming winter collection piece. Insulated puffer jacket with water-resistant shell." |
  1260→| published_at | **null** |
  1261→
  1262→Collections: (none - draft not assigned)
  1263→
  1264→Options: Size (S, M, L, XL)
  1265→
  1266→Variants (4 total): price_amount = 14999, weight_g = 900, inventory = **0 each** (deny)
  1267→
  1268→**Test purpose:** Verifies draft products do not appear on the storefront.
  1269→
  1270→---
  1271→
  1272→**Product 16: "Discontinued Raincoat" -- ARCHIVED**
  1273→
  1274→| Field | Value |
  1275→|-------|-------|
  1276→| handle | discontinued-raincoat |
  1277→| status | **archived** |
  1278→| vendor | Acme Outerwear |
  1279→| product_type | Jackets |
  1280→| tags | [] |
  1281→| description_html | "Lightweight waterproof raincoat. This product has been discontinued." |
  1282→| published_at | 6 months ago |
  1283→
  1284→Collections: (none)
  1285→
  1286→Options: Size (M, L)
  1287→
  1288→Variants (2 total): price_amount = 8999, weight_g = 400, inventory = 3 each (deny)
  1289→
  1290→**Test purpose:** Verifies archived products do not appear on the storefront.
  1291→
  1292→---
  1293→
  1294→**Product 17: "Limited Edition Sneakers" -- SOLD OUT (deny policy)**
  1295→
  1296→| Field | Value |
  1297→|-------|-------|
  1298→| handle | limited-edition-sneakers |
  1299→| status | active |
  1300→| vendor | Acme Sport |
  1301→| product_type | Shoes |
  1302→| tags | ["limited"] |
  1303→| description_html | "Limited edition collaboration sneakers. Once they are gone, they are gone." |
  1304→| published_at | now |
  1305→
  1306→Collections: (none)
  1307→
  1308→Options: Size (EU 40, EU 42, EU 44)
  1309→
  1310→Variants (3 total): price_amount = 15999, weight_g = 650, inventory = **0 each, policy = "deny"**
  1311→
  1312→**Test purpose:** Tests "sold out" display and add-to-cart prevention.
  1313→
  1314→---
  1315→
  1316→**Product 18: "Backorder Denim Jacket" -- OUT OF STOCK (continue policy)**
  1317→
  1318→| Field | Value |
  1319→|-------|-------|
  1320→| handle | backorder-denim-jacket |
  1321→| status | active |
  1322→| vendor | Acme Denim |
  1323→| product_type | Jackets |
  1324→| tags | ["popular"] |
  1325→| description_html | "Classic denim jacket. Currently on backorder - ships within 2-3 weeks." |
  1326→| published_at | now |
  1327→
  1328→Collections: (none)
  1329→
  1330→Options: Size (S, M, L, XL)
  1331→
  1332→Variants (4 total): price_amount = 9999, weight_g = 750, inventory = **0 each, policy = "continue"**
  1333→
  1334→**Test purpose:** Tests that items with "continue" inventory policy can be added to cart despite zero stock.
  1335→
  1336→---
  1337→
  1338→**Product 19: "Gift Card" -- DIGITAL (no shipping)**
  1339→
  1340→| Field | Value |
  1341→|-------|-------|
  1342→| handle | gift-card |
  1343→| status | active |
  1344→| vendor | Acme Fashion |
  1345→| product_type | Gift Cards |
  1346→| tags | ["popular"] |
  1347→| description_html | "Digital gift card delivered via email. The perfect gift when you are not sure what to choose." |
  1348→| published_at | now |
  1349→
  1350→Collections: (none)
  1351→
  1352→Options: Amount (25 EUR, 50 EUR, 100 EUR)
  1353→
  1354→Variants (3 total - each a different denomination):
  1355→
  1356→| SKU | Price (cents) | Weight | requires_shipping | Inventory |
  1357→|-----|---------------|--------|-------------------|-----------|
  1358→| ACME-GIFT-25 | 2500 | 0g | **0 (digital)** | 9999 (deny) |
  1359→| ACME-GIFT-50 | 5000 | 0g | **0 (digital)** | 9999 (deny) |
  1360→| ACME-GIFT-100 | 10000 | 0g | **0 (digital)** | 9999 (deny) |
  1361→
  1362→**Test purpose:** Tests digital product flow (no shipping step in checkout).
  1363→
  1364→---
  1365→
  1366→**Product 20: "Cashmere Overcoat" -- EXPENSIVE**
  1367→
  1368→| Field | Value |
  1369→|-------|-------|
  1370→| handle | cashmere-overcoat |
  1371→| status | active |
  1372→| vendor | Acme Premium |
  1373→| product_type | Jackets |
  1374→| tags | ["limited", "new"] |
  1375→| description_html | "Luxurious cashmere-blend overcoat. Impeccable tailoring with silk lining." |
  1376→| published_at | now |
  1377→
  1378→Collections: New Arrivals
  1379→
  1380→Options: Size (S, M, L), Color (Camel, Charcoal)
  1381→
  1382→Variants (6 total): price_amount = 49999 (499.99 EUR), weight_g = 1200, inventory = 3 each (deny)
  1383→
  1384→**Test purpose:** Tests high-value price display (499.99 EUR).
  1385→
  1386→---
  1387→
  1388→#### Product Summary Table (Acme Fashion)
  1389→
  1390→| # | Title | Handle | Status | Price (cents) | Compare At | Variants | Inventory | Special |
  1391→|---|-------|--------|--------|---------------|-----------|----------|-----------|---------|
  1392→| 1 | Classic Cotton T-Shirt | classic-cotton-t-shirt | active | 2499 | - | 12 | 15 ea | - |
  1393→| 2 | Premium Slim Fit Jeans | premium-slim-fit-jeans | active | 7999 | 9999 | 10 | 8 ea | On sale |
  1394→| 3 | Organic Hoodie | organic-hoodie | active | 5999 | - | 4 | 20 ea | - |
  1395→| 4 | Leather Belt | leather-belt | active | 3499 | - | 4 | 25 ea | - |
  1396→| 5 | Running Sneakers | running-sneakers | active | 11999 | - | 14 | 5 ea | Low stock |
  1397→| 6 | Graphic Print Tee | graphic-print-tee | active | 2999 | - | 4 | 18 ea | - |
  1398→| 7 | V-Neck Linen Tee | v-neck-linen-tee | active | 3499 | - | 9 | 12 ea | - |
  1399→| 8 | Striped Polo Shirt | striped-polo-shirt | active | 2799 | 3999 | 4 | 10 ea | On sale |
  1400→| 9 | Cargo Pants | cargo-pants | active | 5499 | - | 12 | 14 ea | - |
  1401→| 10 | Chino Shorts | chino-shorts | active | 3999 | - | 8 | 16 ea | - |
  1402→| 11 | Wide Leg Trousers | wide-leg-trousers | active | 4999 | 6999 | 3 | 7 ea | On sale |
  1403→| 12 | Wool Scarf | wool-scarf | active | 2999 | - | 3 | 30 ea | - |
  1404→| 13 | Canvas Tote Bag | canvas-tote-bag | active | 1999 | - | 2 | 40 ea | - |
  1405→| 14 | Bucket Hat | bucket-hat | active | 2499 | - | 6 | 22 ea | - |
  1406→| 15 | Unreleased Winter Jacket | unreleased-winter-jacket | draft | 14999 | - | 4 | 0 ea | Draft |
  1407→| 16 | Discontinued Raincoat | discontinued-raincoat | archived | 8999 | - | 2 | 3 ea | Archived |
  1408→| 17 | Limited Edition Sneakers | limited-edition-sneakers | active | 15999 | - | 3 | 0 ea | Sold out (deny) |
  1409→| 18 | Backorder Denim Jacket | backorder-denim-jacket | active | 9999 | - | 4 | 0 ea | Backorder (continue) |
  1410→| 19 | Gift Card | gift-card | active | 2500/5000/10000 | - | 3 | 9999 ea | Digital |
  1411→| 20 | Cashmere Overcoat | cashmere-overcoat | active | 49999 | - | 6 | 3 ea | Expensive |
  1412→
  1413→**Total variants across Acme Fashion:** 107
  1414→
  1415→---
  1416→
  1417→#### Acme Electronics - 5 Products (minimal seed for tenant isolation)
  1418→
  1419→These products exist for tenant isolation testing. Store 2 data must never appear in Store 1 queries.
  1420→
  1421→| # | Title | Handle | Vendor | Type | Options | Variants | Price (cents) | Weight | Inventory |
  1422→|---|-------|--------|--------|------|---------|----------|---------------|--------|-----------|
  1423→| E1 | Pro Laptop 15 | pro-laptop-15 | TechCorp | Laptops | Storage: 256GB, 512GB, 1TB | 3 | 99999, 119999, 149999 | 1800g | 10 ea |
  1424→| E2 | Wireless Headphones | wireless-headphones | AudioMax | Audio | Color: Black, Silver | 2 | 14999 | 250g | 25 ea |
  1425→| E3 | USB-C Cable 2m | usb-c-cable-2m | CablePro | Cables | (none - single default variant) | 1 | 1299 | 50g | 200 |
  1426→| E4 | Mechanical Keyboard | mechanical-keyboard | KeyTech | Peripherals | Switch Type: Red, Blue, Brown | 3 | 12999 | 1100g | 15 ea |
  1427→| E5 | Monitor Stand | monitor-stand | DeskGear | Accessories | (none - single default variant) | 1 | 4999 | 2500g | 30 |
  1428→
  1429→All active, published now, tags vary. Inventory policy = "deny" for all.
  1430→
  1431→**Note on product media:** No `ProductMedia` records are seeded. The storefront must gracefully handle products without images by displaying a placeholder (e.g., a neutral SVG placeholder with the store's brand color). E2E tests should not assert on specific image URLs.
  1432→
  1433→---
  1434→
  1435→### 3.11 DiscountSeeder
  1436→
  1437→**Acme Fashion - 5 discount codes:**
  1438→
  1439→| Code | Type | Value Type | value_amount | starts_at | ends_at | usage_limit | usage_count | rules_json | status |
  1440→|------|------|-----------|-------------|-----------|---------|-------------|-------------|-----------|--------|
  1441→| WELCOME10 | code | percent | 10 (=10%) | 2025-01-01 | 2027-12-31 | null | 3 | min_purchase_amount: 2000 (=20.00 EUR) | active |
  1442→| FLAT5 | code | fixed | 500 (=5.00 EUR) | 2025-01-01 | 2027-12-31 | null | 0 | (empty) | active |
  1443→| FREESHIP | code | free_shipping | 0 | 2025-01-01 | 2027-12-31 | null | 1 | (empty) | active |
  1444→| EXPIRED20 | code | percent | 20 (=20%) | 2024-01-01 | 2024-12-31 | null | 0 | (empty) | expired |
  1445→| MAXED | code | percent | 10 (=10%) | 2025-01-01 | 2027-12-31 | 5 | 5 | (empty) | active |
  1446→
  1447→**Behavioral expectations:**
  1448→- WELCOME10: Applies 10% off to orders with subtotal >= 20.00 EUR. Already used 3 times (has capacity remaining since no usage_limit).
  1449→- FLAT5: Applies flat 5.00 EUR discount. Never used.
  1450→- FREESHIP: Removes shipping cost. Used once.
  1451→- EXPIRED20: Expired - checkout must reject this code with "discount expired" error.
  1452→- MAXED: Usage limit of 5 reached - checkout must reject this code with "discount limit reached" error.
  1453→
  1454→---
  1455→
  1456→### 3.12 CustomerSeeder
  1457→
  1458→**Acme Fashion - 10 customers:**
  1459→
  1460→| # | Email | Name | Password (plaintext) | marketing_opt_in |
  1461→|---|-------|------|----------------------|------------------|
  1462→| 1 | customer@acme.test | John Doe | password | 1 |
  1463→| 2 | jane@example.com | Jane Smith | password | 0 |
  1464→| 3 | michael@example.com | Michael Brown | password | 1 |
  1465→| 4 | sarah@example.com | Sarah Wilson | password | 0 |
  1466→| 5 | david@example.com | David Lee | password | 1 |
  1467→| 6 | emma@example.com | Emma Garcia | password | 0 |
  1468→| 7 | james@example.com | James Taylor | password | 0 |
  1469→| 8 | lisa@example.com | Lisa Anderson | password | 1 |
  1470→| 9 | robert@example.com | Robert Martinez | password | 0 |
  1471→| 10 | anna@example.com | Anna Thomas | password | 1 |
  1472→
  1473→**Customer 1 (customer@acme.test) addresses:**
  1474→
  1475→| Label | is_default | Address Details |
  1476→|-------|-----------|-----------------|
  1477→| Home | 1 | John Doe, Hauptstrasse 1, 10115 Berlin, DE, phone: +49 30 12345678 |
  1478→| Work | 0 | John Doe, Acme Corp, Friedrichstrasse 100, 3rd Floor, 10117 Berlin, DE, phone: +49 30 87654321 |
  1479→
  1480→**Customer 2 (jane@example.com) addresses:**
  1481→
  1482→| Label | is_default | Address Details |
  1483→|-------|-----------|-----------------|
  1484→| Home | 1 | Jane Smith, Schillerstrasse 45, 80336 Munich, Bavaria (BY), DE |
  1485→
  1486→**Customers 3-10:** Each gets one default address with Faker-generated German addresses.
  1487→
  1488→**Acme Electronics - 2 customers (tenant isolation testing):**
  1489→
  1490→| # | Email | Name | Password |
  1491→|---|-------|------|----------|
  1492→| 1 | techfan@example.com | Tech Fan | password |
  1493→| 2 | gadgetlover@example.com | Gadget Lover | password |
  1494→
  1495→Each has one default address with Faker-generated data.
  1496→
  1497→---
  1498→
  1499→### 3.13 OrderSeeder
  1500→
  1501→**Acme Fashion - 15 orders:**
  1502→
  1503→All orders use the customer's default shipping address (unless noted). Order numbers follow the "#NNNN" format starting from #1001.
  1504→
  1505→---
  1506→
  1507→**Order #1001 - Awaiting fulfillment (Credit Card)**
  1508→
  1509→| Field | Value |
  1510→|-------|-------|
  1511→| customer | customer@acme.test (John Doe) |
  1512→| payment_method | credit_card |
  1513→| status / financial / fulfillment | paid / paid / unfulfilled |
  1514→| placed_at | 2 days ago |
  1515→
  1516→Lines:
  1517→
  1518→| Product | Variant (option values) | Qty | Unit Price | Line Total |
  1519→|---------|------------------------|-----|-----------|-----------|
  1520→| Classic Cotton T-Shirt | S / White | 2 | 2499 | 4998 |
  1521→
  1522→Totals: subtotal 4998, discount 0, shipping 499, tax 798, total **5497**
  1523→
  1524→Payment: mock, method "credit_card", provider_payment_id "mock_test_order1001", status "captured", amount 5497
  1525→
  1526→Fulfillments: None.
  1527→
  1528→---
  1529→
  1530→**Order #1002 - Fully delivered (Credit Card)**
  1531→
  1532→| Field | Value |
  1533→|-------|-------|
  1534→| customer | customer@acme.test (John Doe) |
  1535→| payment_method | credit_card |
  1536→| status / financial / fulfillment | fulfilled / paid / fulfilled |
  1537→| placed_at | 10 days ago |
  1538→
  1539→Lines:
  1540→
  1541→| Product | Variant | Qty | Unit Price | Line Total |
  1542→|---------|---------|-----|-----------|-----------|
  1543→| Organic Hoodie | M | 1 | 5999 | 5999 |
  1544→| Classic Cotton T-Shirt | L / Black | 1 | 2499 | 2499 |
  1545→
  1546→Totals: subtotal 8498, discount 0, shipping 499, tax 1357, total **8997**
  1547→
  1548→Payment: mock, method "credit_card", "mock_test_order1002", captured, 8997
  1549→
  1550→Fulfillment: status "delivered", tracking company "DHL", tracking number "DHL1234567890", shipped 8 days ago. Fulfillment lines cover all order lines at full quantity.
  1551→
  1552→---
  1553→
  1554→**Order #1003 - Partially fulfilled (Credit Card)**
  1555→
  1556→| Field | Value |
  1557→|-------|-------|
  1558→| customer | jane@example.com (Jane Smith) |
  1559→| payment_method | credit_card |
  1560→| status / financial / fulfillment | paid / paid / partial |
  1561→| placed_at | 5 days ago |
  1562→
  1563→Lines:
  1564→
  1565→| Product | Variant | Qty | Unit Price | Line Total |
  1566→|---------|---------|-----|-----------|-----------|
  1567→| Premium Slim Fit Jeans | 32 / Blue | 1 | 7999 | 7999 |
  1568→| Leather Belt | L/XL / Brown | 1 | 3499 | 3499 |
  1569→
  1570→Totals: subtotal 11498, discount 0, shipping 499, tax 1836, total **11997**
  1571→
  1572→Payment: mock, method "credit_card", "mock_test_order1003", captured, 11997
  1573→
  1574→Fulfillment: status "shipped", DHL, "DHL9876543210", shipped 3 days ago. Fulfillment lines: **only the Jeans line (qty 1)**. The Belt is not yet shipped.
  1575→
  1576→---
  1577→
  1578→**Order #1004 - Cancelled with full refund (Credit Card)**
  1579→
  1580→| Field | Value |
  1581→|-------|-------|
  1582→| customer | customer@acme.test (John Doe) |
  1583→| payment_method | credit_card |
  1584→| status / financial / fulfillment | cancelled / refunded / unfulfilled |
  1585→| placed_at | 15 days ago |
  1586→
  1587→Lines:
  1588→
  1589→| Product | Variant | Qty | Unit Price | Line Total |
  1590→|---------|---------|-----|-----------|-----------|
  1591→| Classic Cotton T-Shirt | M / Navy | 1 | 2499 | 2499 |
  1592→
  1593→Totals: subtotal 2499, discount 0, shipping 499, tax 399, total **2998**
  1594→
  1595→Payment: mock, method "credit_card", "mock_test_order1004", status "refunded", amount 2998
  1596→
  1597→Refund: amount 2998, reason "Customer requested cancellation", status "processed", provider_refund_id "mock_re_test_order1004"
  1598→
  1599→---
  1600→
  1601→**Order #1005 - Bank transfer awaiting payment**
  1602→
  1603→| Field | Value |
  1604→|-------|-------|
  1605→| customer | jane@example.com (Jane Smith) |
  1606→| payment_method | bank_transfer |
  1607→| status / financial / fulfillment | pending / pending / unfulfilled |
  1608→| placed_at | 2 hours ago |
  1609→
  1610→Lines:
  1611→
  1612→| Product | Variant | Qty | Unit Price | Line Total |
  1613→|---------|---------|-----|-----------|-----------|
  1614→| Leather Belt | S/M / Black | 1 | 3499 | 3499 |
  1615→
  1616→Totals: subtotal 3499, discount 0, shipping 499, tax 559, total **3998**
  1617→
  1618→Payment: mock, method "bank_transfer", "mock_test_order1005", status "pending", amount 3998
  1619→
  1620→**Test purpose:** Tests the bank transfer flow - admin "Confirm Payment" button, fulfillment guard (cannot fulfill until payment confirmed), and auto-cancel job scenario.
  1621→
  1622→---
  1623→
  1624→**Order #1006 - Standard paid order (Credit Card)**
  1625→
  1626→| Field | Value |
  1627→|-------|-------|
  1628→| customer | michael@example.com (Michael Brown) |
  1629→| payment_method | credit_card |
  1630→| status / financial / fulfillment | paid / paid / unfulfilled |
  1631→| placed_at | 1 day ago |
  1632→
  1633→Lines:
  1634→
  1635→| Product | Variant | Qty | Unit Price | Line Total |
  1636→|---------|---------|-----|-----------|-----------|
  1637→| Running Sneakers | EU 42 / Black | 1 | 11999 | 11999 |
  1638→
  1639→Totals: subtotal 11999, discount 0, shipping 499, tax 1916, total **12498**
  1640→
  1641→Payment: mock, method "credit_card", "mock_test_order1006", captured, 12498
  1642→
  1643→---
  1644→
  1645→**Order #1007 - Multi-item delivered (PayPal)**
  1646→
  1647→| Field | Value |
  1648→|-------|-------|
  1649→| customer | sarah@example.com (Sarah Wilson) |
  1650→| payment_method | paypal |
  1651→| status / financial / fulfillment | fulfilled / paid / fulfilled |
  1652→| placed_at | 20 days ago |
  1653→
  1654→Lines:
  1655→
  1656→| Product | Variant | Qty | Unit Price | Line Total |
  1657→|---------|---------|-----|-----------|-----------|
  1658→| V-Neck Linen Tee | M / Beige | 2 | 3499 | 6998 |
  1659→| Wool Scarf | Grey | 1 | 2999 | 2999 |
  1660→
  1661→Totals: subtotal 9997, discount 0, shipping 499, tax 1596, total **10496**
  1662→
  1663→Payment: mock, method "paypal", "mock_test_order1007", captured, 10496
  1664→
  1665→Fulfillment: delivered, DHL, "DHL1112223334", shipped 18 days ago. All lines fulfilled.
  1666→
  1667→---
  1668→
  1669→**Order #1008 - Partial refund (Credit Card)**
  1670→
  1671→| Field | Value |
  1672→|-------|-------|
  1673→| customer | david@example.com (David Lee) |
  1674→| payment_method | credit_card |
  1675→| status / financial / fulfillment | paid / partially_refunded / fulfilled |
  1676→| placed_at | 12 days ago |
  1677→
  1678→Lines:
  1679→
  1680→| Product | Variant | Qty | Unit Price | Line Total |
  1681→|---------|---------|-----|-----------|-----------|
  1682→| Cargo Pants | 32 / Khaki | 1 | 5499 | 5499 |
  1683→| Graphic Print Tee | L | 1 | 2999 | 2999 |
  1684→
  1685→Totals: subtotal 8498, discount 0, shipping 499, tax 1357, total **8997**
  1686→
  1687→Payment: mock, method "credit_card", "mock_test_order1008", captured, 8997
  1688→
  1689→Fulfillment: delivered, UPS, "UPS5556667778", shipped 10 days ago
  1690→
  1691→Refund (partial - for Graphic Print Tee only): amount 2999, reason "Item returned", status "processed", provider_refund_id "mock_re_test_order1008"
  1692→
  1693→---
  1694→
  1695→**Order #1009 - Accessories order (Credit Card)**
  1696→
  1697→| Field | Value |
  1698→|-------|-------|
  1699→| customer | emma@example.com (Emma Garcia) |
  1700→| payment_method | credit_card |
  1701→| status / financial / fulfillment | paid / paid / unfulfilled |
  1702→| placed_at | 3 days ago |
  1703→
  1704→Lines:
  1705→
  1706→| Product | Variant | Qty | Unit Price | Line Total |
  1707→|---------|---------|-----|-----------|-----------|
  1708→| Canvas Tote Bag | Natural | 1 | 1999 | 1999 |
  1709→| Bucket Hat | S/M / Black | 1 | 2499 | 2499 |
  1710→
  1711→Totals: subtotal 4498, discount 0, shipping 499, tax 718, total **4997**
  1712→
  1713→Payment: mock, method "credit_card", "mock_test_order1009", captured, 4997
  1714→
  1715→---
  1716→
  1717→**Order #1010 - High-value order (PayPal)**
  1718→
  1719→| Field | Value |
  1720→|-------|-------|
  1721→| customer | customer@acme.test (John Doe) |
  1722→| payment_method | paypal |
  1723→| status / financial / fulfillment | paid / paid / unfulfilled |
  1724→| placed_at | 1 day ago |
  1725→
  1726→Lines:
  1727→
  1728→| Product | Variant | Qty | Unit Price | Line Total |
  1729→|---------|---------|-----|-----------|-----------|
  1730→| Cashmere Overcoat | M / Camel | 1 | 49999 | 49999 |
  1731→
  1732→Totals: subtotal 49999, discount 0, shipping 499, tax 7983, total **50498**
  1733→
  1734→Payment: mock, method "paypal", "mock_test_order1010", captured, 50498
  1735→
  1736→---
  1737→
  1738→**Order #1011 - Single item delivered (Credit Card)**
  1739→
  1740→| Field | Value |
  1741→|-------|-------|
  1742→| customer | james@example.com (James Taylor) |
  1743→| payment_method | credit_card |
  1744→| status / financial / fulfillment | paid / paid / fulfilled |
  1745→| placed_at | 25 days ago |
  1746→
  1747→Lines:
  1748→
  1749→| Product | Variant | Qty | Unit Price | Line Total |
  1750→|---------|---------|-----|-----------|-----------|
  1751→| Striped Polo Shirt | XL | 1 | 2799 | 2799 |
  1752→
  1753→Totals: subtotal 2799, discount 0, shipping 499, tax 447, total **3298**
  1754→
  1755→Payment: mock, method "credit_card", "mock_test_order1011", captured, 3298
  1756→
  1757→Fulfillment: delivered, FedEx, "FX9998887776", shipped 23 days ago
  1758→
  1759→---
  1760→
  1761→**Order #1012 - Multi-quantity order (Credit Card)**
  1762→
  1763→| Field | Value |
  1764→|-------|-------|
  1765→| customer | lisa@example.com (Lisa Anderson) |
  1766→| payment_method | credit_card |
  1767→| status / financial / fulfillment | paid / paid / unfulfilled |
  1768→| placed_at | 4 days ago |
  1769→
  1770→Lines:
  1771→
  1772→| Product | Variant | Qty | Unit Price | Line Total |
  1773→|---------|---------|-----|-----------|-----------|
  1774→| Chino Shorts | 34 / Navy | 2 | 3999 | 7998 |
  1775→
  1776→Totals: subtotal 7998, discount 0, shipping 499, tax 1277, total **8497**
  1777→
  1778→Payment: mock, method "credit_card", "mock_test_order1012", captured, 8497
  1779→
  1780→---
  1781→
  1782→**Order #1013 - Multi-item order (Credit Card)**
  1783→
  1784→| Field | Value |
  1785→|-------|-------|
  1786→| customer | robert@example.com (Robert Martinez) |
  1787→| payment_method | credit_card |
  1788→| status / financial / fulfillment | paid / paid / unfulfilled |
  1789→| placed_at | 1 day ago |
  1790→
  1791→Lines:
  1792→
  1793→| Product | Variant | Qty | Unit Price | Line Total |
  1794→|---------|---------|-----|-----------|-----------|
  1795→| Wide Leg Trousers | M | 1 | 4999 | 4999 |
  1796→| Wool Scarf | Burgundy | 1 | 2999 | 2999 |
  1797→
  1798→Totals: subtotal 7998, discount 0, shipping 499, tax 1277, total **8497**
  1799→
  1800→Payment: mock, method "credit_card", "mock_test_order1013", captured, 8497
  1801→
  1802→---
  1803→
  1804→**Order #1014 - Digital product order (Credit Card)**
  1805→
  1806→| Field | Value |
  1807→|-------|-------|
  1808→| customer | anna@example.com (Anna Thomas) |
  1809→| payment_method | credit_card |
  1810→| status / financial / fulfillment | paid / paid / fulfilled |
  1811→| placed_at | 14 days ago |
  1812→
  1813→Lines:
  1814→
  1815→| Product | Variant | Qty | Unit Price | Line Total |
  1816→|---------|---------|-----|-----------|-----------|
  1817→| Gift Card | 50 EUR | 1 | 5000 | 5000 |
  1818→
  1819→Totals: subtotal 5000, discount 0, shipping **0** (digital product), tax 798, total **5000**
  1820→
  1821→Payment: mock, method "credit_card", "mock_test_order1014", captured, 5000
  1822→
  1823→Fulfillment: delivered (auto-fulfilled digital product), no tracking company, no tracking number, shipped_at = placed_at, delivered_at = placed_at
  1824→
  1825→---
  1826→
  1827→**Order #1015 - Order with discount (Bank Transfer, confirmed)**
  1828→
  1829→| Field | Value |
  1830→|-------|-------|
  1831→| customer | customer@acme.test (John Doe) |
  1832→| payment_method | bank_transfer |
  1833→| status / financial / fulfillment | paid / paid / unfulfilled |
  1834→| placed_at | now (today) |
  1835→
  1836→Lines:
  1837→
  1838→| Product | Variant | Qty | Unit Price | Line Total | Discount Allocation |
  1839→|---------|---------|-----|-----------|-----------|-------------------|
  1840→| Classic Cotton T-Shirt | M / White | 1 | 2499 | 2499 | WELCOME10 discount, amount: 250 |
  1841→| Graphic Print Tee | M | 1 | 2999 | 2999 | WELCOME10 discount, amount: 300 |
  1842→
  1843→Totals: subtotal 5498, discount **550**, shipping 499, tax 790, total **5447**
  1844→
  1845→Payment: mock, method "bank_transfer", "mock_test_order1015", captured, 5447
  1846→
  1847→The discount_allocations_json on each order line references the WELCOME10 discount's database ID and the allocated discount amount for that specific line.
  1848→
  1849→**Test purpose:** Tests a bank transfer order that has been confirmed by the admin (payment status = captured). Contrasts with #1005 which is still pending.
  1850→
  1851→---
  1852→
  1853→#### Order Summary Table (Acme Fashion)
  1854→
  1855→| Order | Customer | Payment Method | Status | Financial | Fulfillment | Total | Key Test Scenario |
  1856→|-------|----------|---------------|--------|-----------|-------------|-------|-------------------|
  1857→| #1001 | John Doe | credit_card | paid | paid | unfulfilled | 5497 | Awaiting fulfillment |
  1858→| #1002 | John Doe | credit_card | fulfilled | paid | fulfilled | 8997 | Delivered order |
  1859→| #1003 | Jane Smith | credit_card | paid | paid | partial | 11997 | Partial fulfillment |
  1860→| #1004 | John Doe | credit_card | cancelled | refunded | unfulfilled | 2998 | Full cancellation + refund |
  1861→| #1005 | Jane Smith | bank_transfer | pending | pending | unfulfilled | 3998 | Bank transfer awaiting payment |
  1862→| #1006 | Michael Brown | credit_card | paid | paid | unfulfilled | 12498 | Standard paid order |
  1863→| #1007 | Sarah Wilson | paypal | fulfilled | paid | fulfilled | 10496 | Multi-item delivered (PayPal) |
  1864→| #1008 | David Lee | credit_card | paid | partially_refunded | fulfilled | 8997 | Partial refund |
  1865→| #1009 | Emma Garcia | credit_card | paid | paid | unfulfilled | 4997 | Accessories order |
  1866→| #1010 | John Doe | paypal | paid | paid | unfulfilled | 50498 | High-value order (PayPal) |
  1867→| #1011 | James Taylor | credit_card | paid | paid | fulfilled | 3298 | Single item delivered |
  1868→| #1012 | Lisa Anderson | credit_card | paid | paid | unfulfilled | 8497 | Multi-quantity order |
  1869→| #1013 | Robert Martinez | credit_card | paid | paid | unfulfilled | 8497 | Multi-item order |
  1870→| #1014 | Anna Thomas | credit_card | paid | paid | fulfilled | 5000 | Digital product (auto-fulfilled) |
  1871→| #1015 | John Doe | bank_transfer | paid | paid | unfulfilled | 5447 | Order with discount (bank transfer, confirmed) |
  1872→
  1873→---
  1874→
  1875→**Acme Electronics - 3 orders (minimal, for tenant isolation):**
  1876→
  1877→| Order | Customer | Status | Financial | Fulfillment | Total | Details |
  1878→|-------|----------|--------|-----------|-------------|-------|---------|
  1879→| #5001 | techfan@example.com | credit_card | paid | paid | fulfilled | 121298 | Pro Laptop 512GB (119999) + USB-C Cable (1299), shipping 0 |
  1880→| #5002 | gadgetlover@example.com | credit_card | paid | paid | unfulfilled | 14999 | Wireless Headphones Black (14999), shipping 0 |
  1881→| #5003 | techfan@example.com | bank_transfer | pending | pending | unfulfilled | 4999 | Monitor Stand (4999), shipping 0, bank transfer pending |
  1882→
  1883→---
  1884→
  1885→### 3.14 ThemeSeeder
  1886→
  1887→**Acme Fashion:**
  1888→
  1889→| Field | Value |
  1890→|-------|-------|
  1891→| name | Default Theme |
  1892→| version | 1.0.0 |
  1893→| status | published |
  1894→| published_at | now |
  1895→
  1896→**Theme settings (theme_settings row):**
  1897→
  1898→| Setting Key | Value |
  1899→|-------------|-------|
  1900→| primary_color | #1a1a2e |
  1901→| secondary_color | #e94560 |
  1902→| font_family | Inter, sans-serif |
  1903→| hero_heading | Welcome to Acme Fashion |
  1904→| hero_subheading | Discover our curated collection of modern essentials |
  1905→| hero_cta_text | Shop New Arrivals |
  1906→| hero_cta_link | /collections/new-arrivals |
  1907→| featured_collection_handles | ["new-arrivals", "t-shirts", "sale"] |
  1908→| footer_text | 2025 Acme Fashion. All rights reserved. |
  1909→| show_announcement_bar | true |
  1910→| announcement_text | Free shipping on orders over 50 EUR - Use code FREESHIP |
  1911→| products_per_page | 12 |
  1912→| show_vendor | true |
  1913→| show_quantity_selector | true |
  1914→
  1915→**Acme Electronics:**
  1916→
  1917→| Field | Value |
  1918→|-------|-------|
  1919→| name | Default Theme |
  1920→| version | 1.0.0 |
  1921→| status | published |
  1922→
  1923→Theme settings:
  1924→
  1925→| Setting Key | Value |
  1926→|-------------|-------|
  1927→| primary_color | #0f172a |
  1928→| secondary_color | #3b82f6 |
  1929→| font_family | Inter, sans-serif |
  1930→| hero_heading | Acme Electronics |
  1931→| hero_subheading | Premium tech for professionals |
  1932→| hero_cta_text | Shop Featured |
  1933→| hero_cta_link | /collections/featured |
  1934→| featured_collection_handles | ["featured"] |
  1935→| footer_text | 2025 Acme Electronics. All rights reserved. |
  1936→
  1937→---
  1938→
  1939→### 3.15 PageSeeder
  1940→
  1941→**Acme Fashion - 5 content pages:**
  1942→
  1943→All pages: status = "published", published_at = 3 months ago.
  1944→
  1945→**Page 1: About Us**
  1946→- handle: about
  1947→- body_html content: Three sections with h2 headings - "Our Story" (mission and philosophy), "Our Values" (ethical sourcing, sustainability, fair labor), "Our Team" (Berlin-based designers). Multiple paragraphs of realistic store copy.
  1948→
  1949→**Page 2: FAQ**
  1950→- handle: faq
  1951→- body_html content: h2 "Frequently Asked Questions" followed by four Q&A pairs using h3/p structure:
  1952→  1. Shipping timeframes (Germany 2-4 days standard, 1-2 express; EU 5-7 days)
  1953→  2. Return policy (30 days, unworn, original packaging)
  1954→  3. International shipping (EU + US, UK, CA, AU)
  1955→  4. Order tracking (email with tracking number after shipment)
  1956→
  1957→**Page 3: Shipping & Returns**
  1958→- handle: shipping-returns
  1959→- body_html content: Shipping rates table (Germany standard 4.99/express 9.99, EU 8.99, International 14.99) using h3 and ul/li elements, plus returns policy paragraph (30 days, customer pays return shipping unless defective).
  1960→
  1961→**Page 4: Privacy Policy**
  1962→- handle: privacy-policy
  1963→- body_html content: Standard privacy policy with sections: Information We Collect, How We Use Your Information, Cookies, Contact (privacy@acme-fashion.test). Uses h2/h3/p structure.
  1964→
  1965→**Page 5: Terms of Service**
  1966→- handle: terms
  1967→- body_html content: Standard ToS with sections: Orders and Payments (EUR, tax-inclusive), Product Descriptions (color variance disclaimer), Limitation of Liability, Governing Law (Federal Republic of Germany). Uses h2/h3/p structure.
  1968→
  1969→---
  1970→
  1971→### 3.16 NavigationSeeder
  1972→
  1973→**Acme Fashion - Main Menu (handle: main-menu, title: "Main Menu"):**
  1974→
  1975→| Position | Label | Type | Target |
  1976→|----------|-------|------|--------|
  1977→| 0 | Home | link | URL: / |
  1978→| 1 | New Arrivals | collection | resource_id: ID of "New Arrivals" collection |
  1979→| 2 | T-Shirts | collection | resource_id: ID of "T-Shirts" collection |
  1980→| 3 | Pants & Jeans | collection | resource_id: ID of "Pants & Jeans" collection |
  1981→| 4 | Sale | collection | resource_id: ID of "Sale" collection |
  1982→
  1983→**Acme Fashion - Footer Menu (handle: footer-menu, title: "Footer Menu"):**
  1984→
  1985→| Position | Label | Type | Target |
  1986→|----------|-------|------|--------|
  1987→| 0 | About Us | page | resource_id: ID of "About Us" page |
  1988→| 1 | FAQ | page | resource_id: ID of "FAQ" page |
  1989→| 2 | Shipping & Returns | page | resource_id: ID of "Shipping & Returns" page |
  1990→| 3 | Privacy Policy | page | resource_id: ID of "Privacy Policy" page |
  1991→| 4 | Terms of Service | page | resource_id: ID of "Terms of Service" page |
  1992→
  1993→**Acme Electronics - Main Menu (handle: main-menu, title: "Main Menu"):**
  1994→
  1995→| Position | Label | Type | Target |
  1996→|----------|-------|------|--------|
  1997→| 0 | Home | link | URL: / |
  1998→| 1 | Featured | collection | resource_id: ID of "Featured" collection |
  1999→| 2 | Accessories | collection | resource_id: ID of "Accessories" collection |
  2000→

prompt:
Read ALL the specification files in /Users/fabianwesner/Herd/shop/specs/ directory. I need the full content of:
1. specs/01-DATABASE-SCHEMA.md (read in chunks if needed)
2. specs/02-API-ROUTES.md (read in chunks if needed)
3. specs/03-ADMIN-UI.md (read in chunks if needed)
4. specs/04-STOREFRONT-UI.md (read in chunks if needed)
5. specs/05-BUSINESS-LOGIC.md (read in chunks if needed)
6. specs/06-AUTH-AND-SECURITY.md (read in chunks if needed)
7. specs/07-SEEDERS-AND-TEST-DATA.md (read in chunks if needed)
8. specs/08-PLAYWRIGHT-E2E-PLAN.md (read in chunks if needed)

For each file provide a comprehensive summary including:
- All table/column definitions
- All API endpoints
- All UI components and their specifications
- All business rules
- All test specifications
- All seeder data definitions

This is critical - I need ALL the details, not just summaries. Extract every table name, column, relationship, route, component, and test case.


userType: external

slug: iterative-seeking-pine

type: progress

type: assistant

type: message

role: assistant

service_tier: standard

prompt:
Read ALL the specification files in /Users/fabianwesner/Herd/shop/specs/ directory. I need the full content of:
1. specs/01-DATABASE-SCHEMA.md (read in chunks if needed)
2. specs/02-API-ROUTES.md (read in chunks if needed)
3. specs/03-ADMIN-UI.md (read in chunks if needed)
4. specs/04-STOREFRONT-UI.md (read in chunks if needed)
5. specs/05-BUSINESS-LOGIC.md (read in chunks if needed)
6. specs/06-AUTH-AND-SECURITY.md (read in chunks if needed)
7. specs/07-SEEDERS-AND-TEST-DATA.md (read in chunks if needed)
8. specs/08-PLAYWRIGHT-E2E-PLAN.md (read in chunks if needed)

For each file provide a comprehensive summary including:
- All table/column definitions
- All API endpoints
- All UI components and their specifications
- All business rules
- All test specifications
- All seeder data definitions

This is critical - I need ALL the details, not just summaries. Extract every table name, column, relationship, route, component, and test case.


type: user

role: user

content:
     1→<?php
     2→
     3→return [
     4→    App\Providers\AppServiceProvider::class,
     5→    App\Providers\FortifyServiceProvider::class,
     6→];
     7→

prompt:
Explore the current state of the Laravel project at /Users/fabianwesner/Herd/shop. I need to understand:

1. What files already exist (models, controllers, migrations, routes, views, tests, etc.)
2. Current state of composer.json dependencies
3. Current state of package.json
4. Current .env configuration
5. Current config files (auth.php, database.php, etc.)
6. Current routes/web.php, routes/api.php, routes/console.php
7. Current app directory structure
8. Current tests directory structure
9. Current database/migrations directory
10. Current resources/views directory

Give me a comprehensive overview of what already exists vs what needs to be built.


prompt:
Explore the current state of the Laravel project at /Users/fabianwesner/Herd/shop. I need to understand:

1. What files already exist (models, controllers, migrations, routes, views, tests, etc.)
2. Current state of composer.json dependencies
3. Current state of package.json
4. Current .env configuration
5. Current config files (auth.php, database.php, etc.)
6. Current routes/web.php, routes/api.php, routes/console.php
7. Current app directory structure
8. Current tests directory structure
9. Current database/migrations directory
10. Current resources/views directory

Give me a comprehensive overview of what already exists vs what needs to be built.