← back to Designer Wallcoverings

pending-approval/dw-trade-tier-persist-2026-07-09/MEMO.md

85 lines

# DW sign-in tier (3 vs 10 samples) now survives the cross-origin sign-in round-trip

**Status:** BUILT + VERIFIED + STAGED. Customer-facing LIVE theme push is GATED — run
`push-to-live.sh` to ship. $ cost: $0 (all local).

**Live theme:** #144076931123 (5.9.1). Source of the fix:
`~/Projects/Designer-Wallcoverings/shopify/dw-trade-persist-20260709/` (git repo, HEAD `64a88ac`).

---

## STEP 1 — Traced consumption (the crux)

- **Writer** — `snippets/dw-signin-modal.liquid`, runs on the **storefront** origin
  (`www.designerwallcoverings.com`), rendered on every logged-out page
  (`layout/theme.liquid` line 1345, `{% unless customer %}`). On "Professional" it wrote
  `sessionStorage['dw_trade']='1'` right before redirecting to Google (open-signin app) or
  email (native Shopify hosted login).
- **Claimed consumer** — `templates/customers/account.liquid` (and `templates/customers/register.liquid`)
  read `sessionStorage.getItem('dw_trade')` and `location.replace('/pages/trade-only-benefits')`.
- **CRITICAL origin finding** — this store is on **NEW customer accounts**:
  `GET /account`, `/account/login`, `/account/register` all **302/406-bounce to
  `https://shopify.com/1541177456/account`**. The theme's classic-account templates therefore
  **never render** — `templates/customers/account.liquid` is effectively **dead code**.
- **So the tier was lost for TWO reasons**: (a) `sessionStorage` is per-origin and cleared on
  the shopify.com auth hop; (b) even if it survived, the consuming template is never displayed.
- **Behavior the flag drives** — route the returning user to `/pages/trade-only-benefits`
  (the 10-sample trade path). That page is theme-rendered on the storefront and returns 200.

**Consumption origin conclusion:** the tier is consumed on the **STOREFRONT** origin
(the user returns to `www.designerwallcoverings.com` after auth). A storefront cookie/localStorage
is sufficient — it does NOT need to reach the `shopify.com` account origin, because the flag only
routes the user to a storefront `/pages/` URL. It gates nothing on the shopify.com hosted pages.
**No customer-tag / server-side write is required for the routing behavior.** (See residual note.)

## STEP 2 — Mechanism (tied to Step 1)

1. **Durable persistence** — the writer now sets `dw_trade` in **localStorage + a first-party
   cookie** (`path=/; max-age=1800; SameSite=Lax`) in addition to sessionStorage. localStorage +
   cookie on the storefront origin persist across the navigation away (to shopify.com) and back;
   sessionStorage was the only reason the flag was lost.
2. **Real consumer** — a new `{% if customer %}` hook in **`layout/theme.liquid`** (runs on every
   storefront page for a logged-in customer). On return, if the durable flag is set and the user
   isn't already on the benefits page, it routes once to `/pages/trade-only-benefits` and clears
   all channels. This replaces reliance on the dead classic-account template.
3. **Fallback** — `account.liquid` / `register.liquid` readers updated to read the durable store
   too (belt-and-suspenders if the store ever reverts to classic accounts). Google + email routing
   and the Retail/Pro chips are unchanged. No new third-party deps.

## STEP 3 — Round-trip verification (headless, domcontentloaded)

`verify-roundtrip.mjs` runs the EXACT persistence + consumer JS from the edited files across two
distinct origins (storefront A ↔ cross-origin auth B). Result: **ALL PASS ✅**

- **Professional**: durable store = `localStorage=1 sessionStorage=1 cookie=1` after pick, held on
  A through /auth, correctly empty on cross-origin B (per-origin), and on RETURN the consumer fired →
  **final URL `/pages/trade-only-benefits`** (10-sample path), flag cleared.
- **Retail**: no flag written, consumer did NOT route → stayed on the storefront (3-sample default).

## STEP 4 — Validation

- `node --check` on every embedded JS block (incl. the new writer/hook/reader): **all OK**.
- `shopify theme check`: my edits introduce **ZERO new offenses** (the 84 offenses are
  TranslationKeyExists / MissingAsset / MissingTemplate / 2 LiquidHTMLSyntaxError — all
  partial-checkout artifacts; the pre-edit baseline had *more* offenses: 101 vs 84). No offense
  references dw_trade / the hook / cookie logic.
- Local commits (author steve@designerwallcoverings.com, no remote push): baseline `a09e20e` →
  fix `4036244` → verifier `64a88ac`.

## Residual gated piece

The routing fix is **client-only and complete for the "which page does the Pro land on" behavior**.
It does NOT write a Shopify **customer tag** (e.g. `dw_trade`). If DW wants the Pro's tier to be a
durable server-side attribute on the customer record (so the 10-sample entitlement is enforced
server-side / in emails / across devices, not just a one-time landing redirect), that requires a
**customer-tag write** — a canonical, gated action. That is **NOT done here** and is **NOT required**
for the landing-page routing. Draft it separately if you want server-side entitlement.

## Push command (GATED — run to ship)

```sh
bash ~/Projects/Designer-Wallcoverings/pending-approval/dw-trade-tier-persist-2026-07-09/push-to-live.sh
```

Backs up all 4 current-live assets to `shopify/theme-backups/` first. Revert = PUT the `.bak` back.