Files
wiggleverse-ecomm-content/specs/SD-0002-products-bulk-csv-import-export.md
T

33 KiB
Raw Blame History

Solution Design: Products — bulk CSV import/export

Anchor wiggleverse/wiggleverse-ecomm#13 (type/feature, priority/P1) — parent epic #12
Author(s) Claude (session ecomm-0030), for Ben Stull
Reviewers / approvers Ben Stull
Status draft
Version v0.1.0
Source artifacts BDD corpus: prototype rfcs 11-05-* (products import/export) · research/shopify/products · Prototype: wiggleverse-ecomm-prototype · Reference: Shopify product CSV · Builds on: SD-0001 · Supersedes: —

Change log

Date Version Change By
2026-06-11 v0.1.0 Initial draft — §1 Business Context (session ecomm-0030) Claude + Ben

1. Business Context

The business lens — solution-agnostic throughout. No mechanism is proposed until §2.

1.1 Executive Summary

A merchant's catalog already exists before they ever meet this platform — in spreadsheets, in their current platform's export, in the working files they price and re-price every season. The value at stake is letting that catalog become their storefront without re-entering it, letting catalog-wide changes (a season's prices, a supplier's new costs) land as one gesture instead of hundreds, and guaranteeing the catalog can leave whole at any time — so adopting the platform never means retyping a business in, and never means locking a business up. The beneficiaries are merchants — most acutely those migrating from another platform — and the platform itself: every downstream capability of an ecomm (browsing, orders, checkout) presupposes a real catalog existing, and today none can.

1.2 Background

ecomm is Wiggleverse's multi-tenant Shopify alternative. Its first Solution Design (SD-0001) shipped sign-up, identity, and single-storefront creation: a merchant can exist and their storefront can exist — and that storefront is, by design, an honestly empty shell ("There's nothing to manage yet").

