  1200→| Field | Value |
  1201→|-------|-------|
  1202→| handle | canvas-tote-bag |
  1203→| status | active |
  1204→| vendor | Acme Accessories |
  1205→| product_type | Accessories |
  1206→| tags | ["trending"] |
  1207→| description_html | "Heavy-duty canvas tote bag with reinforced handles. Spacious enough for daily essentials." |
  1208→| published_at | now |
  1209→
  1210→Collections: (none)
  1211→
  1212→Options: Color (Natural, Black)
  1213→
  1214→Variants (2 total): price_amount = 1999, weight_g = 300, inventory = 40 each (deny)
  1215→
  1216→---
  1217→
  1218→**Product 14: "Bucket Hat"**
  1219→
  1220→| Field | Value |
  1221→|-------|-------|
  1222→| handle | bucket-hat |
  1223→| status | active |
  1224→| vendor | Acme Accessories |
  1225→| product_type | Accessories |
  1226→| tags | ["new", "trending"] |
  1227→| description_html | "Lightweight bucket hat for sun protection. Packable design, washed cotton twill." |
  1228→| published_at | now |
  1229→
  1230→Collections: New Arrivals
  1231→
  1232→Options: Size (S/M, L/XL), Color (Beige, Black, Olive)
  1233→
  1234→Variants (6 total): price_amount = 2499, weight_g = 80, inventory = 22 each (deny)
  1235→
  1236→---
  1237→
  1238→**Product 15: "Unreleased Winter Jacket" -- DRAFT**
  1239→
  1240→| Field | Value |
  1241→|-------|-------|
  1242→| handle | unreleased-winter-jacket |
  1243→| status | **draft** |
  1244→| vendor | Acme Outerwear |
  1245→| product_type | Jackets |
  1246→| tags | ["limited"] |
  1247→| description_html | "Upcoming winter collection piece. Insulated puffer jacket with water-resistant shell." |
  1248→| published_at | **null** |
  1249→
  1250→Collections: (none - draft not assigned)
  1251→
  1252→Options: Size (S, M, L, XL)
  1253→
  1254→Variants (4 total): price_amount = 14999, weight_g = 900, inventory = **0 each** (deny)
  1255→
  1256→**Test purpose:** Verifies draft products do not appear on the storefront.
  1257→
  1258→---
  1259→
  1260→**Product 16: "Discontinued Raincoat" -- ARCHIVED**
  1261→
  1262→| Field | Value |
  1263→|-------|-------|
  1264→| handle | discontinued-raincoat |
  1265→| status | **archived** |
  1266→| vendor | Acme Outerwear |
  1267→| product_type | Jackets |
  1268→| tags | [] |
  1269→| description_html | "Lightweight waterproof raincoat. This product has been discontinued." |
  1270→| published_at | 6 months ago |
  1271→
  1272→Collections: (none)
  1273→
  1274→Options: Size (M, L)
  1275→
  1276→Variants (2 total): price_amount = 8999, weight_g = 400, inventory = 3 each (deny)
  1277→
  1278→**Test purpose:** Verifies archived products do not appear on the storefront.
  1279→
  1280→---
  1281→
  1282→**Product 17: "Limited Edition Sneakers" -- SOLD OUT (deny policy)**
  1283→
  1284→| Field | Value |
  1285→|-------|-------|
  1286→| handle | limited-edition-sneakers |
  1287→| status | active |
  1288→| vendor | Acme Sport |
  1289→| product_type | Shoes |
  1290→| tags | ["limited"] |
  1291→| description_html | "Limited edition collaboration sneakers. Once they are gone, they are gone." |
  1292→| published_at | now |
  1293→
  1294→Collections: (none)
  1295→
  1296→Options: Size (EU 40, EU 42, EU 44)
  1297→
  1298→Variants (3 total): price_amount = 15999, weight_g = 650, inventory = **0 each, policy = "deny"**
  1299→
  1300→**Test purpose:** Tests "sold out" display and add-to-cart prevention.
  1301→
  1302→---
  1303→
  1304→**Product 18: "Backorder Denim Jacket" -- OUT OF STOCK (continue policy)**
  1305→
  1306→| Field | Value |
  1307→|-------|-------|
  1308→| handle | backorder-denim-jacket |
  1309→| status | active |
  1310→| vendor | Acme Denim |
  1311→| product_type | Jackets |
  1312→| tags | ["popular"] |
  1313→| description_html | "Classic denim jacket. Currently on backorder - ships within 2-3 weeks." |
  1314→| published_at | now |
  1315→
  1316→Collections: (none)
  1317→
  1318→Options: Size (S, M, L, XL)
  1319→
  1320→Variants (4 total): price_amount = 9999, weight_g = 750, inventory = **0 each, policy = "continue"**
  1321→
  1322→**Test purpose:** Tests that items with "continue" inventory policy can be added to cart despite zero stock.
  1323→
  1324→---
  1325→
  1326→**Product 19: "Gift Card" -- DIGITAL (no shipping)**
  1327→
  1328→| Field | Value |
  1329→|-------|-------|
  1330→| handle | gift-card |
  1331→| status | active |
  1332→| vendor | Acme Fashion |
  1333→| product_type | Gift Cards |
  1334→| tags | ["popular"] |
  1335→| description_html | "Digital gift card delivered via email. The perfect gift when you are not sure what to choose." |
  1336→| published_at | now |
  1337→
  1338→Collections: (none)
  1339→
  1340→Options: Amount (25 EUR, 50 EUR, 100 EUR)
  1341→
  1342→Variants (3 total - each a different denomination):
  1343→
  1344→| SKU | Price (cents) | Weight | requires_shipping | Inventory |
  1345→|-----|---------------|--------|-------------------|-----------|
  1346→| ACME-GIFT-25 | 2500 | 0g | **0 (digital)** | 9999 (deny) |
  1347→| ACME-GIFT-50 | 5000 | 0g | **0 (digital)** | 9999 (deny) |
  1348→| ACME-GIFT-100 | 10000 | 0g | **0 (digital)** | 9999 (deny) |
  1349→
  1350→**Test purpose:** Tests digital product flow (no shipping step in checkout).
  1351→
  1352→---
  1353→
  1354→**Product 20: "Cashmere Overcoat" -- EXPENSIVE**
  1355→
  1356→| Field | Value |
  1357→|-------|-------|
  1358→| handle | cashmere-overcoat |
  1359→| status | active |
  1360→| vendor | Acme Premium |
  1361→| product_type | Jackets |
  1362→| tags | ["limited", "new"] |
  1363→| description_html | "Luxurious cashmere-blend overcoat. Impeccable tailoring with silk lining." |
  1364→| published_at | now |
  1365→
  1366→Collections: New Arrivals
  1367→
  1368→Options: Size (S, M, L), Color (Camel, Charcoal)
  1369→
  1370→Variants (6 total): price_amount = 49999 (499.99 EUR), weight_g = 1200, inventory = 3 each (deny)
  1371→
  1372→**Test purpose:** Tests high-value price display (499.99 EUR).
  1373→
  1374→---
  1375→
  1376→#### Product Summary Table (Acme Fashion)
  1377→
  1378→| # | Title | Handle | Status | Price (cents) | Compare At | Variants | Inventory | Special |
  1379→|---|-------|--------|--------|---------------|-----------|----------|-----------|---------|
  1380→| 1 | Classic Cotton T-Shirt | classic-cotton-t-shirt | active | 2499 | - | 12 | 15 ea | - |
  1381→| 2 | Premium Slim Fit Jeans | premium-slim-fit-jeans | active | 7999 | 9999 | 10 | 8 ea | On sale |
  1382→| 3 | Organic Hoodie | organic-hoodie | active | 5999 | - | 4 | 20 ea | - |
  1383→| 4 | Leather Belt | leather-belt | active | 3499 | - | 4 | 25 ea | - |
  1384→| 5 | Running Sneakers | running-sneakers | active | 11999 | - | 14 | 5 ea | Low stock |
  1385→| 6 | Graphic Print Tee | graphic-print-tee | active | 2999 | - | 4 | 18 ea | - |
  1386→| 7 | V-Neck Linen Tee | v-neck-linen-tee | active | 3499 | - | 9 | 12 ea | - |
  1387→| 8 | Striped Polo Shirt | striped-polo-shirt | active | 2799 | 3999 | 4 | 10 ea | On sale |
  1388→| 9 | Cargo Pants | cargo-pants | active | 5499 | - | 12 | 14 ea | - |
  1389→| 10 | Chino Shorts | chino-shorts | active | 3999 | - | 8 | 16 ea | - |
  1390→| 11 | Wide Leg Trousers | wide-leg-trousers | active | 4999 | 6999 | 3 | 7 ea | On sale |
  1391→| 12 | Wool Scarf | wool-scarf | active | 2999 | - | 3 | 30 ea | - |
  1392→| 13 | Canvas Tote Bag | canvas-tote-bag | active | 1999 | - | 2 | 40 ea | - |
  1393→| 14 | Bucket Hat | bucket-hat | active | 2499 | - | 6 | 22 ea | - |
  1394→| 15 | Unreleased Winter Jacket | unreleased-winter-jacket | draft | 14999 | - | 4 | 0 ea | Draft |
  1395→| 16 | Discontinued Raincoat | discontinued-raincoat | archived | 8999 | - | 2 | 3 ea | Archived |
  1396→| 17 | Limited Edition Sneakers | limited-edition-sneakers | active | 15999 | - | 3 | 0 ea | Sold out (deny) |
  1397→| 18 | Backorder Denim Jacket | backorder-denim-jacket | active | 9999 | - | 4 | 0 ea | Backorder (continue) |
  1398→| 19 | Gift Card | gift-card | active | 2500/5000/10000 | - | 3 | 9999 ea | Digital |
  1399→| 20 | Cashmere Overcoat | cashmere-overcoat | active | 49999 | - | 6 | 3 ea | Expensive |
  1400→
  1401→**Total variants across Acme Fashion:** 107
  1402→
  1403→---
  1404→
  1405→#### Acme Electronics - 5 Products (minimal seed for tenant isolation)
  1406→
  1407→These products exist for tenant isolation testing. Store 2 data must never appear in Store 1 queries.
  1408→
  1409→| # | Title | Handle | Vendor | Type | Options | Variants | Price (cents) | Weight | Inventory |
  1410→|---|-------|--------|--------|------|---------|----------|---------------|--------|-----------|
  1411→| E1 | Pro Laptop 15 | pro-laptop-15 | TechCorp | Laptops | Storage: 256GB, 512GB, 1TB | 3 | 99999, 119999, 149999 | 1800g | 10 ea |
  1412→| E2 | Wireless Headphones | wireless-headphones | AudioMax | Audio | Color: Black, Silver | 2 | 14999 | 250g | 25 ea |
  1413→| E3 | USB-C Cable 2m | usb-c-cable-2m | CablePro | Cables | (none - single default variant) | 1 | 1299 | 50g | 200 |
  1414→| E4 | Mechanical Keyboard | mechanical-keyboard | KeyTech | Peripherals | Switch Type: Red, Blue, Brown | 3 | 12999 | 1100g | 15 ea |
  1415→| E5 | Monitor Stand | monitor-stand | DeskGear | Accessories | (none - single default variant) | 1 | 4999 | 2500g | 30 |
  1416→
  1417→All active, published now, tags vary. Inventory policy = "deny" for all.
  1418→
  1419→**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.
  1420→
  1421→---
  1422→
  1423→### 3.11 DiscountSeeder
  1424→
  1425→**Acme Fashion - 5 discount codes:**
  1426→
  1427→| Code | Type | Value Type | value_amount | starts_at | ends_at | usage_limit | usage_count | rules_json | status |
  1428→|------|------|-----------|-------------|-----------|---------|-------------|-------------|-----------|--------|
  1429→| WELCOME10 | code | percent | 10 (=10%) | 2025-01-01 | 2027-12-31 | null | 3 | min_purchase_amount: 2000 (=20.00 EUR) | active |
  1430→| FLAT5 | code | fixed | 500 (=5.00 EUR) | 2025-01-01 | 2027-12-31 | null | 0 | (empty) | active |
  1431→| FREESHIP | code | free_shipping | 0 | 2025-01-01 | 2027-12-31 | null | 1 | (empty) | active |
  1432→| EXPIRED20 | code | percent | 20 (=20%) | 2024-01-01 | 2024-12-31 | null | 0 | (empty) | expired |
  1433→| MAXED | code | percent | 10 (=10%) | 2025-01-01 | 2027-12-31 | 5 | 5 | (empty) | active |
  1434→
  1435→**Behavioral expectations:**
  1436→- WELCOME10: Applies 10% off to orders with subtotal >= 20.00 EUR. Already used 3 times (has capacity remaining since no usage_limit).
  1437→- FLAT5: Applies flat 5.00 EUR discount. Never used.
  1438→- FREESHIP: Removes shipping cost. Used once.
  1439→- EXPIRED20: Expired - checkout must reject this code with "discount expired" error.
  1440→- MAXED: Usage limit of 5 reached - checkout must reject this code with "discount limit reached" error.
  1441→
  1442→---
  1443→
  1444→### 3.12 CustomerSeeder
  1445→
  1446→**Acme Fashion - 10 customers:**
  1447→
  1448→| # | Email | Name | Password (plaintext) | marketing_opt_in |
  1449→|---|-------|------|----------------------|------------------|
  1450→| 1 | customer@acme.test | John Doe | password | 1 |
  1451→| 2 | jane@example.com | Jane Smith | password | 0 |
  1452→| 3 | michael@example.com | Michael Brown | password | 1 |
  1453→| 4 | sarah@example.com | Sarah Wilson | password | 0 |
  1454→| 5 | david@example.com | David Lee | password | 1 |
  1455→| 6 | emma@example.com | Emma Garcia | password | 0 |
  1456→| 7 | james@example.com | James Taylor | password | 0 |
  1457→| 8 | lisa@example.com | Lisa Anderson | password | 1 |
  1458→| 9 | robert@example.com | Robert Martinez | password | 0 |
  1459→| 10 | anna@example.com | Anna Thomas | password | 1 |
  1460→
  1461→**Customer 1 (customer@acme.test) addresses:**
  1462→
  1463→| Label | is_default | Address Details |
  1464→|-------|-----------|-----------------|
  1465→| Home | 1 | John Doe, Hauptstrasse 1, 10115 Berlin, DE, phone: +49 30 12345678 |
  1466→| Work | 0 | John Doe, Acme Corp, Friedrichstrasse 100, 3rd Floor, 10117 Berlin, DE, phone: +49 30 87654321 |
  1467→
  1468→**Customer 2 (jane@example.com) addresses:**
  1469→
  1470→| Label | is_default | Address Details |
  1471→|-------|-----------|-----------------|
  1472→| Home | 1 | Jane Smith, Schillerstrasse 45, 80336 Munich, Bavaria (BY), DE |
  1473→
  1474→**Customers 3-10:** Each gets one default address with Faker-generated German addresses.
  1475→
  1476→**Acme Electronics - 2 customers (tenant isolation testing):**
  1477→
  1478→| # | Email | Name | Password |
  1479→|---|-------|------|----------|
  1480→| 1 | techfan@example.com | Tech Fan | password |
  1481→| 2 | gadgetlover@example.com | Gadget Lover | password |
  1482→
  1483→Each has one default address with Faker-generated data.
  1484→
  1485→---
  1486→
  1487→### 3.13 OrderSeeder
  1488→
  1489→**Acme Fashion - 15 orders:**
  1490→
  1491→All orders use the customer's default shipping address (unless noted). Order numbers follow the "#NNNN" format starting from #1001.
  1492→
  1493→---
  1494→
  1495→**Order #1001 - Awaiting fulfillment**
  1496→
  1497→| Field | Value |
  1498→|-------|-------|
  1499→| customer | customer@acme.test (John Doe) |
  1500→| status / financial / fulfillment | paid / paid / unfulfilled |
  1501→| placed_at | 2 days ago |
  1502→
  1503→Lines:
  1504→
  1505→| Product | Variant (option values) | Qty | Unit Price | Line Total |
  1506→|---------|------------------------|-----|-----------|-----------|
  1507→| Classic Cotton T-Shirt | S / White | 2 | 2499 | 4998 |
  1508→
  1509→Totals: subtotal 4998, discount 0, shipping 499, tax 798, total **5497**
  1510→
  1511→Payment: stripe, provider_payment_id "pi_test_order1001", status "captured", amount 5497
  1512→
  1513→Fulfillments: None.
  1514→
  1515→---
  1516→
  1517→**Order #1002 - Fully delivered**
  1518→
  1519→| Field | Value |
  1520→|-------|-------|
  1521→| customer | customer@acme.test (John Doe) |
  1522→| status / financial / fulfillment | fulfilled / paid / fulfilled |
  1523→| placed_at | 10 days ago |
  1524→
  1525→Lines:
  1526→
  1527→| Product | Variant | Qty | Unit Price | Line Total |
  1528→|---------|---------|-----|-----------|-----------|
  1529→| Organic Hoodie | M | 1 | 5999 | 5999 |
  1530→| Classic Cotton T-Shirt | L / Black | 1 | 2499 | 2499 |
  1531→
  1532→Totals: subtotal 8498, discount 0, shipping 499, tax 1357, total **8997**
  1533→
  1534→Payment: stripe, "pi_test_order1002", captured, 8997
  1535→
  1536→Fulfillment: status "delivered", tracking company "DHL", tracking number "DHL1234567890", shipped 8 days ago. Fulfillment lines cover all order lines at full quantity.
  1537→
  1538→---
  1539→
  1540→**Order #1003 - Partially fulfilled**
  1541→
  1542→| Field | Value |
  1543→|-------|-------|
  1544→| customer | jane@example.com (Jane Smith) |
  1545→| status / financial / fulfillment | paid / paid / partial |
  1546→| placed_at | 5 days ago |
  1547→
  1548→Lines:
  1549→
  1550→| Product | Variant | Qty | Unit Price | Line Total |
  1551→|---------|---------|-----|-----------|-----------|
  1552→| Premium Slim Fit Jeans | 32 / Blue | 1 | 7999 | 7999 |
  1553→| Leather Belt | L/XL / Brown | 1 | 3499 | 3499 |
  1554→
  1555→Totals: subtotal 11498, discount 0, shipping 499, tax 1836, total **11997**
  1556→
  1557→Payment: stripe, "pi_test_order1003", captured, 11997
  1558→
  1559→Fulfillment: status "shipped", DHL, "DHL9876543210", shipped 3 days ago. Fulfillment lines: **only the Jeans line (qty 1)**. The Belt is not yet shipped.
  1560→
  1561→---
  1562→
  1563→**Order #1004 - Cancelled with full refund**
  1564→
  1565→| Field | Value |
  1566→|-------|-------|
  1567→| customer | customer@acme.test (John Doe) |
  1568→| status / financial / fulfillment | cancelled / refunded / unfulfilled |
  1569→| placed_at | 15 days ago |
  1570→
  1571→Lines:
  1572→
  1573→| Product | Variant | Qty | Unit Price | Line Total |
  1574→|---------|---------|-----|-----------|-----------|
  1575→| Classic Cotton T-Shirt | M / Navy | 1 | 2499 | 2499 |
  1576→
  1577→Totals: subtotal 2499, discount 0, shipping 499, tax 399, total **2998**
  1578→
  1579→Payment: stripe, "pi_test_order1004", status "refunded", amount 2998
  1580→
  1581→Refund: amount 2998, reason "Customer requested cancellation", status "processed", provider_refund_id "re_test_order1004"
  1582→
  1583→---
  1584→
  1585→**Order #1005 - Payment pending**
  1586→
  1587→| Field | Value |
  1588→|-------|-------|
  1589→| customer | jane@example.com (Jane Smith) |
  1590→| status / financial / fulfillment | pending / pending / unfulfilled |
  1591→| placed_at | 2 hours ago |
  1592→
  1593→Lines:
  1594→
  1595→| Product | Variant | Qty | Unit Price | Line Total |
  1596→|---------|---------|-----|-----------|-----------|
  1597→| Leather Belt | S/M / Black | 1 | 3499 | 3499 |
  1598→
  1599→Totals: subtotal 3499, discount 0, shipping 499, tax 559, total **3998**
  1600→
  1601→Payment: stripe, "pi_test_order1005", status "requires_action", amount 3998
  1602→
  1603→---
  1604→
  1605→**Order #1006 - Standard paid order**
  1606→
  1607→| Field | Value |
  1608→|-------|-------|
  1609→| customer | michael@example.com (Michael Brown) |
  1610→| status / financial / fulfillment | paid / paid / unfulfilled |
  1611→| placed_at | 1 day ago |
  1612→
  1613→Lines:
  1614→
  1615→| Product | Variant | Qty | Unit Price | Line Total |
  1616→|---------|---------|-----|-----------|-----------|
  1617→| Running Sneakers | EU 42 / Black | 1 | 11999 | 11999 |
  1618→
  1619→Totals: subtotal 11999, discount 0, shipping 499, tax 1916, total **12498**
  1620→
  1621→Payment: stripe, "pi_test_order1006", captured, 12498
  1622→
  1623→---
  1624→
  1625→**Order #1007 - Multi-item delivered**
  1626→
  1627→| Field | Value |
  1628→|-------|-------|
  1629→| customer | sarah@example.com (Sarah Wilson) |
  1630→| status / financial / fulfillment | fulfilled / paid / fulfilled |
  1631→| placed_at | 20 days ago |
  1632→
  1633→Lines:
  1634→
  1635→| Product | Variant | Qty | Unit Price | Line Total |
  1636→|---------|---------|-----|-----------|-----------|
  1637→| V-Neck Linen Tee | M / Beige | 2 | 3499 | 6998 |
  1638→| Wool Scarf | Grey | 1 | 2999 | 2999 |
  1639→
  1640→Totals: subtotal 9997, discount 0, shipping 499, tax 1596, total **10496**
  1641→
  1642→Payment: stripe, captured, 10496
  1643→
  1644→Fulfillment: delivered, DHL, "DHL1112223334", shipped 18 days ago. All lines fulfilled.
  1645→
  1646→---
  1647→
  1648→**Order #1008 - Partial refund**
  1649→
  1650→| Field | Value |
  1651→|-------|-------|
  1652→| customer | david@example.com (David Lee) |
  1653→| status / financial / fulfillment | paid / partially_refunded / fulfilled |
  1654→| placed_at | 12 days ago |
  1655→
  1656→Lines:
  1657→
  1658→| Product | Variant | Qty | Unit Price | Line Total |
  1659→|---------|---------|-----|-----------|-----------|
  1660→| Cargo Pants | 32 / Khaki | 1 | 5499 | 5499 |
  1661→| Graphic Print Tee | L | 1 | 2999 | 2999 |
  1662→
  1663→Totals: subtotal 8498, discount 0, shipping 499, tax 1357, total **8997**
  1664→
  1665→Payment: stripe, captured, 8997
  1666→
  1667→Fulfillment: delivered, UPS, "UPS5556667778", shipped 10 days ago
  1668→
  1669→Refund (partial - for Graphic Print Tee only): amount 2999, reason "Item returned", status "processed", provider_refund_id "re_test_order1008"
  1670→
  1671→---
  1672→
  1673→**Order #1009 - Accessories order**
  1674→
  1675→| Field | Value |
  1676→|-------|-------|
  1677→| customer | emma@example.com (Emma Garcia) |
  1678→| status / financial / fulfillment | paid / paid / unfulfilled |
  1679→| placed_at | 3 days ago |
  1680→
  1681→Lines:
  1682→
  1683→| Product | Variant | Qty | Unit Price | Line Total |
  1684→|---------|---------|-----|-----------|-----------|
  1685→| Canvas Tote Bag | Natural | 1 | 1999 | 1999 |
  1686→| Bucket Hat | S/M / Black | 1 | 2499 | 2499 |
  1687→
  1688→Totals: subtotal 4498, discount 0, shipping 499, tax 718, total **4997**
  1689→
  1690→Payment: stripe, captured, 4997
  1691→
  1692→---
  1693→
  1694→**Order #1010 - High-value order**
  1695→
  1696→| Field | Value |
  1697→|-------|-------|
  1698→| customer | customer@acme.test (John Doe) |
  1699→| status / financial / fulfillment | paid / paid / unfulfilled |
  1700→| placed_at | 1 day ago |
  1701→
  1702→Lines:
  1703→
  1704→| Product | Variant | Qty | Unit Price | Line Total |
  1705→|---------|---------|-----|-----------|-----------|
  1706→| Cashmere Overcoat | M / Camel | 1 | 49999 | 49999 |
  1707→
  1708→Totals: subtotal 49999, discount 0, shipping 499, tax 7983, total **50498**
  1709→
  1710→Payment: stripe, captured, 50498
  1711→
  1712→---
  1713→
  1714→**Order #1011 - Single item delivered**
  1715→
  1716→| Field | Value |
  1717→|-------|-------|
  1718→| customer | james@example.com (James Taylor) |
  1719→| status / financial / fulfillment | paid / paid / fulfilled |
  1720→| placed_at | 25 days ago |
  1721→
  1722→Lines:
  1723→
  1724→| Product | Variant | Qty | Unit Price | Line Total |
  1725→|---------|---------|-----|-----------|-----------|
  1726→| Striped Polo Shirt | XL | 1 | 2799 | 2799 |
  1727→
  1728→Totals: subtotal 2799, discount 0, shipping 499, tax 447, total **3298**
  1729→
  1730→Payment: stripe, captured, 3298
  1731→
  1732→Fulfillment: delivered, FedEx, "FX9998887776", shipped 23 days ago
  1733→
  1734→---
  1735→
  1736→**Order #1012 - Multi-quantity order**
  1737→
  1738→| Field | Value |
  1739→|-------|-------|
  1740→| customer | lisa@example.com (Lisa Anderson) |
  1741→| status / financial / fulfillment | paid / paid / unfulfilled |
  1742→| placed_at | 4 days ago |
  1743→
  1744→Lines:
  1745→
  1746→| Product | Variant | Qty | Unit Price | Line Total |
  1747→|---------|---------|-----|-----------|-----------|
  1748→| Chino Shorts | 34 / Navy | 2 | 3999 | 7998 |
  1749→
  1750→Totals: subtotal 7998, discount 0, shipping 499, tax 1277, total **8497**
  1751→
  1752→Payment: stripe, captured, 8497
  1753→
  1754→---
  1755→
  1756→**Order #1013 - Multi-item order**
  1757→
  1758→| Field | Value |
  1759→|-------|-------|
  1760→| customer | robert@example.com (Robert Martinez) |
  1761→| status / financial / fulfillment | paid / paid / unfulfilled |
  1762→| placed_at | 1 day ago |
  1763→
  1764→Lines:
  1765→
  1766→| Product | Variant | Qty | Unit Price | Line Total |
  1767→|---------|---------|-----|-----------|-----------|
  1768→| Wide Leg Trousers | M | 1 | 4999 | 4999 |
  1769→| Wool Scarf | Burgundy | 1 | 2999 | 2999 |
  1770→
  1771→Totals: subtotal 7998, discount 0, shipping 499, tax 1277, total **8497**
  1772→
  1773→Payment: stripe, captured, 8497
  1774→
  1775→---
  1776→
  1777→**Order #1014 - Digital product order**
  1778→
  1779→| Field | Value |
  1780→|-------|-------|
  1781→| customer | anna@example.com (Anna Thomas) |
  1782→| status / financial / fulfillment | paid / paid / fulfilled |
  1783→| placed_at | 14 days ago |
  1784→
  1785→Lines:
  1786→
  1787→| Product | Variant | Qty | Unit Price | Line Total |
  1788→|---------|---------|-----|-----------|-----------|
  1789→| Gift Card | 50 EUR | 1 | 5000 | 5000 |
  1790→
  1791→Totals: subtotal 5000, discount 0, shipping **0** (digital product), tax 798, total **5000**
  1792→
  1793→Payment: stripe, captured, 5000
  1794→
  1795→Fulfillment: delivered (digital fulfillment), no tracking company, no tracking number, shipped_at = placed_at
  1796→
  1797→---
  1798→
  1799→**Order #1015 - Order with discount**
  1800→
  1801→| Field | Value |
  1802→|-------|-------|
  1803→| customer | customer@acme.test (John Doe) |
  1804→| status / financial / fulfillment | paid / paid / unfulfilled |
  1805→| placed_at | now (today) |
  1806→
  1807→Lines:
  1808→
  1809→| Product | Variant | Qty | Unit Price | Line Total | Discount Allocation |
  1810→|---------|---------|-----|-----------|-----------|-------------------|
  1811→| Classic Cotton T-Shirt | M / White | 1 | 2499 | 2499 | WELCOME10 discount, amount: 250 |
  1812→| Graphic Print Tee | M | 1 | 2999 | 2999 | WELCOME10 discount, amount: 300 |
  1813→
  1814→Totals: subtotal 5498, discount **550**, shipping 499, tax 790, total **5447**
  1815→
  1816→Payment: stripe, captured, 5447
  1817→
  1818→The discount_allocations_json on each order line references the WELCOME10 discount's database ID and the allocated discount amount for that specific line.
  1819→
  1820→---
  1821→
  1822→#### Order Summary Table (Acme Fashion)
  1823→
  1824→| Order | Customer | Status | Financial | Fulfillment | Total | Key Test Scenario |
  1825→|-------|----------|--------|-----------|-------------|-------|-------------------|
  1826→| #1001 | John Doe | paid | paid | unfulfilled | 5497 | Awaiting fulfillment |
  1827→| #1002 | John Doe | fulfilled | paid | fulfilled | 8997 | Delivered order |
  1828→| #1003 | Jane Smith | paid | paid | partial | 11997 | Partial fulfillment |
  1829→| #1004 | John Doe | cancelled | refunded | unfulfilled | 2998 | Full cancellation + refund |
  1830→| #1005 | Jane Smith | pending | pending | unfulfilled | 3998 | Payment pending |
  1831→| #1006 | Michael Brown | paid | paid | unfulfilled | 12498 | Standard paid order |
  1832→| #1007 | Sarah Wilson | fulfilled | paid | fulfilled | 10496 | Multi-item delivered |
  1833→| #1008 | David Lee | paid | partially_refunded | fulfilled | 8997 | Partial refund |
  1834→| #1009 | Emma Garcia | paid | paid | unfulfilled | 4997 | Accessories order |
  1835→| #1010 | John Doe | paid | paid | unfulfilled | 50498 | High-value order |
  1836→| #1011 | James Taylor | paid | paid | fulfilled | 3298 | Single item delivered |
  1837→| #1012 | Lisa Anderson | paid | paid | unfulfilled | 8497 | Multi-quantity order |
  1838→| #1013 | Robert Martinez | paid | paid | unfulfilled | 8497 | Multi-item order |
  1839→| #1014 | Anna Thomas | paid | paid | fulfilled | 5000 | Digital product order |
  1840→| #1015 | John Doe | paid | paid | unfulfilled | 5447 | Order with discount |
  1841→
  1842→---
  1843→
  1844→**Acme Electronics - 3 orders (minimal, for tenant isolation):**
  1845→
  1846→| Order | Customer | Status | Financial | Fulfillment | Total | Details |
  1847→|-------|----------|--------|-----------|-------------|-------|---------|
  1848→| #5001 | techfan@example.com | paid | paid | fulfilled | 121298 | Pro Laptop 512GB (119999) + USB-C Cable (1299), shipping 0 |
  1849→| #5002 | gadgetlover@example.com | paid | paid | unfulfilled | 14999 | Wireless Headphones Black (14999), shipping 0 |
  1850→| #5003 | techfan@example.com | pending | pending | unfulfilled | 4999 | Monitor Stand (4999), shipping 0, payment requires_action |
  1851→
  1852→---
  1853→
  1854→### 3.14 ThemeSeeder
  1855→
  1856→**Acme Fashion:**
  1857→
  1858→| Field | Value |
  1859→|-------|-------|
  1860→| name | Default Theme |
  1861→| version | 1.0.0 |
  1862→| status | published |
  1863→| published_at | now |
  1864→
  1865→**Theme settings (theme_settings row):**
  1866→
  1867→| Setting Key | Value |
  1868→|-------------|-------|
  1869→| primary_color | #1a1a2e |
  1870→| secondary_color | #e94560 |
  1871→| font_family | Inter, sans-serif |
  1872→| hero_heading | Welcome to Acme Fashion |
  1873→| hero_subheading | Discover our curated collection of modern essentials |
  1874→| hero_cta_text | Shop New Arrivals |
  1875→| hero_cta_link | /collections/new-arrivals |
  1876→| featured_collection_handles | ["new-arrivals", "t-shirts", "sale"] |
  1877→| footer_text | 2025 Acme Fashion. All rights reserved. |
  1878→| show_announcement_bar | true |
  1879→| announcement_text | Free shipping on orders over 50 EUR - Use code FREESHIP |
  1880→| products_per_page | 12 |
  1881→| show_vendor | true |
  1882→| show_quantity_selector | true |
  1883→
  1884→**Acme Electronics:**
  1885→
  1886→| Field | Value |
  1887→|-------|-------|
  1888→| name | Default Theme |
  1889→| version | 1.0.0 |
  1890→| status | published |
  1891→
  1892→Theme settings:
  1893→
  1894→| Setting Key | Value |
  1895→|-------------|-------|
  1896→| primary_color | #0f172a |
  1897→| secondary_color | #3b82f6 |
  1898→| font_family | Inter, sans-serif |
  1899→| hero_heading | Acme Electronics |
  1900→| hero_subheading | Premium tech for professionals |
  1901→| hero_cta_text | Shop Featured |
  1902→| hero_cta_link | /collections/featured |
  1903→| featured_collection_handles | ["featured"] |
  1904→| footer_text | 2025 Acme Electronics. All rights reserved. |
  1905→
  1906→---
  1907→
  1908→### 3.15 PageSeeder
  1909→
  1910→**Acme Fashion - 5 content pages:**
  1911→
  1912→All pages: status = "published", published_at = 3 months ago.
  1913→
  1914→**Page 1: About Us**
  1915→- handle: about
  1916→- 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.
  1917→
  1918→**Page 2: FAQ**
  1919→- handle: faq
  1920→- body_html content: h2 "Frequently Asked Questions" followed by four Q&A pairs using h3/p structure:
  1921→  1. Shipping timeframes (Germany 2-4 days standard, 1-2 express; EU 5-7 days)
  1922→  2. Return policy (30 days, unworn, original packaging)
  1923→  3. International shipping (EU + US, UK, CA, AU)
  1924→  4. Order tracking (email with tracking number after shipment)
  1925→
  1926→**Page 3: Shipping & Returns**
  1927→- handle: shipping-returns
  1928→- 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).
  1929→
  1930→**Page 4: Privacy Policy**
  1931→- handle: privacy-policy
  1932→- 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.
  1933→
  1934→**Page 5: Terms of Service**
  1935→- handle: terms
  1936→- 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.
  1937→
  1938→---
  1939→
  1940→### 3.16 NavigationSeeder
  1941→
  1942→**Acme Fashion - Main Menu (handle: main-menu, title: "Main Menu"):**
  1943→
  1944→| Position | Label | Type | Target |
  1945→|----------|-------|------|--------|
  1946→| 0 | Home | link | URL: / |
  1947→| 1 | New Arrivals | collection | resource_id: ID of "New Arrivals" collection |
  1948→| 2 | T-Shirts | collection | resource_id: ID of "T-Shirts" collection |
  1949→| 3 | Pants & Jeans | collection | resource_id: ID of "Pants & Jeans" collection |
  1950→| 4 | Sale | collection | resource_id: ID of "Sale" collection |
  1951→
  1952→**Acme Fashion - Footer Menu (handle: footer-menu, title: "Footer Menu"):**
  1953→
  1954→| Position | Label | Type | Target |
  1955→|----------|-------|------|--------|
  1956→| 0 | About Us | page | resource_id: ID of "About Us" page |
  1957→| 1 | FAQ | page | resource_id: ID of "FAQ" page |
  1958→| 2 | Shipping & Returns | page | resource_id: ID of "Shipping & Returns" page |
  1959→| 3 | Privacy Policy | page | resource_id: ID of "Privacy Policy" page |
  1960→| 4 | Terms of Service | page | resource_id: ID of "Terms of Service" page |
  1961→
  1962→**Acme Electronics - Main Menu (handle: main-menu, title: "Main Menu"):**
  1963→
  1964→| Position | Label | Type | Target |
  1965→|----------|-------|------|--------|
  1966→| 0 | Home | link | URL: / |
  1967→| 1 | Featured | collection | resource_id: ID of "Featured" collection |
  1968→| 2 | Accessories | collection | resource_id: ID of "Accessories" collection |
  1969→
  1970→---
  1971→
  1972→### 3.17 AnalyticsSeeder
  1973→
  1974→**Acme Fashion - analytics_daily (30 days of daily data):**
  1975→
  1976→Generate one row per day for the past 30 days (today minus 30 through today). Revenue trends upward to simulate growth.
  1977→
  1978→**Generation algorithm (pseudo-code):**
  1979→
  1980→```
  1981→FOR i FROM 30 DOWN TO 0:
  1982→    dayFactor = 1 + (30 - i) * 0.03       // ~3% daily growth factor
  1983→    visits = ROUND(RANDOM(50, 100) * dayFactor)
  1984→    addToCart = ROUND(visits * RANDOM(18, 25) / 100)
  1985→    checkoutStarted = ROUND(addToCart * RANDOM(40, 55) / 100)
  1986→    orders = MAX(2, ROUND(checkoutStarted * RANDOM(35, 55) / 100))
  1987→    aov = RANDOM(4000, 9000)               // average order value in cents
  1988→    revenue = orders * aov
  1989→
  1990→    INSERT analytics_daily:
  1991→        store_id = Acme Fashion ID
  1992→        date = TODAY minus i days (ISO format YYYY-MM-DD)
  1993→        visits_count = visits
  1994→        add_to_cart_count = addToCart
  1995→        checkout_started_count = checkoutStarted
  1996→        orders_count = orders
  1997→        revenue_amount = revenue
  1998→        aov_amount = aov
  1999→```

