Draft v1.2 · 2026-07-06 Adversarially QA-reviewed

Nanobag Product Consolidation Plan

Merging six per-market duplicate products into one canonical reusable-shopping-bags — staged invisibly, switched on by merging to the GitHub-connected live theme (translations preserved).

What's happening & why for everyone

Today Nanobag sells the same physical bags through six separate Shopify products — one per market (US, EU, Canada, UK, Singapore, International). This split hurts us everywhere: Google sees duplicates and ranks none of them well, reviews are scattered six ways, every content or price change is done six times, and the cart breaks when a shopper crosses markets.

Shopify shipped a feature in July 2026 (variant-level publishing) that lets one product show a different selection of colors/styles per market. That removes the original reason the duplicates were created. This plan merges everything into the main US product, reusable-shopping-bags, while keeping each market's exact current assortment and prices.

Nothing changes for customers until the final switch. All preparation happens invisibly on the live product. "Go live" is one git merge to the live theme's main branch — the theme updates in place, keeping all its translations and settings. Rolling back is reverting that merge. Prices stay exactly as they are today in every market.

Not touched at all: the Meta-catalog and TikTok ad products (ads are running on them), free-gift products, and the Daypack/Standard standalone US products.

6 → 1
market products merged into one canonical
133
unique Style × Color combinations across all markets
20
variants to add to the canonical (created hidden)
7
phases, each independently reversible
1 click
cutover = publishing the prepared theme

The plan at a glance for everyone

Who does what for everyone

Shubham (Shopify admin / accounts)Claude (scripts & theme code)
Create the Admin API token (one-off, scoped)Variant mapping matrix — done (consolidation-variant-matrix.csv)
Sign off the Phase 0 gates: live feature test, price-list check, inventory pooling, SKU auditAll Admin GraphQL scripts (variant creation, market publishing, price lists), validated before handover
Google Search Console check; Judge.me review grouping; nav menusTheme repoint edits (~25 templates + gallery snippet) on a branch
Run the scripts (or hand over the token); push & publish themes; every go/no-go decisionPer-market QA checklists, redirect CSV, monitoring queries
Check ads/emails for links to old products before retiring themPost-cutover verification support

Top risks the QA review caught for everyone

An independent adversarial review (Opus 4.8) produced 15 findings — all folded into the phases below. The headline items:

SeverityRiskHow the plan handles it
BlockerNon-US prices may be fixed lists today, not currency conversion — trusting conversion would silently change EU/CA/SG/INT pricesPhase 0 confirms the live config; plan fix-prices every market from the matrix regardless
BlockerOld + new products both sellable during transition → overselling the same physical stockInventory pooling is a hard precondition before cutover, not an afterthought
BlockerThe new Shopify feature might not filter hidden variants everywhere in the theme (custom variant picker, deep links, structured data)Phase 0.3 live test is the go/no-go gate for the whole architecture
BlockerCollections, search & recommendations are product-level — canonical could be invisible in market listings even with a working PDPPhase 2.3 adds the canonical to every collection + discovery rules before cutover
MajorAll non-US orders switch to SB02- SKUs — 3PL, accounting and Amazon mappings can breakPhase 0.7 SKU-continuity audit before cutover
MajorFree-gift rules & mini-cart metafields point at old product IDsRepointed (not copied) in Phases 1 & 3, verified in QA
MajorOld product URLs going dead before redirects existPhase 6 archives + creates 301s in the same step

Execution detail for dev

Verified data facts (2026-07-06): Style vocabulary identical across all 7 products (daypack, micro, pack, sling, standard, xl); SG/INT differ only in option name (Type vs Style). SKU scheme = market prefix + shared barcode (SB02- US, OP01- EU, CA01- CA, SBUK02- UK, SG01- SG, bare = INT). Canonical (94 keys) is a strict subset of the 133-key union. UK prices +16–29%, non-uniform. Zero compare_at prices exist anywhere. Known data defects: micro/psychedelic has SKU added_later (no barcode) in both sources; sling/petaline CA 15.95 vs 18.95 elsewhere; blank SKUs on CA/UK porcelain pack/sling.