The Products MVP epic (#12) is the next move: give the storefront a real product catalog. The epic makes a deliberate boundary decision: the MVP ships no per-item editing — bulk ingestion and extraction is the only way product data moves. Its sibling Features display the catalog (#14, list + read-only detail) and extend it to bundled offerings (#15, kits); this Feature is the mechanism they all feed from.

The backdrop that makes bulk-first the right boundary: real merchant catalogs are not built one item at a time inside an admin tool. Merchants switching platforms hold their entire catalog as an export of their current system — hundreds of products, each with variations, images, and prices. Merchants who stay maintain their catalogs batch-wise: a seasonal price list, a supplier's updated cost sheet, a spreadsheet kept as the working source of truth. The catalog's natural lifecycle is bulk in, bulk update, bulk out.

1.3 Business Actors / Roles

Real-world roles — they exist whether or not this platform does.

Role Responsible for (in the business)
Merchant Owns a storefront's catalog: what is sold, at what price, shown how. Keeps it current as seasons, suppliers, and stock change.
Migrating merchant A merchant switching platforms. Their catalog already lives, complete, in their current system and its export files; they decide whether switching is worth the cost.
Platform builder Builds and validates the capabilities a catalog feeds (browsing, orders, demos). Needs realistic catalogs to exist before those capabilities can be exercised.

1.4 Problem Statement

A storefront can exist but cannot hold anything sellable: there is no way to get product data into the platform at all, and the MVP deliberately offers no per-item editing to fall back on. For the merchant whose catalog already exists elsewhere — the common case — hand re-entry of hundreds of products, each with variations, imagery, and prices, is a switching cost that simply ends the conversation. The gap recurs after adoption: catalog maintenance is batch-shaped (whole-catalog price changes, supplier updates), and one-at-a-time upkeep mismatches how merchants actually work their data. And data that goes in must come out: a catalog that cannot be extracted whole makes the platform a trap, which careful merchants correctly treat as a reason not to enter.

1.5 Pain Points

# Pain Who feels it Cost / frequency today
PP-1 A created storefront is a dead end — nothing to sell, nothing to manage, nothing to show Merchant Total: blocks any real use of the platform; felt by every merchant immediately after sign-up
PP-2 An existing catalog would have to be re-keyed item by item to move over Migrating merchant Hundreds of products × dozens of fields each — a prohibitive switching cost; prospective merchants don't switch
PP-3 Catalog-wide changes (season prices, supplier costs) have no whole-catalog gesture Merchant Recurring — every season, supplier change, or repricing event; effort scales with catalog size
PP-4 No realistic catalog can be stood up to build, demo, or validate against Platform builder Continuous — every product-dependent capability (#14, #15, future orders) is blocked or faked
PP-5 Whatever goes in cannot be gotten back out — the catalog would be trapped Merchant Felt at the adoption decision (a reason to say no) and at every backup/audit/leave moment after

1.6 Targeted Business Outcomes

# Outcome Success metric Baseline → Target Guardrail (must not regress) How / when measured
BO-1 Merchants with existing catalogs adopt — populating a storefront is hours, not weeks # storefronts holding a real catalog; effort to first full catalog 0 storefronts can hold a catalog → a several-hundred-product catalog lands in under an hour of merchant effort Sign-up → storefront flow (SD-0001) stays intact Platform records (operationalized §8.1); reviewed monthly
BO-2 Catalog upkeep happens in the platform — merchants refresh in bulk rather than letting data go stale or leaving # storefronts performing repeat bulk updates No upkeep possible → catalog-holding storefronts update in bulk as their prices/data change Existing catalog data never corrupted by an update Platform records; reviewed monthly
BO-3 "My data would be trapped" is a non-objection — the catalog is extractable whole, always Full-catalog extraction available and exercised No extraction exists → every storefront's complete catalog can be taken out on demand, at any time Extraction completeness: nothing the merchant supplied is unrecoverable Platform records; reviewed quarterly
BO-4 Product-dependent work is unblocked — sibling and downstream capabilities build against real catalogs #14 / #15 / future order work proceeding against realistic data Nothing to build against → realistic catalogs standable in minutes Delivery record of #14/#15; per Feature

1.7 Scope (business)

  • In scope: populating a storefront's catalog in bulk from records the merchant already holds; updating the catalog in bulk; extracting the complete catalog at any time. "Catalog" here means products in full commercial reality: variations (size/color and the like), imagery, organization (vendor, type, tags, category), pricing/cost, stock levels, and publication state.
  • Out of scope: per-item create/edit (a later epic — the MVP's deliberate boundary); removing products in bulk (nothing is deleted by this mechanism — see §2); automated or scheduled synchronization with other platforms; movement of non-catalog data (customers, orders — other epics); the meaning and behavior of bundled offerings (kits — Feature #15, which rides this mechanism but defines its own semantics).
  • Non-goals: real-time integration with other commerce systems (the supplied file is the boundary, deliberately); making the MVP a catalog editing tool of any kind.

1.8 Assumptions · Constraints · Dependencies

  • Assumptions: merchants hold, or can readily produce, their catalog as a structured file (a spreadsheet, their current platform's export). Risk if wrong: a merchant with no digital catalog at all has no entry path in this MVP. Catalogs at MVP scale run to a few thousand items. Risk if wrong: larger catalogs need heavier machinery (a named seam, §2).
  • Constraints: bulk-only is Epic #12's deliberate MVP boundary — this design must not quietly grow per-item editing. One storefront per account (SD-0001 INV-4) — a merchant's catalog context is unambiguous.
  • Dependencies: SD-0001's shipped surfaces (identity, storefront, admin shell) — live as of v0.4.0. Sibling #14 displays what this ingests; sibling #15 extends what the records can express — both sequence after this mechanism exists.

1.9 Business Use Cases

BUC-1 — As a migrating merchant, I can bring my existing catalog into my storefront in one bulk gesture, so that switching platforms doesn't mean re-keying my business.

Scenario: BUC-1 — An existing catalog comes over whole
  Given a merchant whose catalog of several hundred products lives in an
    export from their current platform
  When they supply that catalog to their storefront in one gesture
  Then the storefront holds the full catalog — every product with its
    variations, imagery, organization, and prices
  And nothing had to be re-entered by hand
  • BUC-1 acceptance criteria: the catalog the storefront holds matches the records the merchant supplied, completely; the merchant's effort is one supply-and-review gesture, not per-product work.

BUC-1a — unhappy path: unusable records are reported, not silently dropped.

Scenario: BUC-1a — Unusable records come back with actionable feedback
  Given a merchant supplies catalog records of which some are incomplete,
    contradictory, or unreadable
  When the storefront cannot accept some of the records
  Then the merchant is told exactly which records failed and why, in terms
    they can act on
  And they can correct and re-supply the problem records
  And nothing is silently dropped, guessed at, or invented
  • BUC-1a acceptance criteria: every rejected record is identified with an actionable reason; accepted vs. rejected is fully accounted for — the merchant is never left wondering what made it in.

BUC-2 — As a merchant, I can see exactly what a bulk change will do to my catalog before it happens, so that I never damage my own data by accident.

Scenario: BUC-2 — A bulk change is reviewed before it takes effect
  Given a merchant about to apply a bulk change to a catalog their business
    depends on
  When they supply the new records
  Then they see what will be added, what will change (and to what), and what
    is in error — before anything takes effect
  And the change happens only when they say so
  • BUC-2 acceptance criteria: the preview is complete and faithful (what it shows is exactly what applying does); declining costs nothing; nothing changes without the merchant's explicit go-ahead. (OHM: consent & agency — the merchant authorizes the change knowing what it is.)

BUC-3 — As a merchant, I can update my whole catalog at once, so that batch-shaped changes (seasonal prices, supplier costs) cost one gesture instead of hundreds.

Scenario: BUC-3 — A catalog-wide change lands as one gesture
  Given a storefront holding a catalog, and a season's repricing touching
    most of it
  When the merchant supplies the updated records
  Then the affected products are updated to the new values
  And the unaffected products are untouched
  And no duplicates are created
  • BUC-3 acceptance criteria: updates land on the products they target; re-supplying unchanged records changes nothing (supplying the same catalog twice never doubles it); the merchant's effort does not scale with catalog size.

BUC-4 — As a merchant, I can take my complete catalog out at any time, so that my business data is never trapped in the platform.

Scenario: BUC-4 — The catalog leaves whole, on demand
  Given a storefront holding a catalog the merchant built up over time
  When the merchant asks for their catalog
  Then they receive the complete catalog — every product, variation, image,
    and price — in a form they can use elsewhere
  And what they receive could rebuild the same catalog faithfully
  • BUC-4 acceptance criteria: extraction is always available, complete (nothing the merchant supplied is unrecoverable), and round-trips — what comes out can go back in and reproduce the same catalog. (OHM: agency — leaving is always possible; the platform earns retention, never extorts it.)

2. Solution Proposal

Build software: CSV file import/export in the storefront admin — a new Products surface where a merchant uploads a CSV to add and update products in bulk, and downloads a CSV of the full catalog at any time.

The shape of it:

  • One canonical CSV format, Shopify-flavored: one row per variant, consecutive rows sharing a Handle form one product (with its options, variants, and images). The column set is a deliberate superset of Shopify's product CSV — adding component columns (the kits seam, #15), volume, cost/tax fields — so a Shopify export is structurally familiar and our format never needs to churn when siblings arrive. The full column specification is §6.
  • Two accepted dialects, auto-detected: the canonical format, and Shopify's own product-CSV export (mapped onto canonical at the boundary). The header row identifies the dialect; the merchant never picks from a menu. This is the migrating merchant's path (BUC-1): their existing export imports directly.
  • Import is upsert-only. A row whose Handle is new creates a product; a known Handle updates it (variants matched by option-value combination). Nothing is ever deleted by an import — the mechanism is non-destructive by construction, so a partial file can never silently destroy catalog (BUC-2's safety, structurally).
  • Validate-all → preview → confirm. The whole file is validated and diffed against the catalog before anything is written. The merchant sees a summary — N products to add, M to update, K rows in error — and can drill into any record to see exactly which fields will change and to what. Nothing applies until they confirm; confirming applies the valid records and leaves the error rows listed, unapplied, and actionable (BUC-1a, BUC-2). Unrecognized columns are warned about in the preview and ignored, never silently dropped.
  • Synchronous, with a stated capacity of ~5,000 rows per file. No job queue in the MVP; the design names the async seam for when catalogs outgrow it (§6.9). One deliberate exception rides that seam's first rail: images.
  • Images are fetched and hosted. Image Src URLs are downloaded into platform object storage after the catalog rows commit, with renditions (thumbnail / card / detail) generated at fetch. Images that can't be fetched, aren't images, or fall below the resolution bar are rejected (the product shows a placeholder), with the outcome reported per image. The catalog is self-contained: exports reference our hosted copies, and the storefront never depends on a third-party host staying alive.
  • Imports are first-class records. Every import run is kept — file name, dialect detected, who ran it, add/update/error counts, image-fetch outcomes — with a detail view the merchant can leave and return to (the post-commit image phase reports there and on the Products page).
  • Export is one gesture: the complete catalog (optionally filtered by status) as a canonical CSV. Export → re-import is lossless and idempotent — the acceptance bar from #13 and BUC-4's round-trip guarantee.

Why this approach. CSV is the medium merchant catalogs already live in: every platform exports it, every spreadsheet tool speaks it, and the migrating merchant (the sharpest pain, PP-2) holds one today. Accepting Shopify's dialect directly converts the largest migration population's existing artifact into a working catalog with zero transformation effort. Upsert-only plus preview-confirm makes a powerful bulk mechanism safe to hand to a non-technical merchant: the destructive operations simply don't exist, and every change is consented to with full knowledge (OHM: consent & agency).

Alternatives weighed (detail in §6.7): a per-item editing UI first (rejected — Epic #12's explicit boundary, and it does nothing for migration); integration APIs / direct platform connectors (rejected — heavy, narrow, and premature before the catalog model exists); accepting spreadsheet formats (XLSX) (rejected for MVP — CSV covers the actual artifacts merchants hold; XLSX is an adapter behind the same boundary later); do-nothing / concierge data entry by the operator (rejected — doesn't scale past a demo and builds no product capability).

Solution-specific non-goals: no deletion semantics of any kind in the CSV; no scheduled/automated re-import; no foreign dialects beyond Shopify's product CSV in the MVP; no kit semantics (the format carries the columns; #15 defines their meaning); no image editing/cropping — the platform hosts what the merchant's URLs provide, or rejects it.

3. Product Personas

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

Corpus grounding: scenario IDs cite the prototype corpus's products import/export scenarios (rfcs 11-05-00320037). 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)

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)

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)

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
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)

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)

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
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)

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)

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
    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)

PUC-8 — Import history (realizes BUC-2's accountability)

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)

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)

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 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)

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

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

(not yet authored)

7. Delivery Plan

(not yet authored)

8. Success Metrics & Measurement

(not yet authored)

9. Telemetry, Observability & Monitoring

(not yet authored)

10. Operations

(not yet authored)

11. Documentation plan

(not yet authored)

12. Traceability matrix

(not yet authored)

13. Open Questions & Decisions log

(not yet authored)

14. Glossary & References

(not yet authored)