| Field | Value |
|-------|-------|
| handle | canvas-tote-bag |
| status | active |
| vendor | Acme Accessories |
| product_type | Accessories |
| tags | ["trending"] |
| description_html | "Heavy-duty canvas tote bag with reinforced handles. Spacious enough for daily essentials." |
| published_at | now |

Collections: (none)

Options: Color (Natural, Black)

Variants (2 total): price_amount = 1999, weight_g = 300, inventory = 40 each (deny)

---

**Product 14: "Bucket Hat"**

| Field | Value |
|-------|-------|
| handle | bucket-hat |
| status | active |
| vendor | Acme Accessories |
| product_type | Accessories |
| tags | ["new", "trending"] |
| description_html | "Lightweight bucket hat for sun protection. Packable design, washed cotton twill." |
| published_at | now |

Collections: New Arrivals

Options: Size (S/M, L/XL), Color (Beige, Black, Olive)

Variants (6 total): price_amount = 2499, weight_g = 80, inventory = 22 each (deny)

---

**Product 15: "Unreleased Winter Jacket" -- DRAFT**

| Field | Value |
|-------|-------|
| handle | unreleased-winter-jacket |
| status | **draft** |
| vendor | Acme Outerwear |
| product_type | Jackets |
| tags | ["limited"] |
| description_html | "Upcoming winter collection piece. Insulated puffer jacket with water-resistant shell." |
| published_at | **null** |

