spec(SD-0002 §2): solution proposal — canonical CSV, Shopify dialect, upsert + preview-confirm

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 08:35:48 -07:00
parent 2cb6ccc947
commit 966323b7c3
@@ -226,7 +226,79 @@ Scenario: BUC-4 — The catalog leaves whole, on demand
## 2. Solution Proposal
*(not yet authored — next in the section-at-a-time loop)*
**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