Assortment rule: a variant is published to a market's catalog iff that market's dup has that Style×Color today (matrix column presence). Targets: US 94 · EU 98 · CA 96 · UK 105 · SG 110 · INT 100 of 114 canonical variants post-gap-fill.

Phase 0 — Preconditions & go/no-go gates ~2 days · mixed
  1. USER Custom-app Admin API token: read/write_products, read/write_publications, read_markets, read/write_price_lists.
  2. CLAUDE Query markets/catalogs/publications + price lists — confirm whether EU/CA/SG/INT already use fixed price lists. Output: publication & pricing map appendix.
  3. BOTH Variant-publishing live test (architecture gate). Unpublish ONE variant of a low-traffic product from ONE market catalog, verify in that market context:
    • native variant picker hides/disables it;
    • the PDP shim's variant array (Liquid product.variants) excludes it — the custom controller is the real rendering path;
    • ?variant=<id> deep-link and /cart/<variant_id>:1 permalink blocked or fall back safely;
    • selected_or_first_available_variant never resolves to a market-hidden variant;
    • product JSON-LD doesn't emit the hidden variant;
    • /products/<handle>.js, /cart/add, checkout all block it.
    If Liquid does NOT filter unpublished variants → STOP; fallback = theme-side gating via market metafield (minicart_variant pattern).
  4. USER Quick win regardless: unpublish test-us-nanobag-2x-weight.
  5. USER GSC: confirm reusable-shopping-bags out-ranks the dup PDPs; if not, reopen canonical choice.
  6. USER Inventory pooling — hard prerequisite. Move/sum dup quantities into canonical inventory items and zero the dup pools before Phase 4 (or explicitly accept a buffered overlap).
  7. USER SKU-continuity audit. 3PL/WMS, accounting/COGS, Amazon FBA/MCF, feeds — add SB02- mappings or re-key on barcode.
  8. USER Lifecycle audit. Klaviyo flows, abandoned-checkout, back-in-stock, wishlists referencing dup IDs; ads/emails with ?variant= deep links (not just handles).
Phase 1 — Extend canonical invisibly Claude scripts · user runs
  1. Resolve junk-SKU variants first (user supplies real barcode for micro/psychedelic; script validates every source SKU matches <prefix>-<barcode>, halts on exceptions).
  2. Add the 20 missing variants via productSet with published: false per variant; SKU SB02-<barcode>; price per matrix.
  3. Copy variant images from source dups (productCreateMedia + attach).
  4. Metafields the theme reads (compare-nanobag "In Use" images, custom.minicart_variant contextual values): repoint, don't copy — any value referencing a dup product/variant ID is rewritten to the canonical ID.
  5. Product-level translation migration (v1.2). Theme translations survive the GitHub cutover, but product content translations (title, description, option name "Style", option/variant values, SEO fields) live on the product — and canonical has only ever served US. Script: read each dup's translations via translatableResource(s), register the union onto canonical via translationsRegister per locale.
  6. Verify: 114 variants in admin; US PDP unchanged; new variants invisible per Phase 0.3 results; canonical PDP content spot-checked in ≥3 languages.

Rollback: delete the 20 variants and their created media / copied metafields.