Collections: (none - draft not assigned)

Options: Size (S, M, L, XL)

Variants (4 total): price_amount = 14999, weight_g = 900, inventory = **0 each** (deny)

**Test purpose:** Verifies draft products do not appear on the storefront.

---

**Product 16: "Discontinued Raincoat" -- ARCHIVED**

| Field | Value |
|-------|-------|
| handle | discontinued-raincoat |
| status | **archived** |
| vendor | Acme Outerwear |
| product_type | Jackets |
| tags | [] |
| description_html | "Lightweight waterproof raincoat. This product has been discontinued." |
| published_at | 6 months ago |

Collections: (none)

Options: Size (M, L)

Variants (2 total): price_amount = 8999, weight_g = 400, inventory = 3 each (deny)

**Test purpose:** Verifies archived products do not appear on the storefront.

---

**Product 17: "Limited Edition Sneakers" -- SOLD OUT (deny policy)**

| Field | Value |
|-------|-------|
| handle | limited-edition-sneakers |
| status | active |
| vendor | Acme Sport |
| product_type | Shoes |
| tags | ["limited"] |
| description_html | "Limited edition collaboration sneakers. Once they are gone, they are gone." |
| published_at | now |

Collections: (none)

Options: Size (EU 40, EU 42, EU 44)

