# Deployment & go-live checklist

Everything is built and tested locally. This is the ordered path to production, and
exactly what I need from you to finish wiring the live store.

## What I need from you (blockers)

1. **Shopify admin access** — either:
   - authorize the **Shopify** connector in your claude.ai connector settings (then I can
     create the metaobjects, metafields, and pull real product GIDs directly), **or**
   - a **custom app** with an Admin API token (scopes below) + the store domain.
2. **Appstle API key** + confirmation of the exact **plan-swap** endpoint/payload
   (the `/upgrade` handler is stubbed against a placeholder URL). Also: does Appstle
   already generate the quarterly renewal **order**, or only the charge? This decides
   whether fulfillment **edits Appstle's order** vs. **creates its own** (see below).
3. **Membership tagging** — confirm we can drive `wineclub` + `wc-tier:<key>` tags from
   Appstle via Shopify Flow (or you tag pilot members manually to start).
4. **Email provider** — Resend API key + a verified `FROM_EMAIL`, or tell me to use
   Shopify Email / Postmark / SendGrid instead (one function to swap).
5. **Copy sign-off** — approve the two email drafts in [emails/](emails/).
6. **The two open product decisions** in [flows/02](flows/02-fulfillment-generation.md)
   and [flows/03](flows/03-fallback.md): out-of-stock substitution behavior, and
   unpaid-add-ons-at-close behavior.

## Setup order

### 1. Metaobjects & metafields
- Run [metaobjects/definitions.graphql](metaobjects/definitions.graphql) (5 definitions).
- Add `wineclub.vintage`, `wineclub.wine_type`, `wineclub.catalog_group` to each wine product.
- Seed the active cycle + one tier pool per tier ([metaobjects/seed-q2-2026.md](metaobjects/seed-q2-2026.md)).

### 2. Theme
- Upload `theme/assets/wine-club-customize.{css,js}` to the theme.
- Add `theme/sections/wine-club-customize.liquid` + `theme/snippets/wine-club-customize-data.liquid`.
- Create page `/pages/wine-club-customize` using a template that renders the section.
- Verify tier/cycle resolution with a test customer tagged `wineclub` + `wc-tier:classic-3`.

### 3. App Proxy Worker
- Custom app → App Proxy: prefix `apps`, subpath `wineclub`, URL = the Worker.
- `wrangler secret put` all secrets (listed in [app-proxy/README.md](app-proxy/README.md)).
- `wrangler deploy`. Cron (daily 08:00 UTC) is configured in `wrangler.toml`.
- Admin API scopes: `read_customers`, `write_customers`, `read_products`,
  `write_draft_orders`, `write_orders`.

### 4. Automations
- Reminder + fulfillment run from the Worker's `scheduled()` handler — no separate Flow
  needed. Verify by temporarily setting a cycle's `close_at` to today (+10 for reminder)
  in a staging context.
- Set up the Flow that writes `wineclub` / `wc-tier:*` tags on Appstle subscription events.

## Test / verification status (local)

- `node --check` passes on portal JS and Worker.
- **Portal**: 23/23 headless (jsdom) assertions — render, swap, live re-pricing, filters,
  one-time add-on add/remove, min-bottle gating, lock-in.
- **Worker**: 15/15 unit assertions — server-side reprice/off-pool rejection, date math,
  HMAC message construction, pricing parity with the portal, idempotent fulfillment,
  fallback path, signature-before-admin ordering.
- Open `theme/preview.html` in a browser for a live visual check.

## Still stubbed / pending real data
- Appstle plan-swap call (`handleUpgrade`) — placeholder URL.
- Fulfillment order strategy — currently creates a draft order; may need to compose onto
  Appstle's renewal order instead (decision #2 above).
- Reminder email listing actual default bottle **names** (currently positions) — small add
  once product titles are loaded in the reminder task.