Phase 2 — Market publications, pricing, discovery Claude scripts · user runs
  1. Per market catalog: set variant publication states FIRST (publishableUnpublish the variants not in that market's assortment), THEN publish the product to the catalog — documented safe order, no wrong-assortment window.
  2. Fixed price lists for EVERY market from the matrix (UK definitely; EU/CA/SG/INT per Phase 0.2 findings — freeze today's shopper-visible prices either way). Include the petaline decision (Open Q3b).
  3. Collections & discovery: add canonical to every collection each dup belongs to; update Search & Discovery boosts/recommendation rules.
  4. Google Merchant Center: repoint the organic/free-listings feed (and any GMC feed not served by the untouched meta-catalog products).
  5. Verify per market via subfolder URLs: PDP reachable, assortment counts, ≥10 price spot-checks/market incl. UK + petaline, variant images, collection membership.

Rollback: unpublish canonical from the new market catalogs; remove from added collections. Dups still serve all traffic.

Phase 3 — Theme repoint on the Shubham branch + QA theme Claude edits · user pushes & QAs
  1. Repoint every dup-handle reference to reusable-shopping-bags: ~25 contextual templates (index.context.*, cart.context.*, page.ebfcm-template.context.*, index.sl-531E49B0.context.*, overlay-group.context.*), snippets/product-media-gallery-new.liquid:212,373, nav menus (USER, admin). All edits stay on the Shubham branch — nothing touches main (the live theme) until cutover.
  2. Check PDP shim / new-main-product for Type option-name or dup-handle assumptions (expected none — keys on Style).
  3. Free-gift rules: nb-gift-rules qualifying product IDs + EG app config must include the canonical product ID per market.
  4. USER For QA: connect a second, unpublished theme to the Shubham branch (or CLI-push it). A fresh theme has no theme-content translations — fine for functional QA; for language-fidelity QA run scripts/copy-theme-translations.mjs onto it.
  5. QA each market via preview: PDP, picker + shim, gallery, compare-nanobag block, minicart recommendation, free-gift add, cart, checkout, translated PDP content (Phase 1.5).

Rollback: don't merge. Delete the QA theme when done.

Phase 4 — Cutover = merge to main user
  1. Precondition check: inventory pooling (0.6) executed; SKU mappings (0.7) live.
  2. Drift control (the contextual JSON files are written both by us and by Shopify's theme editor): customizer freeze for the window; sync Shubham with latest main; re-verify the repoint diff on fresh templates; never merge unintentional settings_data.json changes; merge promptly.
  3. USER Safety snapshot: duplicate the live theme in admin right before merging (frozen fallback; verify it carried translations — git revert remains the translation-safe rollback either way).
  4. USER Merge Shubhammain. The GitHub integration updates the live theme in place (~1 min); translations/settings/app embeds untouched (theme ID unchanged). Dups remain published with zeroed/pooled inventory — no oversell. Update nav menus now; add canonical to market collections a few hours before the merge, not days.
  5. Watch 48–72h: orders/market, conversion, 404s, checkout errors, free-gift adds, Judge.me widget, 3PL routing on new SKUs.

Rollback: git revert the merge on main and push — the previous live theme code is restored. Reverse the inventory move, revert nav menus. Emergency fallback: publish the step-3 duplicate.

Phase 5 — Reviews user · Judge.me admin
  1. Judge.me product grouping to pool dup reviews onto canonical (reversible; export/import only where grouping can't cover).
  2. Verify count + stars on canonical PDP in 2–3 markets; review rich-results still render.
Phase 6 — Retire dups user · staggered
  1. After ≥2 clean weeks AND lifecycle audit cleared: confirm no live ad/email/flow references dup handles or variant deep-links; drain draft orders referencing dup variants.
  2. Archive + create 301s in the SAME step (/products/nanobag-eu → /products/reusable-shopping-bags etc.). No unpublish-and-wait window. Claude generates the redirect CSV; user imports (admin → Navigation → URL redirects) immediately after archiving.
  3. SEO follow-up: GSC re-indexing, hreflang/canonicals on market-subfolder PDPs, GMC disapproval watch.

Rollback: delete redirects, unarchive, republish.

Open questions — need answers before Phase 1 for everyone

  1. The 19 colorways that exist only on the test product (mocha, metropolis, grove, rainbow birds…) — future launches? Include as hidden-everywhere variants now, or drop?
  2. Inventory pooling mechanics: sum into canonical items, or share inventory items?
  3. (a) UK pricing: keep exact current UK prices (plan assumes yes). (b) sling/petaline CA 15.95 / UK 19.35 anomaly — intentional promo or data error?
  4. Real barcode for micro/psychedelic (needed for its SKU).
  5. nanobag-daypack-us / nanobag-standard-us — fold into canonical in a later pass?
  6. Any automatic discounts/promotions keyed to dup product IDs? (Check admin → Discounts before Phase 4.)
Standing rule: the ad products (*-meta-catalog, TikTok-US) are running live ads and are never archived or repointed in this project. The user pushes and publishes all themes; scripts are run only after user sign-off.