Variants (3 total): price_amount = 15999, weight_g = 650, inventory = **0 each, policy = "deny"**

**Test purpose:** Tests "sold out" display and add-to-cart prevention.

---

**Product 18: "Backorder Denim Jacket" -- OUT OF STOCK (continue policy)**

| Field | Value |
|-------|-------|
| handle | backorder-denim-jacket |
| status | active |
| vendor | Acme Denim |
| product_type | Jackets |
| tags | ["popular"] |
| description_html | "Classic denim jacket. Currently on backorder - ships within 2-3 weeks." |
| published_at | now |

Collections: (none)

Options: Size (S, M, L, XL)

Variants (4 total): price_amount = 9999, weight_g = 750, inventory = **0 each, policy = "continue"**

**Test purpose:** Tests that items with "continue" inventory policy can be added to cart despite zero stock.

---

**Product 19: "Gift Card" -- DIGITAL (no shipping)**

| Field | Value |
|-------|-------|
| handle | gift-card |
| status | active |
| vendor | Acme Fashion |
| product_type | Gift Cards |
| tags | ["popular"] |
| description_html | "Digital gift card delivered via email. The perfect gift when you are not sure what to choose." |
| published_at | now |

Collections: (none)

Options: Amount (25 EUR, 50 EUR, 100 EUR)

Variants (3 total - each a different denomination):

| SKU | Price (cents) | Weight | requires_shipping | Inventory |
|-----|---------------|--------|-------------------|-----------|
| ACME-GIFT-25 | 2500 | 0g | **0 (digital)** | 9999 (deny) |
| ACME-GIFT-50 | 5000 | 0g | **0 (digital)** | 9999 (deny) |
| ACME-GIFT-100 | 10000 | 0g | **0 (digital)** | 9999 (deny) |

**Test purpose:** Tests digital product flow (no shipping step in checkout).

---

**Product 20: "Cashmere Overcoat" -- EXPENSIVE**

| Field | Value |
|-------|-------|
| handle | cashmere-overcoat |
| status | active |
| vendor | Acme Premium |
| product_type | Jackets |
| tags | ["limited", "new"] |
| description_html | "Luxurious cashmere-blend overcoat. Impeccable tailoring with silk lining." |
| published_at | now |

Collections: New Arrivals

Options: Size (S, M, L), Color (Camel, Charcoal)

Variants (6 total): price_amount = 49999 (499.99 EUR), weight_g = 1200, inventory = 3 each (deny)

**Test purpose:** Tests high-value price display (499.99 EUR).

---

#### Product Summary Table (Acme Fashion)

| # | Title | Handle | Status | Price (cents) | Compare At | Variants | Inventory | Special |
|---|-------|--------|--------|---------------|-----------|----------|-----------|---------|
| 1 | Classic Cotton T-Shirt | classic-cotton-t-shirt | active | 2499 | - | 12 | 15 ea | - |
| 2 | Premium Slim Fit Jeans | premium-slim-fit-jeans | active | 7999 | 9999 | 10 | 8 ea | On sale |
| 3 | Organic Hoodie | organic-hoodie | active | 5999 | - | 4 | 20 ea | - |
| 4 | Leather Belt | leather-belt | active | 3499 | - | 4 | 25 ea | - |
| 5 | Running Sneakers | running-sneakers | active | 11999 | - | 14 | 5 ea | Low stock |
| 6 | Graphic Print Tee | graphic-print-tee | active | 2999 | - | 4 | 18 ea | - |
| 7 | V-Neck Linen Tee | v-neck-linen-tee | active | 3499 | - | 9 | 12 ea | - |
| 8 | Striped Polo Shirt | striped-polo-shirt | active | 2799 | 3999 | 4 | 10 ea | On sale |
| 9 | Cargo Pants | cargo-pants | active | 5499 | - | 12 | 14 ea | - |
| 10 | Chino Shorts | chino-shorts | active | 3999 | - | 8 | 16 ea | - |
| 11 | Wide Leg Trousers | wide-leg-trousers | active | 4999 | 6999 | 3 | 7 ea | On sale |
| 12 | Wool Scarf | wool-scarf | active | 2999 | - | 3 | 30 ea | - |
| 13 | Canvas Tote Bag | canvas-tote-bag | active | 1999 | - | 2 | 40 ea | - |
| 14 | Bucket Hat | bucket-hat | active | 2499 | - | 6 | 22 ea | - |
| 15 | Unreleased Winter Jacket | unreleased-winter-jacket | draft | 14999 | - | 4 | 0 ea | Draft |
| 16 | Discontinued Raincoat | discontinued-raincoat | archived | 8999 | - | 2 | 3 ea | Archived |
| 17 | Limited Edition Sneakers | limited-edition-sneakers | active | 15999 | - | 3 | 0 ea | Sold out (deny) |
| 18 | Backorder Denim Jacket | backorder-denim-jacket | active | 9999 | - | 4 | 0 ea | Backorder (continue) |
| 19 | Gift Card | gift-card | active | 2500/5000/10000 | - | 3 | 9999 ea | Digital |
| 20 | Cashmere Overcoat | cashmere-overcoat | active | 49999 | - | 6 | 3 ea | Expensive |

**Total variants across Acme Fashion:** 107

---

#### Acme Electronics - 5 Products (minimal seed for tenant isolation)

These products exist for tenant isolation testing. Store 2 data must never appear in Store 1 queries.

| # | Title | Handle | Vendor | Type | Options | Variants | Price (cents) | Weight | Inventory |
|---|-------|--------|--------|------|---------|----------|---------------|--------|-----------|
| E1 | Pro Laptop 15 | pro-laptop-15 | TechCorp | Laptops | Storage: 256GB, 512GB, 1TB | 3 | 99999, 119999, 149999 | 1800g | 10 ea |
| E2 | Wireless Headphones | wireless-headphones | AudioMax | Audio | Color: Black, Silver | 2 | 14999 | 250g | 25 ea |
| E3 | USB-C Cable 2m | usb-c-cable-2m | CablePro | Cables | (none - single default variant) | 1 | 1299 | 50g | 200 |
| E4 | Mechanical Keyboard | mechanical-keyboard | KeyTech | Peripherals | Switch Type: Red, Blue, Brown | 3 | 12999 | 1100g | 15 ea |
| E5 | Monitor Stand | monitor-stand | DeskGear | Accessories | (none - single default variant) | 1 | 4999 | 2500g | 30 |

All active, published now, tags vary. Inventory policy = "deny" for all.

**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.

---

### 3.11 DiscountSeeder

**Acme Fashion - 5 discount codes:**

