SD-0002: Products — bulk CSV import/export Solution Design (#13) + Claude Design bundle #4

Merged
ben.stull merged 12 commits from session-0030 into main 2026-06-11 20:57:57 +00:00
Showing only changes of commit f4e2a9b792 - Show all commits
@@ -302,11 +302,180 @@ what the merchant's URLs provide, or rejects it.
## 3. Product Personas
*(not yet authored)*
| Product persona | In ecomm | Maps to business role(s) |
| --- | --- | --- |
| **Merchant** | The authenticated storefront owner (SD-0001 §3), now extended: manages their catalog from the admin's new **Products** section — imports, reviews, confirms, exports. The MVP's only authenticated user type. | Merchant; Migrating merchant |
The **Platform builder** (§1.3) gets no persona of their own: they exercise
the same Merchant surface with demo data (stand up a storefront, import a
realistic catalog). The **Operator** persona (SD-0001) is untouched by this
design.
## 4. Product Use Cases
*(not yet authored)*
Corpus grounding: scenario IDs cite the prototype corpus's products
import/export scenarios
([rfcs 11-05-00320037](https://git.wiggleverse.org/wiggleverse/wiggleverse-ecomm-prototype-content/src/branch/main/rfcs)).
Divergences are marked — the load-bearing one: the corpus matches rows to
products **by SKU** (11-05-0035); this design matches products **by `Handle`**
and variants **by option-value combination**, with SKU as correctable data
(rationale in §6.7).
**PUC-1 — The Products section exists, honestly** *(product-only; creates the surface #14 fills in)*
```gherkin
Scenario: PUC-1 — Products page, before and after a catalog exists
Given a Merchant in their storefront admin
When they open "Products" in the admin navigation
Then with an empty catalog they see an empty state: "No products yet",
a primary "Import products" action, and links to the sample CSV and
column reference
And with a populated catalog they see the product count, "Import products"
and "Export" actions, and the import history with an honest note that
the browsable product list arrives with a coming release (#14)
```
**PUC-2 — Upload a file to import** *(realizes BUC-1; corpus 11-05-0034)*
```gherkin
Scenario: PUC-2 — A Merchant starts an import
Given a Merchant on the Products page
When they choose "Import products" and select a .csv file
Then the file uploads and a "Validating" state shows progress
And they land on the import preview (PUC-3) when validation completes
```
**PUC-3 — Preview: see exactly what will happen** *(realizes BUC-2; the consent gate)*
```gherkin
Scenario: PUC-3 — The preview summarizes and lets the Merchant drill in
Given a Merchant whose file has been validated
Then they see which dialect was recognized ("Canonical" or "Shopify
product CSV mapped")
And a summary: N products to add, M to update, U unchanged, K rows in error
And any columns that will not be imported, listed by name
And selecting any product in the preview shows its record-level detail:
fields to be set (for adds) or a field-by-field before after diff
(for updates)
And nothing has been written to the catalog yet
```
```gherkin
Scenario: PUC-3a — Declining costs nothing
Given a Merchant on the import preview
When they choose "Cancel"
Then they return to the Products page and the catalog is unchanged
And no trace of the canceled import remains in the import history
```
**PUC-4 — Confirm: the import applies** *(realizes BUC-1, BUC-3)*
```gherkin
Scenario: PUC-4 — Confirming applies the valid records
Given a Merchant on a preview showing additions and updates
When they choose "Import N products"
Then an "Importing" state shows progress
And they land on the import run's detail page: products added, products
updated, rows in error (each listed and unapplied), and the image-fetch
phase begins (PUC-7)
And the catalog now holds exactly what the preview showed
```
**PUC-5 — Row errors come back actionable** *(realizes BUC-1a; corpus 11-05-0036)*
```gherkin
Scenario: PUC-5 — Bad rows are reported, good rows are not blocked
Given a Merchant's file where some rows are invalid (e.g. a malformed
price, a variant row whose options contradict its product)
Then the preview's error table lists each failed row: line number, the
column at fault, and what's wrong, in plain language
And confirming imports the valid rows and leaves the error rows unapplied
And the same error table remains on the import run's detail page
```
```gherkin
Scenario: PUC-5a — A file the importer cannot work with is rejected whole
Given a Merchant uploads a file that is not parseable CSV, is missing a
required column (e.g. "Title"), exceeds the row capacity (§2), or
matches no known dialect
Then the upload is rejected with one clear message naming the problem
And nothing is imported and no import run is recorded
```
**PUC-6 — A Shopify export imports directly** *(realizes BUC-1; the migration path)*
```gherkin
Scenario: PUC-6 — A migrating Merchant brings their Shopify export
Given a Merchant with the product CSV their Shopify store exported
When they upload it unmodified
Then the preview shows "Shopify product CSV mapped" and the standard
summary
And Shopify columns with no canonical equivalent are listed as not
imported (warned, never silent)
And confirming lands their catalog: products, variants, options, images,
prices, tags, status
```
**PUC-7 — Image outcomes are reported, not assumed** *(realizes BUC-1a for imagery)*
```gherkin
Scenario: PUC-7 — The image-fetch phase reports per image
Given a confirmed import whose records reference image URLs
Then the run detail shows live progress ("Fetching images: 312 of 4,950")
And when complete, each image's outcome: fetched, rejected (below the
resolution bar / not an image), or failed (unreachable)
And products whose images were rejected or failed show a placeholder and
carry a visible badge on the Products page
And the Merchant can re-import corrected URLs to retry (upsert, BUC-3)
```
**PUC-8 — Import history** *(realizes BUC-2's accountability)*
```gherkin
Scenario: PUC-8 — Past imports are reviewable
Given a Merchant who has run imports before
When they open the import history on the Products page
Then they see each run: when, file name, dialect, who ran it, and its
add / update / error / image-outcome counts
And opening a run shows its full detail page (PUC-4, PUC-5, PUC-7),
unchanged since the run finished
```
**PUC-9 — Export the catalog** *(realizes BUC-4; corpus 11-05-0032, 11-05-0033 — diverges: MVP filter is status only, vendor/collection filters deferred)*
```gherkin
Scenario: PUC-9 — One gesture produces the whole catalog
Given a Merchant on the Products page with a populated catalog
When they choose "Export" (optionally filtering by status:
all / active / draft / archived)
Then a canonical-format CSV downloads containing every matching product
all variants, options, tags, prices, and image URLs (pointing at the
platform's hosted copies)
And with an empty catalog the "Export" action is disabled, with a note
```
**PUC-10 — The round-trip is visibly lossless** *(realizes BUC-3, BUC-4; the #13 acceptance bar)*
```gherkin
Scenario: PUC-10 — Re-importing an export is a no-op, and says so
Given a Merchant who exports their catalog and re-imports the file
unmodified
Then the preview shows every product as "unchanged" nothing to add,
nothing to update, no errors
And confirming (or canceling) leaves the catalog identical
```
**PUC-11 — Learning the format** *(realizes BUC-1 for the cold-start merchant)*
```gherkin
Scenario: PUC-11 — The sample CSV and column reference teach the shape
Given a Merchant who has never seen the canonical format
When they download the sample CSV from the Products page or import screen
Then it opens in their spreadsheet tool with a handful of example products
including one with variants and one with images
And the linked column reference documents every column: name, meaning,
required or optional, accepted values
```
## 5. UX Layout