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 08ded5fa1b - Show all commits
@@ -425,7 +425,9 @@ Scenario: PUC-7 — The image-fetch phase reports per image
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
are surfaced on the Products page pre-#14 as an aggregate notice
("N products have image problems") linking to the run detail; per-product
badges arrive with #14's list view
And the Merchant can re-import corrected URLs to retry (upsert, BUC-3)
```
@@ -462,7 +464,9 @@ Scenario: PUC-10 — Re-importing an export is a no-op, and says so
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
And the import action is unavailable, with the note "Nothing to change
your catalog already matches this file"
And canceling leaves the catalog identical
```
**PUC-11 — Learning the format** *(realizes BUC-1 for the cold-start merchant)*
@@ -479,7 +483,117 @@ Scenario: PUC-11 — The sample CSV and column reference teach the shape
## 5. UX Layout
*(not yet authored)*
Text is the source of truth; wireframes are generated from these descriptions
on demand and never committed. All surfaces live inside SD-0001's admin shell
(its header: storefront name left, signed-in email + sign out right).
### 5.1 Design tooling decision
- **Decision:** Code directly.
- **Rationale:** rubric score **1** (claude-design-vs-code.md): Q1 **+1**
(net-new Products section, no data-surface precedent in the codebase),
Q2 **1** (this section describes the UI to wireframe level — named
components, enumerated states), Q3 **0** (one admin section, multi-step but
utilitarian), Q4 **+1** (no design system in the ecomm app yet), Q5 **1**
(solo build, operator is the only reviewer), Q6 **1** (work is dominantly
logic: parsing, diffing, upsert, image pipeline). Default at 1 is Code; no
override fires — the import preview is novel but structural, and prose
specifies it adequately.
### 5.2 Screen: Products (serves PUC-1, PUC-7, PUC-8, PUC-9, PUC-11)
- **Purpose:** the catalog's home in the admin; where imports start, exports
download, and past imports are reviewed. Created by this design; #14 fills
in the browsable list.
- **Layout (top → bottom):**
- **Header row:** title "Products" + product count (e.g. "Products · 412");
actions right-aligned: secondary **"Export"** (opens a small menu: status
filter All / Active / Draft / Archived, then downloads — PUC-9; disabled
with a note when the catalog is empty), primary **"Import products"**
(→ §5.3).
- **Notices band (conditional):** image-problems aggregate notice — "N
products have image problems" linking to the most recent run's detail
(PUC-7); shown while any product's image status is rejected/failed.
- **Primary content, empty catalog:** empty state — "No products yet. Bulk
import is how product data gets in." with the **"Import products"**
action repeated, plus links **"Download sample CSV"** and **"Column
reference"** (PUC-11).
- **Primary content, populated catalog:** the honest pre-#14 state — the
product count and one line: "Your catalog is loaded. The browsable
product list arrives with an upcoming release." (replaced by #14's list).
- **Import history (section):** table of runs, newest first — date · file
name · dialect · added / updated / errors · image outcomes (e.g.
"4,938 ✓ · 12 ✗") · status (Importing… / Fetching images… / Complete /
Complete with problems). Row click → run detail (§5.5). Empty state: "No
imports yet."
- **States:** loading: skeleton for count + history · error: honest failure
banner with retry (INV-9 spirit) · empty/populated per above.
- **Notifications:** none beyond the notices band (no toasts here; outcomes
live on durable surfaces).
### 5.3 Screen: Import — upload (serves PUC-2, PUC-5a, PUC-11)
- **Purpose:** choose and validate a file.
- **Layout:**
- **Header:** "Import products", back to Products.
- **Primary content:** drop zone / file picker ("CSV, up to 5,000 rows");
beneath it the format help: "Works with the canonical format or a Shopify
product export." + links to sample CSV and column reference (PUC-11).
- **Actions:** none beyond the picker — selecting a file starts upload +
validation immediately (one fewer click; canceling is free, PUC-3a).
- **States:** idle · uploading/validating: progress ("Validating… 2,140 of
4,950 rows") with cancel · file-level rejection (PUC-5a): error banner
naming the one problem ("This file is missing the required column
'Title'"), picker remains for retry · success: → preview (§5.4).
- **Notifications:** none (errors render in place).
### 5.4 Screen: Import — preview (serves PUC-3, PUC-3a, PUC-5, PUC-6, PUC-10)
- **Purpose:** the consent gate — see exactly what will happen, then decide.
- **Layout:**
- **Header:** "Import preview — ⟨file name⟩"; dialect line: "Recognized:
Shopify product CSV — mapped to canonical" or "Canonical format" (PUC-6).
- **Warnings band (conditional):** columns not imported, listed by name
(unknown-column warning); collapsible when long.
- **Summary tiles:** **N to add · M to update · U unchanged · K errors**
each tile filters the detail list below.
- **Detail list:** one row per product (grouped from its variant rows):
handle, title, change kind (add / update / unchanged / error), variant
count. Expanding a row drills in (PUC-3): adds show the fields to be
set; updates show a field-by-field **before → after** diff (only changed
fields, per variant where applicable); errors show the error detail.
- **Error table (under the errors filter):** line number · column · plain-
language problem ("row 214: 'Variant Price' — '12,50' is not a price").
- **Actions (sticky footer):** primary **"Import N products"** (disabled
when nothing valid to apply — all-unchanged reads "Nothing to change —
your catalog already matches this file", PUC-10); secondary **"Cancel"**
(returns to Products, no trace, PUC-3a).
- **States:** the preview *is* a state machine of its content (mixes of
add/update/unchanged/error per above); plus stale-session expiry: a preview
left open past its validity window (§6) prompts re-validation rather than
applying stale diffs.
- **Notifications:** none.
### 5.5 Screen: Import run detail (serves PUC-4, PUC-5, PUC-7, PUC-8)
- **Purpose:** the durable record of one confirmed import — what applied, what
errored, how the image fetch went. The post-confirm landing page and the
import-history destination.
- **Layout:**
- **Header:** file name · imported ⟨relative time⟩ by ⟨email⟩ · dialect.
- **Result summary:** added / updated / errors counts (mirrors the preview's
final numbers).
- **Images section:** while fetching — progress "Fetching images: 312 of
4,950" (updates live); when done — outcome summary ("4,938 fetched ·
9 rejected · 3 failed") and an outcomes table listing only problems:
product handle · variant · image URL · outcome (rejected: below the
resolution bar / not an image · failed: unreachable) · what to do
("correct the URL and re-import"). All-clean collapses to one line.
- **Error table:** the run's unapplied rows (line · column · problem),
exactly as the preview showed them (PUC-5).
- **States:** applying ("Importing…") · fetching images · complete · complete
with problems (errors and/or image problems present).
- **Notifications:** in-app only (decided: no email summaries in the MVP).
## 6. Technical Design