| Code | Type | Value Type | value_amount | starts_at | ends_at | usage_limit | usage_count | rules_json | status |
|------|------|-----------|-------------|-----------|---------|-------------|-------------|-----------|--------|
| WELCOME10 | code | percent | 10 (=10%) | 2025-01-01 | 2027-12-31 | null | 3 | min_purchase_amount: 2000 (=20.00 EUR) | active |
| FLAT5 | code | fixed | 500 (=5.00 EUR) | 2025-01-01 | 2027-12-31 | null | 0 | (empty) | active |
| FREESHIP | code | free_shipping | 0 | 2025-01-01 | 2027-12-31 | null | 1 | (empty) | active |
| EXPIRED20 | code | percent | 20 (=20%) | 2024-01-01 | 2024-12-31 | null | 0 | (empty) | expired |
| MAXED | code | percent | 10 (=10%) | 2025-01-01 | 2027-12-31 | 5 | 5 | (empty) | active |

**Behavioral expectations:**
- WELCOME10: Applies 10% off to orders with subtotal >= 20.00 EUR. Already used 3 times (has capacity remaining since no usage_limit).
- FLAT5: Applies flat 5.00 EUR discount. Never used.
- FREESHIP: Removes shipping cost. Used once.
- EXPIRED20: Expired - checkout must reject this code with "discount expired" error.
- MAXED: Usage limit of 5 reached - checkout must reject this code with "discount limit reached" error.

---

### 3.12 CustomerSeeder

**Acme Fashion - 10 customers:**

| # | Email | Name | Password (plaintext) | marketing_opt_in |
|---|-------|------|----------------------|------------------|
| 1 | customer@acme.test | John Doe | password | 1 |
| 2 | jane@example.com | Jane Smith | password | 0 |
| 3 | michael@example.com | Michael Brown | password | 1 |
| 4 | sarah@example.com | Sarah Wilson | password | 0 |
| 5 | david@example.com | David Lee | password | 1 |
| 6 | emma@example.com | Emma Garcia | password | 0 |
| 7 | james@example.com | James Taylor | password | 0 |
| 8 | lisa@example.com | Lisa Anderson | password | 1 |
| 9 | robert@example.com | Robert Martinez | password | 0 |
| 10 | anna@example.com | Anna Thomas | password | 1 |

**Customer 1 (customer@acme.test) addresses:**

| Label | is_default | Address Details |
|-------|-----------|-----------------|
| Home | 1 | John Doe, Hauptstrasse 1, 10115 Berlin, DE, phone: +49 30 12345678 |
| Work | 0 | John Doe, Acme Corp, Friedrichstrasse 100, 3rd Floor, 10117 Berlin, DE, phone: +49 30 87654321 |

**Customer 2 (jane@example.com) addresses:**

| Label | is_default | Address Details |
|-------|-----------|-----------------|
| Home | 1 | Jane Smith, Schillerstrasse 45, 80336 Munich, Bavaria (BY), DE |

**Customers 3-10:** Each gets one default address with Faker-generated German addresses.

**Acme Electronics - 2 customers (tenant isolation testing):**

| # | Email | Name | Password |
|---|-------|------|----------|
| 1 | techfan@example.com | Tech Fan | password |
| 2 | gadgetlover@example.com | Gadget Lover | password |

Each has one default address with Faker-generated data.

---

### 3.13 OrderSeeder

**Acme Fashion - 15 orders:**

All orders use the customer's default shipping address (unless noted). Order numbers follow the "#NNNN" format starting from #1001.

---

**Order #1001 - Awaiting fulfillment**

| Field | Value |
|-------|-------|
| customer | customer@acme.test (John Doe) |
| status / financial / fulfillment | paid / paid / unfulfilled |
| placed_at | 2 days ago |

Lines:

| Product | Variant (option values) | Qty | Unit Price | Line Total |
|---------|------------------------|-----|-----------|-----------|
| Classic Cotton T-Shirt | S / White | 2 | 2499 | 4998 |

Totals: subtotal 4998, discount 0, shipping 499, tax 798, total **5497**

Payment: stripe, provider_payment_id "pi_test_order1001", status "captured", amount 5497

Fulfillments: None.

---

**Order #1002 - Fully delivered**

| Field | Value |
|-------|-------|
| customer | customer@acme.test (John Doe) |
| status / financial / fulfillment | fulfilled / paid / fulfilled |
| placed_at | 10 days ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Organic Hoodie | M | 1 | 5999 | 5999 |
| Classic Cotton T-Shirt | L / Black | 1 | 2499 | 2499 |

Totals: subtotal 8498, discount 0, shipping 499, tax 1357, total **8997**

Payment: stripe, "pi_test_order1002", captured, 8997

Fulfillment: status "delivered", tracking company "DHL", tracking number "DHL1234567890", shipped 8 days ago. Fulfillment lines cover all order lines at full quantity.

---

**Order #1003 - Partially fulfilled**

| Field | Value |
|-------|-------|
| customer | jane@example.com (Jane Smith) |
| status / financial / fulfillment | paid / paid / partial |
| placed_at | 5 days ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Premium Slim Fit Jeans | 32 / Blue | 1 | 7999 | 7999 |
| Leather Belt | L/XL / Brown | 1 | 3499 | 3499 |

Totals: subtotal 11498, discount 0, shipping 499, tax 1836, total **11997**

Payment: stripe, "pi_test_order1003", captured, 11997

Fulfillment: status "shipped", DHL, "DHL9876543210", shipped 3 days ago. Fulfillment lines: **only the Jeans line (qty 1)**. The Belt is not yet shipped.

---

**Order #1004 - Cancelled with full refund**

| Field | Value |
|-------|-------|
| customer | customer@acme.test (John Doe) |
| status / financial / fulfillment | cancelled / refunded / unfulfilled |
| placed_at | 15 days ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Classic Cotton T-Shirt | M / Navy | 1 | 2499 | 2499 |

Totals: subtotal 2499, discount 0, shipping 499, tax 399, total **2998**

Payment: stripe, "pi_test_order1004", status "refunded", amount 2998

Refund: amount 2998, reason "Customer requested cancellation", status "processed", provider_refund_id "re_test_order1004"

---

**Order #1005 - Payment pending**

| Field | Value |
|-------|-------|
| customer | jane@example.com (Jane Smith) |
| status / financial / fulfillment | pending / pending / unfulfilled |
| placed_at | 2 hours ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Leather Belt | S/M / Black | 1 | 3499 | 3499 |

Totals: subtotal 3499, discount 0, shipping 499, tax 559, total **3998**

Payment: stripe, "pi_test_order1005", status "requires_action", amount 3998

---

**Order #1006 - Standard paid order**

| Field | Value |
|-------|-------|
| customer | michael@example.com (Michael Brown) |
| status / financial / fulfillment | paid / paid / unfulfilled |
| placed_at | 1 day ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Running Sneakers | EU 42 / Black | 1 | 11999 | 11999 |

Totals: subtotal 11999, discount 0, shipping 499, tax 1916, total **12498**

Payment: stripe, "pi_test_order1006", captured, 12498

---

**Order #1007 - Multi-item delivered**

| Field | Value |
|-------|-------|
| customer | sarah@example.com (Sarah Wilson) |
| status / financial / fulfillment | fulfilled / paid / fulfilled |
| placed_at | 20 days ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| V-Neck Linen Tee | M / Beige | 2 | 3499 | 6998 |
| Wool Scarf | Grey | 1 | 2999 | 2999 |

Totals: subtotal 9997, discount 0, shipping 499, tax 1596, total **10496**

Payment: stripe, captured, 10496

Fulfillment: delivered, DHL, "DHL1112223334", shipped 18 days ago. All lines fulfilled.

---

**Order #1008 - Partial refund**

| Field | Value |
|-------|-------|
| customer | david@example.com (David Lee) |
| status / financial / fulfillment | paid / partially_refunded / fulfilled |
| placed_at | 12 days ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Cargo Pants | 32 / Khaki | 1 | 5499 | 5499 |
| Graphic Print Tee | L | 1 | 2999 | 2999 |

Totals: subtotal 8498, discount 0, shipping 499, tax 1357, total **8997**

Payment: stripe, captured, 8997

Fulfillment: delivered, UPS, "UPS5556667778", shipped 10 days ago

Refund (partial - for Graphic Print Tee only): amount 2999, reason "Item returned", status "processed", provider_refund_id "re_test_order1008"

---

**Order #1009 - Accessories order**

| Field | Value |
|-------|-------|
| customer | emma@example.com (Emma Garcia) |
| status / financial / fulfillment | paid / paid / unfulfilled |
| placed_at | 3 days ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Canvas Tote Bag | Natural | 1 | 1999 | 1999 |
| Bucket Hat | S/M / Black | 1 | 2499 | 2499 |

Totals: subtotal 4498, discount 0, shipping 499, tax 718, total **4997**

Payment: stripe, captured, 4997

---

**Order #1010 - High-value order**

| Field | Value |
|-------|-------|
| customer | customer@acme.test (John Doe) |
| status / financial / fulfillment | paid / paid / unfulfilled |
| placed_at | 1 day ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Cashmere Overcoat | M / Camel | 1 | 49999 | 49999 |

Totals: subtotal 49999, discount 0, shipping 499, tax 7983, total **50498**

Payment: stripe, captured, 50498

---

**Order #1011 - Single item delivered**

| Field | Value |
|-------|-------|
| customer | james@example.com (James Taylor) |
| status / financial / fulfillment | paid / paid / fulfilled |
| placed_at | 25 days ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Striped Polo Shirt | XL | 1 | 2799 | 2799 |

Totals: subtotal 2799, discount 0, shipping 499, tax 447, total **3298**

Payment: stripe, captured, 3298

Fulfillment: delivered, FedEx, "FX9998887776", shipped 23 days ago

---

**Order #1012 - Multi-quantity order**

| Field | Value |
|-------|-------|
| customer | lisa@example.com (Lisa Anderson) |
| status / financial / fulfillment | paid / paid / unfulfilled |
| placed_at | 4 days ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Chino Shorts | 34 / Navy | 2 | 3999 | 7998 |

Totals: subtotal 7998, discount 0, shipping 499, tax 1277, total **8497**

Payment: stripe, captured, 8497

---

**Order #1013 - Multi-item order**

| Field | Value |
|-------|-------|
| customer | robert@example.com (Robert Martinez) |
| status / financial / fulfillment | paid / paid / unfulfilled |
| placed_at | 1 day ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Wide Leg Trousers | M | 1 | 4999 | 4999 |
| Wool Scarf | Burgundy | 1 | 2999 | 2999 |

Totals: subtotal 7998, discount 0, shipping 499, tax 1277, total **8497**

Payment: stripe, captured, 8497

---

**Order #1014 - Digital product order**

| Field | Value |
|-------|-------|
| customer | anna@example.com (Anna Thomas) |
| status / financial / fulfillment | paid / paid / fulfilled |
| placed_at | 14 days ago |

Lines:

| Product | Variant | Qty | Unit Price | Line Total |
|---------|---------|-----|-----------|-----------|
| Gift Card | 50 EUR | 1 | 5000 | 5000 |

Totals: subtotal 5000, discount 0, shipping **0** (digital product), tax 798, total **5000**

Payment: stripe, captured, 5000

Fulfillment: delivered (digital fulfillment), no tracking company, no tracking number, shipped_at = placed_at

---

**Order #1015 - Order with discount**

| Field | Value |
|-------|-------|
| customer | customer@acme.test (John Doe) |
| status / financial / fulfillment | paid / paid / unfulfilled |
| placed_at | now (today) |

Lines:

| Product | Variant | Qty | Unit Price | Line Total | Discount Allocation |
|---------|---------|-----|-----------|-----------|-------------------|
| Classic Cotton T-Shirt | M / White | 1 | 2499 | 2499 | WELCOME10 discount, amount: 250 |
| Graphic Print Tee | M | 1 | 2999 | 2999 | WELCOME10 discount, amount: 300 |

Totals: subtotal 5498, discount **550**, shipping 499, tax 790, total **5447**

Payment: stripe, captured, 5447

The discount_allocations_json on each order line references the WELCOME10 discount's database ID and the allocated discount amount for that specific line.

---

#### Order Summary Table (Acme Fashion)

| Order | Customer | Status | Financial | Fulfillment | Total | Key Test Scenario |
|-------|----------|--------|-----------|-------------|-------|-------------------|
| #1001 | John Doe | paid | paid | unfulfilled | 5497 | Awaiting fulfillment |
| #1002 | John Doe | fulfilled | paid | fulfilled | 8997 | Delivered order |
| #1003 | Jane Smith | paid | paid | partial | 11997 | Partial fulfillment |
| #1004 | John Doe | cancelled | refunded | unfulfilled | 2998 | Full cancellation + refund |
| #1005 | Jane Smith | pending | pending | unfulfilled | 3998 | Payment pending |
| #1006 | Michael Brown | paid | paid | unfulfilled | 12498 | Standard paid order |
| #1007 | Sarah Wilson | fulfilled | paid | fulfilled | 10496 | Multi-item delivered |
| #1008 | David Lee | paid | partially_refunded | fulfilled | 8997 | Partial refund |
| #1009 | Emma Garcia | paid | paid | unfulfilled | 4997 | Accessories order |
| #1010 | John Doe | paid | paid | unfulfilled | 50498 | High-value order |
| #1011 | James Taylor | paid | paid | fulfilled | 3298 | Single item delivered |
| #1012 | Lisa Anderson | paid | paid | unfulfilled | 8497 | Multi-quantity order |
| #1013 | Robert Martinez | paid | paid | unfulfilled | 8497 | Multi-item order |
| #1014 | Anna Thomas | paid | paid | fulfilled | 5000 | Digital product order |
| #1015 | John Doe | paid | paid | unfulfilled | 5447 | Order with discount |

---

**Acme Electronics - 3 orders (minimal, for tenant isolation):**

| Order | Customer | Status | Financial | Fulfillment | Total | Details |
|-------|----------|--------|-----------|-------------|-------|---------|
| #5001 | techfan@example.com | paid | paid | fulfilled | 121298 | Pro Laptop 512GB (119999) + USB-C Cable (1299), shipping 0 |
| #5002 | gadgetlover@example.com | paid | paid | unfulfilled | 14999 | Wireless Headphones Black (14999), shipping 0 |
| #5003 | techfan@example.com | pending | pending | unfulfilled | 4999 | Monitor Stand (4999), shipping 0, payment requires_action |

---

### 3.14 ThemeSeeder

**Acme Fashion:**

| Field | Value |
|-------|-------|
| name | Default Theme |
| version | 1.0.0 |
| status | published |
| published_at | now |

**Theme settings (theme_settings row):**

| Setting Key | Value |
|-------------|-------|
| primary_color | #1a1a2e |
| secondary_color | #e94560 |
| font_family | Inter, sans-serif |
| hero_heading | Welcome to Acme Fashion |
| hero_subheading | Discover our curated collection of modern essentials |
| hero_cta_text | Shop New Arrivals |
| hero_cta_link | /collections/new-arrivals |
| featured_collection_handles | ["new-arrivals", "t-shirts", "sale"] |
| footer_text | 2025 Acme Fashion. All rights reserved. |
| show_announcement_bar | true |
| announcement_text | Free shipping on orders over 50 EUR - Use code FREESHIP |
| products_per_page | 12 |
| show_vendor | true |
| show_quantity_selector | true |

**Acme Electronics:**

| Field | Value |
|-------|-------|
| name | Default Theme |
| version | 1.0.0 |
| status | published |

Theme settings:

| Setting Key | Value |
|-------------|-------|
| primary_color | #0f172a |
| secondary_color | #3b82f6 |
| font_family | Inter, sans-serif |
| hero_heading | Acme Electronics |
| hero_subheading | Premium tech for professionals |
| hero_cta_text | Shop Featured |
| hero_cta_link | /collections/featured |
| featured_collection_handles | ["featured"] |
| footer_text | 2025 Acme Electronics. All rights reserved. |

---

### 3.15 PageSeeder

**Acme Fashion - 5 content pages:**

All pages: status = "published", published_at = 3 months ago.

**Page 1: About Us**
- handle: about
- 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.

**Page 2: FAQ**
- handle: faq
- body_html content: h2 "Frequently Asked Questions" followed by four Q&A pairs using h3/p structure:
  1. Shipping timeframes (Germany 2-4 days standard, 1-2 express; EU 5-7 days)
  2. Return policy (30 days, unworn, original packaging)
  3. International shipping (EU + US, UK, CA, AU)
  4. Order tracking (email with tracking number after shipment)

**Page 3: Shipping & Returns**
- handle: shipping-returns
- 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).

**Page 4: Privacy Policy**
- handle: privacy-policy
- 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.

**Page 5: Terms of Service**
- handle: terms
- 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.

---

### 3.16 NavigationSeeder

**Acme Fashion - Main Menu (handle: main-menu, title: "Main Menu"):**

| Position | Label | Type | Target |
|----------|-------|------|--------|
| 0 | Home | link | URL: / |
| 1 | New Arrivals | collection | resource_id: ID of "New Arrivals" collection |
| 2 | T-Shirts | collection | resource_id: ID of "T-Shirts" collection |
| 3 | Pants & Jeans | collection | resource_id: ID of "Pants & Jeans" collection |
| 4 | Sale | collection | resource_id: ID of "Sale" collection |

**Acme Fashion - Footer Menu (handle: footer-menu, title: "Footer Menu"):**

| Position | Label | Type | Target |
|----------|-------|------|--------|
| 0 | About Us | page | resource_id: ID of "About Us" page |
| 1 | FAQ | page | resource_id: ID of "FAQ" page |
| 2 | Shipping & Returns | page | resource_id: ID of "Shipping & Returns" page |
| 3 | Privacy Policy | page | resource_id: ID of "Privacy Policy" page |
| 4 | Terms of Service | page | resource_id: ID of "Terms of Service" page |

**Acme Electronics - Main Menu (handle: main-menu, title: "Main Menu"):**

| Position | Label | Type | Target |
|----------|-------|------|--------|
| 0 | Home | link | URL: / |
| 1 | Featured | collection | resource_id: ID of "Featured" collection |
| 2 | Accessories | collection | resource_id: ID of "Accessories" collection |

---

### 3.17 AnalyticsSeeder

**Acme Fashion - analytics_daily (30 days of daily data):**

Generate one row per day for the past 30 days (today minus 30 through today). Revenue trends upward to simulate growth.

**Generation algorithm (pseudo-code):**

```
FOR i FROM 30 DOWN TO 0:
    dayFactor = 1 + (30 - i) * 0.03       // ~3% daily growth factor
    visits = ROUND(RANDOM(50, 100) * dayFactor)
    addToCart = ROUND(visits * RANDOM(18, 25) / 100)
    checkoutStarted = ROUND(addToCart * RANDOM(40, 55) / 100)
    orders = MAX(2, ROUND(checkoutStarted * RANDOM(35, 55) / 100))
    aov = RANDOM(4000, 9000)               // average order value in cents
    revenue = orders * aov

    INSERT analytics_daily:
        store_id = Acme Fashion ID
        date = TODAY minus i days (ISO format YYYY-MM-DD)
        visits_count = visits
        add_to_cart_count = addToCart
        checkout_started_count = checkoutStarted
        orders_count = orders
        revenue_amount = revenue
        aov_amount = aov
```


   330→    Dashboard --> Discounts: click "Discounts"
   331→    Dashboard --> Settings: click "Settings"
   332→    Dashboard --> Analytics: click "Analytics"
   333→    Dashboard --> Themes: click "Themes"
   334→    Dashboard --> LoginPage: click profile dropdown then "Logout"
   335→```
   336→
   337→---
   338→
   339→### Test 2.1: Can log in as admin
   340→
   341→**Preconditions:** Seeded admin user
   342→
   343→**Steps:**
   344→1. Navigate to `/admin/login`
   345→2. Enter email: `admin@acme.test`
   346→3. Enter password: `password`
   347→4. Click the "Sign in" button
   348→
   349→**Expected Results:**
   350→- Page displays "Dashboard"
   351→- No JavaScript errors
   352→
   353→---
   354→
   355→### Test 2.2: Shows error for invalid credentials
   356→
   357→**Preconditions:** Seeded admin user
   358→
   359→**Steps:**
   360→1. Navigate to `/admin/login`
   361→2. Enter email: `admin@acme.test`
   362→3. Enter password: `wrongpassword`
   363→4. Click the "Sign in" button
   364→
   365→**Expected Results:**
   366→- Page displays "Invalid credentials"
   367→- No JavaScript errors
   368→
   369→---
   370→
   371→### Test 2.3: Shows error for empty email
   372→
   373→**Preconditions:** None
   374→
   375→**Steps:**
   376→1. Navigate to `/admin/login`
   377→2. Enter password: `password` (leave email empty)
   378→3. Click the "Sign in" button
   379→
   380→**Expected Results:**
   381→- Validation error referencing "email" is visible
   382→- No JavaScript errors
   383→
   384→---
   385→
   386→### Test 2.4: Shows error for empty password
   387→
   388→**Preconditions:** None
   389→
   390→**Steps:**
   391→1. Navigate to `/admin/login`
   392→2. Enter email: `admin@acme.test` (leave password empty)
   393→3. Click the "Sign in" button
   394→
   395→**Expected Results:**
   396→- Validation error referencing "password" is visible
   397→- No JavaScript errors
   398→
   399→---
   400→
   401→### Test 2.5: Redirects unauthenticated users to login from dashboard
   402→
   403→**Preconditions:** Not logged in
   404→
   405→**Steps:**
   406→1. Navigate to `/admin` (without logging in)
   407→
   408→**Expected Results:**
   409→- Page displays "Sign in" (redirected to login form)
   410→- No JavaScript errors
   411→
   412→---
   413→
   414→### Test 2.6: Redirects unauthenticated users to login from products
   415→
   416→**Preconditions:** Not logged in
   417→
   418→**Steps:**
   419→1. Navigate to `/admin/products` (without logging in)
   420→
   421→**Expected Results:**
   422→- Page displays "Sign in" (redirected to login form)
   423→- No JavaScript errors
   424→
   425→---
   426→
   427→### Test 2.7: Can log out
   428→
   429→**Preconditions:** Seeded admin user
   430→
   431→**Steps:**
   432→1. Navigate to `/admin/login`
   433→2. Enter email: `admin@acme.test`
   434→3. Enter password: `password`
   435→4. Click the "Sign in" button
   436→5. Verify "Dashboard" is visible
   437→6. Click on "Admin User" (profile/user menu)
   438→7. Click "Logout"
   439→
   440→**Expected Results:**
   441→- Page displays "Sign in" (returned to login form)
   442→
   443→---
   444→
   445→### Test 2.8: Can navigate through admin sidebar sections
   446→
   447→**Preconditions:** Seeded admin user
   448→
   449→**Steps:**
   450→1. Navigate to `/admin/login`
   451→2. Enter email: `admin@acme.test`
   452→3. Enter password: `password`
   453→4. Click the "Sign in" button
   454→5. Click "Products" in the sidebar
   455→6. Verify "Products" heading is visible
   456→7. Click "Orders" in the sidebar
   457→8. Verify "Orders" heading is visible
   458→9. Click "Customers" in the sidebar
   459→10. Verify "Customers" heading is visible
   460→11. Click "Discounts" in the sidebar
   461→12. Verify "Discounts" heading is visible
   462→13. Click "Settings" in the sidebar
   463→14. Verify "Store Settings" heading is visible
   464→
   465→**Expected Results:**
   466→- Each section loads without JavaScript errors
   467→- Each section heading is visible after clicking its sidebar link
   468→
   469→---
   470→
   471→### Test 2.9: Can navigate to analytics from sidebar
   472→
   473→**Preconditions:** Seeded admin user
   474→
   475→**Steps:**
   476→1. Navigate to `/admin/login`
   477→2. Enter email: `admin@acme.test`
   478→3. Enter password: `password`
   479→4. Click the "Sign in" button
   480→5. Click "Analytics" in the sidebar
   481→
   482→**Expected Results:**
   483→- Page displays "Analytics"
   484→- No JavaScript errors
   485→
   486→---
   487→
   488→### Test 2.10: Can navigate to themes from sidebar
   489→
   490→**Preconditions:** Seeded admin user
   491→
   492→**Steps:**
   493→1. Navigate to `/admin/login`
   494→2. Enter email: `admin@acme.test`
   495→3. Enter password: `password`
   496→4. Click the "Sign in" button
   497→5. Click "Themes" in the sidebar
   498→
   499→**Expected Results:**
   500→- Page displays "Themes"
   501→- No JavaScript errors
   502→
   503→**Login Helper Pattern:** Tests 2.7-2.10 require the admin to be logged in first. Each test should perform the full login sequence (visit login page, fill credentials, click sign in, assert dashboard) before proceeding. This ensures test independence.
   504→
   505→**Total: 10 tests**
   506→
   507→---
   508→
   509→## Suite 3: Admin Product Management
   510→
   511→**File:** `tests/Browser/Admin/ProductManagementTest.php`
   512→
   513→**Purpose:** Verify CRUD operations for products through the admin interface - listing, creating, editing, archiving, searching, and filtering by status.
   514→
   515→### Product Lifecycle States
   516→
   517→```mermaid
   518→stateDiagram-v2
   519→    [*] --> Draft: create product (default)
   520→    Draft --> Active: set status to Active + Save
   521→    Active --> Archived: set status to Archived + Save
   522→    Draft --> Archived: set status to Archived + Save
   523→    Archived --> Active: set status to Active + Save
   524→    Active --> Draft: set status to Draft + Save
   525→```
   526→
   527→---
   528→
   529→### Test 3.1: Shows the product list with seeded products
   530→
   531→**Preconditions:** Logged in as admin, seeded products
   532→
   533→**Steps:**
   534→1. Navigate to `/admin/login`
   535→2. Enter email: `admin@acme.test`
   536→3. Enter password: `password`
   537→4. Click the "Sign in" button
   538→5. Click "Products" in the sidebar
   539→
   540→**Expected Results:**
   541→- Page displays "Classic Cotton T-Shirt"
   542→- Page displays "Premium Slim Fit Jeans"
   543→- No JavaScript errors
   544→
   545→---
   546→
   547→### Test 3.2: Can create a new product
   548→
   549→**Preconditions:** Logged in as admin
   550→
   551→**Steps:**
   552→1. Navigate to `/admin/login`
   553→2. Log in as admin (email: `admin@acme.test`, password: `password`)
   554→3. Click "Products" in the sidebar
   555→4. Click "Add product"
   556→5. Enter title: `Test Product Created by E2E`
   557→6. Enter description: `This product was created by the E2E test suite.`
   558→7. Enter vendor: `Test Vendor`
   559→8. Enter product type: `T-Shirts`
   560→9. Enter variant price (variants.0.price): `29.99`
   561→10. Enter variant SKU (variants.0.sku): `E2E-TEST-001`
   562→11. Enter variant quantity (variants.0.quantity): `50`
   563→12. Click "Save"
   564→13. Click "Products" to return to the product list
   565→
   566→**Expected Results:**
   567→- After step 12: page displays "Product saved", no JavaScript errors
   568→- After step 13: page displays "Test Product Created by E2E" in the list
   569→
   570→---
   571→
   572→### Test 3.3: Can edit an existing product title
   573→
   574→**Preconditions:** Logged in as admin, seeded products
   575→
   576→**Steps:**
   577→1. Navigate to `/admin/login`
   578→2. Log in as admin
   579→3. Click "Products" in the sidebar
   580→4. Verify "Classic Cotton T-Shirt" is visible in the list
   581→5. Click "Classic Cotton T-Shirt" to open the edit form
   582→6. Clear the title field and enter: `Classic Cotton T-Shirt Updated`
   583→7. Click "Save"
   584→8. Click "Products" to return to the product list
   585→
   586→**Expected Results:**
   587→- After step 7: page displays "Product saved", no JavaScript errors
   588→- After step 8: page displays "Classic Cotton T-Shirt Updated" in the list
   589→
   590→---
   591→
   592→### Test 3.4: Can archive a product
   593→
   594→**Preconditions:** Logged in as admin
   595→
   596→**Steps:**
   597→1. Navigate to `/admin/login`
   598→2. Log in as admin
   599→3. Click "Products" in the sidebar
   600→4. Click "Add product"
   601→5. Enter title: `Product To Archive`
   602→6. Enter variant price: `19.99`
   603→7. Enter variant SKU: `E2E-ARCHIVE-001`
   604→8. Enter variant quantity: `10`
   605→9. Click "Save"
   606→10. Verify "Product saved" is displayed
   607→11. Click "Products" to return to the product list
   608→12. Click "Product To Archive" to open the edit form
   609→13. Change status to "Archived" (click the Archived option)
   610→14. Click "Save"
   611→15. Click "Products" to return to the product list
   612→
   613→**Expected Results:**
   614→- After step 9: page displays "Product saved"
   615→- After step 14: page displays "Product saved"
   616→- After step 15: with default "Active" filter, the archived product should not appear in the list
   617→
   618→---
   619→
   620→### Test 3.5: Shows draft products only in admin, not storefront
   621→
   622→**Preconditions:** Logged in as admin, Product #15 exists with draft status
   623→
   624→**Steps:**
   625→1. Navigate to `/admin/login`
   626→2. Log in as admin
   627→3. Click "Products" in the sidebar
   628→4. Verify Product #15 is visible in the admin list with a "Draft" badge
   629→5. Open a new browser context / navigate to `/collections/t-shirts` (as guest)
   630→6. Verify the draft product does NOT appear in the collection listing
   631→7. Navigate to `/search?q=draft`
   632→8. Verify the draft product does NOT appear in search results
   633→
   634→**Expected Results:**
   635→- Step 4: draft product visible in admin, no JavaScript errors
   636→- Step 6: draft product absent from storefront collection, no JavaScript errors
   637→- Step 8: draft product absent from search results, no JavaScript errors
   638→
   639→---
   640→
   641→### Test 3.6: Can search products in admin
   642→
   643→**Preconditions:** Logged in as admin, seeded products
   644→
   645→**Steps:**
   646→1. Navigate to `/admin/login`
   647→2. Log in as admin
   648→3. Click "Products" in the sidebar
   649→4. Enter "Cotton" in the search input field
   650→
   651→**Expected Results:**
   652→- Page displays "Classic Cotton T-Shirt" in filtered results
   653→- No JavaScript errors
   654→
   655→---
   656→
   657→### Test 3.7: Can filter products by status in admin
   658→
   659→**Preconditions:** Logged in as admin, seeded products including drafts
   660→
   661→**Steps:**
   662→1. Navigate to `/admin/login`
   663→2. Log in as admin
   664→3. Click "Products" in the sidebar
   665→4. Click the "Draft" status filter tab
   666→5. Verify only draft products are visible
   667→6. Click the "Active" status filter tab
   668→
   669→**Expected Results:**
   670→- After step 4: only draft products are visible, no JavaScript errors
   671→- After step 6: "Classic Cotton T-Shirt" is visible, no JavaScript errors
   672→
   673→**Total: 7 tests**
   674→
   675→---
   676→
   677→## Suite 4: Admin Order Management
   678→
   679→**File:** `tests/Browser/Admin/OrderManagementTest.php`
   680→
   681→**Purpose:** Verify order listing, status filtering, order detail with timeline, fulfillment creation, and refund processing.
   682→
   683→### Order State Transitions (via admin actions)
   684→
   685→```mermaid
   686→stateDiagram-v2
   687→    state financial {
   688→        pending_f --> paid: payment captured
   689→        paid --> partially_refunded: partial refund
   690→        paid --> refunded: full refund
   691→    }
   692→    state fulfillment {
   693→        unfulfilled --> partial: partial fulfillment
   694→        unfulfilled --> fulfilled: full fulfillment
   695→        partial --> fulfilled: remaining items fulfilled
   696→    }
   697→```
   698→
   699→---
   700→
   701→### Test 4.1: Shows the order list with seeded orders
   702→
   703→**Preconditions:** Logged in as admin, seeded orders
   704→
   705→**Steps:**
   706→1. Navigate to `/admin/login`
   707→2. Log in as admin
   708→3. Click "Orders" in the sidebar
   709→
   710→**Expected Results:**
   711→- Page displays "#1001"
   712→- No JavaScript errors
   713→
   714→---
   715→
   716→### Test 4.2: Can filter orders by status
   717→
   718→**Preconditions:** Logged in as admin, seeded orders
   719→
   720→**Steps:**
   721→1. Navigate to `/admin/login`
   722→2. Log in as admin
   723→3. Click "Orders" in the sidebar
   724→4. Click the "Paid" status filter/tab
   725→5. Verify "#1001" is visible
   726→6. Click the "Fulfilled" status filter/tab
   727→7. Click the "All" tab to reset the filter
   728→
   729→**Expected Results:**
   730→- After step 4: "#1001" is visible, no JavaScript errors
   731→- After step 6: filtered results shown, no JavaScript errors
   732→- After step 7: full list shown, no JavaScript errors
   733→
   734→---
   735→
   736→### Test 4.3: Shows order detail with line items and totals
   737→
   738→**Preconditions:** Logged in as admin, Order #1001 exists
   739→
   740→**Steps:**
   741→1. Navigate to `/admin/login`
   742→2. Log in as admin
   743→3. Click "Orders" in the sidebar
   744→4. Click "#1001" to open the order detail
   745→
   746→**Expected Results:**
   747→- Page displays "#1001"
   748→- Page displays "Paid" (financial status)
   749→- Page displays "Unfulfilled" (fulfillment status)
   750→- Page displays "Classic Cotton T-Shirt" (line item)
   751→- Page displays "Subtotal", "Shipping", "Tax", and "Total" sections
   752→- No JavaScript errors
   753→
   754→---
   755→
   756→### Test 4.4: Shows order timeline events
   757→
   758→**Preconditions:** Logged in as admin, Order #1001 exists
   759→
   760→**Steps:**
   761→1. Navigate to `/admin/login`
   762→2. Log in as admin
   763→3. Click "Orders" in the sidebar
   764→4. Click "#1001" to open the order detail
   765→
   766→**Expected Results:**
   767→- Page displays "Timeline" section
   768→- Timeline shows at least the order creation event
   769→- No JavaScript errors
   770→
   771→---
   772→
   773→### Test 4.5: Can create a fulfillment
   774→
   775→**Preconditions:** Logged in as admin, Order #1001 is unfulfilled
   776→
   777→**Steps:**
   778→1. Navigate to `/admin/login`
   779→2. Log in as admin
   780→3. Click "Orders" in the sidebar
   781→4. Click "#1001" to open the order detail
   782→5. Click "Create fulfillment"
   783→6. Enter tracking company: `DHL`
   784→7. Enter tracking number: `DHL123456789`
   785→8. Click "Fulfill items"
   786→
   787→**Expected Results:**
   788→- Page displays "Fulfillment created"
   789→- Page displays "DHL" and "DHL123456789" in the fulfillment section
   790→- No JavaScript errors
   791→
   792→---
   793→
   794→### Test 4.6: Can process a refund
   795→
   796→**Preconditions:** Logged in as admin, Order #1001 is paid
   797→
   798→**Steps:**
   799→1. Navigate to `/admin/login`
   800→2. Log in as admin
   801→3. Click "Orders" in the sidebar
   802→4. Click "#1001" to open the order detail
   803→5. Click "Refund"
   804→6. Enter amount: `10.00`
   805→7. Enter reason: `Customer requested partial refund`
   806→8. Click "Process refund"
   807→
   808→**Expected Results:**
   809→- Page displays "Refund processed"
   810→- Page displays "Partially refunded" (updated financial status)
   811→- No JavaScript errors
   812→
   813→---
   814→
   815→### Test 4.7: Shows customer information in order detail
   816→
   817→**Preconditions:** Logged in as admin, Order #1001 exists with customer
   818→
   819→**Steps:**
   820→1. Navigate to `/admin/login`
   821→2. Log in as admin
   822→3. Click "Orders" in the sidebar
   823→4. Click "#1001" to open the order detail
   824→
   825→**Expected Results:**
   826→- Page displays "customer@acme.test" in the customer info section
   827→- No JavaScript errors
   828→
   829→**Total: 7 tests**

    Dashboard --> Discounts: click "Discounts"
    Dashboard --> Settings: click "Settings"
    Dashboard --> Analytics: click "Analytics"
    Dashboard --> Themes: click "Themes"
    Dashboard --> LoginPage: click profile dropdown then "Logout"
```

---

### Test 2.1: Can log in as admin

**Preconditions:** Seeded admin user

**Steps:**
1. Navigate to `/admin/login`
2. Enter email: `admin@acme.test`
3. Enter password: `password`
4. Click the "Sign in" button

**Expected Results:**
- Page displays "Dashboard"
- No JavaScript errors

---

### Test 2.2: Shows error for invalid credentials

**Preconditions:** Seeded admin user

**Steps:**
1. Navigate to `/admin/login`
2. Enter email: `admin@acme.test`
3. Enter password: `wrongpassword`
4. Click the "Sign in" button

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

---

### Test 2.3: Shows error for empty email

**Preconditions:** None

**Steps:**
1. Navigate to `/admin/login`
2. Enter password: `password` (leave email empty)
3. Click the "Sign in" button

**Expected Results:**
- Validation error referencing "email" is visible
- No JavaScript errors

---

### Test 2.4: Shows error for empty password

**Preconditions:** None

**Steps:**
1. Navigate to `/admin/login`
2. Enter email: `admin@acme.test` (leave password empty)
3. Click the "Sign in" button

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

---

### Test 2.5: Redirects unauthenticated users to login from dashboard

**Preconditions:** Not logged in

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

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

---

### Test 2.6: Redirects unauthenticated users to login from products

**Preconditions:** Not logged in

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

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

---

### Test 2.7: Can log out

**Preconditions:** Seeded admin user

**Steps:**
1. Navigate to `/admin/login`
2. Enter email: `admin@acme.test`
3. Enter password: `password`
4. Click the "Sign in" button
5. Verify "Dashboard" is visible
6. Click on "Admin User" (profile/user menu)
7. Click "Logout"

**Expected Results:**
- Page displays "Sign in" (returned to login form)

---

### Test 2.8: Can navigate through admin sidebar sections

**Preconditions:** Seeded admin user

**Steps:**
1. Navigate to `/admin/login`
2. Enter email: `admin@acme.test`
3. Enter password: `password`
4. Click the "Sign in" button
5. Click "Products" in the sidebar
6. Verify "Products" heading is visible
7. Click "Orders" in the sidebar
8. Verify "Orders" heading is visible
9. Click "Customers" in the sidebar
10. Verify "Customers" heading is visible
11. Click "Discounts" in the sidebar
12. Verify "Discounts" heading is visible
13. Click "Settings" in the sidebar
14. Verify "Store Settings" heading is visible

**Expected Results:**
- Each section loads without JavaScript errors
- Each section heading is visible after clicking its sidebar link

---

### Test 2.9: Can navigate to analytics from sidebar

**Preconditions:** Seeded admin user

**Steps:**
1. Navigate to `/admin/login`
2. Enter email: `admin@acme.test`
3. Enter password: `password`
4. Click the "Sign in" button
5. Click "Analytics" in the sidebar

**Expected Results:**
- Page displays "Analytics"
- No JavaScript errors

---

### Test 2.10: Can navigate to themes from sidebar

**Preconditions:** Seeded admin user

**Steps:**
1. Navigate to `/admin/login`
2. Enter email: `admin@acme.test`
3. Enter password: `password`
4. Click the "Sign in" button
5. Click "Themes" in the sidebar

**Expected Results:**
- Page displays "Themes"
- No JavaScript errors

**Login Helper Pattern:** Tests 2.7-2.10 require the admin to be logged in first. Each test should perform the full login sequence (visit login page, fill credentials, click sign in, assert dashboard) before proceeding. This ensures test independence.

**Total: 10 tests**

---

## Suite 3: Admin Product Management

**File:** `tests/Browser/Admin/ProductManagementTest.php`

**Purpose:** Verify CRUD operations for products through the admin interface - listing, creating, editing, archiving, searching, and filtering by status.

### Product Lifecycle States

```mermaid
stateDiagram-v2
    [*] --> Draft: create product (default)
    Draft --> Active: set status to Active + Save
    Active --> Archived: set status to Archived + Save
    Draft --> Archived: set status to Archived + Save
    Archived --> Active: set status to Active + Save
    Active --> Draft: set status to Draft + Save
```

---

### Test 3.1: Shows the product list with seeded products

**Preconditions:** Logged in as admin, seeded products

**Steps:**
1. Navigate to `/admin/login`
2. Enter email: `admin@acme.test`
3. Enter password: `password`
4. Click the "Sign in" button
5. Click "Products" in the sidebar

**Expected Results:**
- Page displays "Classic Cotton T-Shirt"
- Page displays "Premium Slim Fit Jeans"
- No JavaScript errors

---

### Test 3.2: Can create a new product

**Preconditions:** Logged in as admin

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin (email: `admin@acme.test`, password: `password`)
3. Click "Products" in the sidebar
4. Click "Add product"
5. Enter title: `Test Product Created by E2E`
6. Enter description: `This product was created by the E2E test suite.`
7. Enter vendor: `Test Vendor`
8. Enter product type: `T-Shirts`
9. Enter variant price (variants.0.price): `29.99`
10. Enter variant SKU (variants.0.sku): `E2E-TEST-001`
11. Enter variant quantity (variants.0.quantity): `50`
12. Click "Save"
13. Click "Products" to return to the product list

**Expected Results:**
- After step 12: page displays "Product saved", no JavaScript errors
- After step 13: page displays "Test Product Created by E2E" in the list

---

### Test 3.3: Can edit an existing product title

**Preconditions:** Logged in as admin, seeded products

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Products" in the sidebar
4. Verify "Classic Cotton T-Shirt" is visible in the list
5. Click "Classic Cotton T-Shirt" to open the edit form
6. Clear the title field and enter: `Classic Cotton T-Shirt Updated`
7. Click "Save"
8. Click "Products" to return to the product list

**Expected Results:**
- After step 7: page displays "Product saved", no JavaScript errors
- After step 8: page displays "Classic Cotton T-Shirt Updated" in the list

---

### Test 3.4: Can archive a product

**Preconditions:** Logged in as admin

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Products" in the sidebar
4. Click "Add product"
5. Enter title: `Product To Archive`
6. Enter variant price: `19.99`
7. Enter variant SKU: `E2E-ARCHIVE-001`
8. Enter variant quantity: `10`
9. Click "Save"
10. Verify "Product saved" is displayed
11. Click "Products" to return to the product list
12. Click "Product To Archive" to open the edit form
13. Change status to "Archived" (click the Archived option)
14. Click "Save"
15. Click "Products" to return to the product list

**Expected Results:**
- After step 9: page displays "Product saved"
- After step 14: page displays "Product saved"
- After step 15: with default "Active" filter, the archived product should not appear in the list

---

### Test 3.5: Shows draft products only in admin, not storefront

**Preconditions:** Logged in as admin, Product #15 exists with draft status

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Products" in the sidebar
4. Verify Product #15 is visible in the admin list with a "Draft" badge
5. Open a new browser context / navigate to `/collections/t-shirts` (as guest)
6. Verify the draft product does NOT appear in the collection listing
7. Navigate to `/search?q=draft`
8. Verify the draft product does NOT appear in search results

**Expected Results:**
- Step 4: draft product visible in admin, no JavaScript errors
- Step 6: draft product absent from storefront collection, no JavaScript errors
- Step 8: draft product absent from search results, no JavaScript errors

---

### Test 3.6: Can search products in admin

**Preconditions:** Logged in as admin, seeded products

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Products" in the sidebar
4. Enter "Cotton" in the search input field

**Expected Results:**
- Page displays "Classic Cotton T-Shirt" in filtered results
- No JavaScript errors

---

### Test 3.7: Can filter products by status in admin

**Preconditions:** Logged in as admin, seeded products including drafts

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Products" in the sidebar
4. Click the "Draft" status filter tab
5. Verify only draft products are visible
6. Click the "Active" status filter tab

**Expected Results:**
- After step 4: only draft products are visible, no JavaScript errors
- After step 6: "Classic Cotton T-Shirt" is visible, no JavaScript errors

**Total: 7 tests**

---

## Suite 4: Admin Order Management

**File:** `tests/Browser/Admin/OrderManagementTest.php`

**Purpose:** Verify order listing, status filtering, order detail with timeline, fulfillment creation, and refund processing.

### Order State Transitions (via admin actions)

```mermaid
stateDiagram-v2
    state financial {
        pending_f --> paid: payment captured
        paid --> partially_refunded: partial refund
        paid --> refunded: full refund
    }
    state fulfillment {
        unfulfilled --> partial: partial fulfillment
        unfulfilled --> fulfilled: full fulfillment
        partial --> fulfilled: remaining items fulfilled
    }
```

---

### Test 4.1: Shows the order list with seeded orders

**Preconditions:** Logged in as admin, seeded orders

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Orders" in the sidebar

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

---

### Test 4.2: Can filter orders by status

**Preconditions:** Logged in as admin, seeded orders

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Orders" in the sidebar
4. Click the "Paid" status filter/tab
5. Verify "#1001" is visible
6. Click the "Fulfilled" status filter/tab
7. Click the "All" tab to reset the filter

**Expected Results:**
- After step 4: "#1001" is visible, no JavaScript errors
- After step 6: filtered results shown, no JavaScript errors
- After step 7: full list shown, no JavaScript errors

---

### Test 4.3: Shows order detail with line items and totals

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

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Orders" in the sidebar
4. Click "#1001" to open the order detail

**Expected Results:**
- Page displays "#1001"
- Page displays "Paid" (financial status)
- Page displays "Unfulfilled" (fulfillment status)
- Page displays "Classic Cotton T-Shirt" (line item)
- Page displays "Subtotal", "Shipping", "Tax", and "Total" sections
- No JavaScript errors

---

### Test 4.4: Shows order timeline events

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

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Orders" in the sidebar
4. Click "#1001" to open the order detail

**Expected Results:**
- Page displays "Timeline" section
- Timeline shows at least the order creation event
- No JavaScript errors

---

### Test 4.5: Can create a fulfillment

**Preconditions:** Logged in as admin, Order #1001 is unfulfilled

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Orders" in the sidebar
4. Click "#1001" to open the order detail
5. Click "Create fulfillment"
6. Enter tracking company: `DHL`
7. Enter tracking number: `DHL123456789`
8. Click "Fulfill items"

**Expected Results:**
- Page displays "Fulfillment created"
- Page displays "DHL" and "DHL123456789" in the fulfillment section
- No JavaScript errors

---

### Test 4.6: Can process a refund

**Preconditions:** Logged in as admin, Order #1001 is paid

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Orders" in the sidebar
4. Click "#1001" to open the order detail
5. Click "Refund"
6. Enter amount: `10.00`
7. Enter reason: `Customer requested partial refund`
8. Click "Process refund"

**Expected Results:**
- Page displays "Refund processed"
- Page displays "Partially refunded" (updated financial status)
- No JavaScript errors

---

### Test 4.7: Shows customer information in order detail

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

**Steps:**
1. Navigate to `/admin/login`
2. Log in as admin
3. Click "Orders" in the sidebar
4. Click "#1001" to open the order detail

**Expected Results:**
- Page displays "customer@acme.test" in the customer info section
- No JavaScript errors

**Total: 7 tests**