Add shopify-app-launch skill (standard build-to-submission process) and update offers screenshot

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
metatroncubeswdev 2026-10-14 18:26:22 -04:00
parent 0050304273
commit 67c75feec5
4 changed files with 351 additions and 0 deletions

View File

@ -0,0 +1,299 @@
---
name: shopify-app-launch
description: Standard end-to-end process for building, deploying and submitting a public Shopify app to the App Store (dev setup, extensions, protected data, VPS deploy, pricing, listing assets, screencast, review submission). Use whenever the user is building a Shopify app, preparing it for release, deploying it, filling the Partner Dashboard listing, or submitting it for App Store review.
---
# Shopify app launch process
The standard process for taking any public Shopify app from an empty folder to "Submitted for review". It was first run on Offerlyst (Bundles & BOGO, October 2026); `references/offerlyst-example.md` holds that app's concrete values as a worked example.
Work through the phases in order. Each phase ends with a checklist; do not start the next phase while an item in the current one is open, unless the user says to. Track progress with a todo list that mirrors these checklists, and give the user a short status line at the end of each phase.
## Ground rules for Claude
- **Secrets never go in chat or Git.** This covers the client secret, DB passwords, encryption keys and storefront passwords. Generate them on the server (`openssl rand -hex 32`) and put them in `.env`, which is gitignored. If the user pastes one, tell them to rotate it.
- **The user types every password.** Claude does not enter passwords, payment details or create accounts. When a page needs one, open it, highlight the field and hand over to the user.
- **Before any irreversible click, confirm.** "Submit for review", deleting an app, and accepting terms or OAuth grants each need an explicit yes in chat for that click.
- **Cookie banners:** never click "Accept". If one covers the screen while recording, hide it with JS.
- **Use the Shopify AI Toolkit skill (`shopify`)** for every Admin GraphQL query, Function, Polaris and Liquid file. Search the docs, then validate. If a validator is broken, say so and fall back to `tsc` or `shopify app build`.
- **Verify, don't assume.** After every deploy, run `curl` against the live URL and check that the change you made is actually there.
---
## Phase 1: Decide the product before coding
1. **Write the brief:**
- the problem
- the 3–5 core features
- which features each plan gets
- the competitors (name, entry price, rating, what they lack)
2. **Choose the name.**
- Check the App Store (`apps.shopify.com/search?q=<name>`) and domain availability before the user commits.
- The name must not contain "Shopify".
- Keep it under 30 characters. The listing title shows as `Name: Short descriptor` (e.g. "Offerlyst: Bundles & BOGO").
- Pick an `app handle`, which becomes the App Store URL (`apps.shopify.com/<handle>`).
3. **Choose the app domain.** A subdomain of the user's company domain works (e.g. `bundles.metatronlabz.com`). It must not contain "shopify" or "example".
4. **Choose the surfaces.** The options are:
- embedded admin (App Home)
- theme app extension (app embed and/or blocks)
- app proxy (storefront pages under `/apps/<subpath>`)
- Shopify Function (discounts, delivery, payment, validation)
- checkout UI extension
- webhooks
Each one adds review requirements (see Phase 8).
5. **Brand assets.** The user supplies or approves these:
- the icon (1200×1200, full-bleed, no text or Shopify logo)
- a horizontal logo
- a brand palette
**Checklist 1:** brief written · name and handle checked and approved · domain chosen · surfaces listed · icon ready
---
## Phase 2: Scaffold and develop
1. **Scaffold:** `shopify app init`, using the React Router template. Keep its pinned API version, or set the latest stable version (e.g. `2026-10`) in both `shopify.app.toml` and the extension tomls.
2. **Admin UI:** use Polaris web components (`s-page`, `s-section`, `s-grid`, `s-button` ...) and App Bridge.
- Lay out rows that hold long text with `s-grid` (`gridTemplateColumns="auto 1fr auto"`), so the help text wraps inside its own column.
- On Home, show a **setup checklist**: turn on the app embed (deep link `.../themes/<id>/editor?context=apps&activateAppId=<api_key>/<embed-handle>`), create the first item, then preview it. Reviewers check onboarding.
3. **Database:** Prisma. Use SQLite in dev only and switch to Postgres before deploying. Commit the migrations.
4. **Shopify Functions:**
- Prototype in JS. Before choosing a language, measure the instruction count with a large cart (200 lines).
- If JS goes over the limit (11M instructions for discounts), port the function to **Rust** (`shopify_function` crate).
- Keep a JS reference engine plus shared test vectors, so both implementations are tested against the same cases (parity tests).
- Always build with `shopify app function build`. A raw `cargo build` fails with "unknown import shopify_function_v2".
- Windows: use the GNU Rust toolchain if MSVC isn't installed, and build from PowerShell, because Git Bash's `link` shadows the linker.
- Pass configuration through metafields: `$app:configuration` for the function, and `input_variables` for query variables.
5. **Theme app extension:**
- Inherit the merchant theme's fonts and colours; offer accent colour and radius as settings.
- Mobile first: 44px tap targets and 16px inputs.
- Read storefront data from an app-data metafield (`app.metafields.<ns>.<key>`).
6. **App proxy pages:** the merchant's theme CSS may not load on these, especially on draft themes, so inline the app's own CSS and JS. Respect `path_prefix`. Verify the HMAC signature and return 400 for unsigned requests.
7. **Webhooks** (declare them in `shopify.app.toml`):
- `app/uninstalled`
- `app/scopes_update`
- `app_subscriptions/update` (if paid)
- the data topics you need
- **the three mandatory compliance topics:** `customers/data_request`, `customers/redact`, `shop/redact`
8. **Scopes:** request the minimum. Remember the scopes that features imply, e.g. an app proxy needs `write_app_proxy`, and theme embed detection needs `read_themes`.
9. **Tests:**
- unit tests for the core logic
- parity and differential tests for any Function
- `tsc --noEmit`
- `shopify app build`
10. **Public pages:** `/privacy` and `/terms`. The terms must include data processing terms if you touch customer data.
11. **Landing page (`/`):** do **not** show a manual "shop domain" login form. It violates App Store requirement 2.3.1. Show product info only; installs start from the App Store.
**Checklist 2:** app runs in `shopify app dev` on a dev store · Function within limits · tests green · tsc clean · compliance webhooks · privacy and terms pages · no shop-domain form
---
## Phase 3: Link the production app config
1. Run `shopify app config link` to create or link the production app.
- **Back up `shopify.app.toml` first.** `config link` rewrites it and drops webhooks, the proxy, name, handle and api_version. Restore them afterwards.
2. In `shopify.app.toml`:
- `application_url = "https://<domain>"`
- `redirect_urls = ["https://<domain>/auth/callback"]`
- `[build] automatically_update_urls_on_dev = false`, so `shopify app dev` doesn't overwrite the production URLs
- check the `name`, `handle`, scopes, `[app_proxy]` and webhook subscriptions
3. Commit the toml. It holds no secrets. The client secret is shown only in the Dev Dashboard; copy it straight into the server's `.env`.
**Checklist 3:** toml has production URLs · URL auto-update off · webhooks, proxy and scopes present · committed
---
## Phase 4: Protected customer data (if you read orders or customers)
Any `orders/*` or `customers/*` webhook, or any order or customer query, triggers this. Without it, `shopify app deploy` is blocked.
1. Go to Partner Dashboard › App › **API access requests** › Protected customer data › Request access.
2. **Level 1** (no personal fields) is usually enough. Leave name, email, phone and address unticked unless a feature truly needs them; ticking them moves the request to Level 2 and adds many more questions.
3. Give each data use a reason (e.g. "Analytics: apply and report bundle discounts").
4. Answer the data protection questions truthfully, and implement what you claim:
- **Encryption at rest:** AES-256-GCM for identifiers, and HMAC hashes where you only need to match values. Use a 64-hex-character key in `.env` (`DATA_ENCRYPTION_KEY`).
- **Retention:** delete shop data after uninstall, via `shop/redact` (48 hours later).
- **A data processing agreement in the terms:** controller and processor roles, breach notice within 72 hours, sub-processors.
- **Encrypted backups:** `pg_dump` piped through `gpg` or `age`.
- **Access limited to staff,** documented in `SECURITY.md`.
5. Re-run `shopify app deploy`.
**Checklist 4:** request submitted · encryption implemented · terms include data processing terms · deploy succeeds
---
## Phase 5: Deploy to the VPS
1. **Dockerfile:** a multi-stage build that installs all dependencies, builds, then copies the output into a slim runtime that installs production dependencies only. Do **not** prune dev dependencies before `npm run build`. Commit `package-lock.json` (and `Cargo.lock`).
2. **docker-compose:** Postgres plus the app.
- Required env vars: `SHOPIFY_API_KEY`, `SHOPIFY_API_SECRET`, `SHOPIFY_APP_URL`, `SCOPES`, `DATABASE_URL`, `DATA_ENCRYPTION_KEY`.
- Use `${VAR:?}` so a missing variable fails loudly.
- The app runs `prisma migrate deploy` on start.
3. **Reverse proxy:**
- If the VPS has nothing on ports 80/443, add a Caddy service (automatic HTTPS).
- If the VPS **already runs Nginx**, add a compose override that binds the app to `127.0.0.1:<free port>`, an Nginx server block that proxies to it, and certbot for TLS. Check which ports are already in use first.
4. **On the server:**
```
mkdir -p /opt/<app> && cd /opt && git clone <repo> <app> && cd <app>
cp .env.example .env # fill secrets on the server: openssl rand -hex 32
docker compose -f docker-compose.yml [-f docker-compose.nginx.yml] up -d --build
docker compose logs -f app
```
5. **DNS:** an A record for the app domain pointing to the VPS IP.
6. **Verify from outside:**
- `/privacy` and `/terms` return 200.
- Unsigned requests to `/proxy` and `/webhooks/*` return 400 or 401.
- `/` loads with **no** shop-domain form.
7. From the PC, run `shopify app deploy`. It releases the extensions, Function, toml config and webhooks as a new app version.
8. **Redeploy routine:** after every push, run `git pull && docker compose ... up -d --build app` on the VPS, then confirm the change is live with `curl`.
**Checklist 5:** HTTPS live · DB migrated · health checks pass · `shopify app deploy` released · app installs on the dev store and opens embedded
---
## Phase 6: Test on a development store
1. Install from the Dev Dashboard (Test on development store). Open the app from the admin's Apps menu.
2. Walk through every feature as a merchant: onboarding checklist → app embed on → create → publish → storefront → cart → checkout.
3. Test edge cases:
- Several offers or features running at once
- Removing items, which should remove the effect
- Guest storefront access
- Uninstall, then reinstall without errors
4. **Billing:** with managed pricing, choose each paid plan on the dev store. These are test charges, $0. Confirm that the app reads the plan and applies its limits.
5. Fix the bugs, redeploy (Phase 5.8) and retest.
**Checklist 6:** full flow works · edge cases pass · each plan's limits verified · uninstall and reinstall clean
---
## Phase 7: Pricing (Shopify managed pricing)
1. Go to Partner Dashboard › App › Distribution/Listing › **Pricing** › Managed pricing.
2. Create the plans. Keep stable keywords in the plan names (e.g. Starter, Growth, Plus), because the app maps the subscription name to its limits. Add yearly prices if wanted, and a free trial (e.g. 14 days) on paid plans.
3. Make the Free plan public so search shows "Free plan available".
4. A private `shopify-test` plan is created automatically. Leave it alone.
5. The app's Plans page links to `https://admin.shopify.com/store/<store>/charges/<handle>/pricing_plans`.
**Checklist 7:** plans public · trial set · plan names match the code mapping · test subscription approved
---
## Phase 8: Listing content and assets
Go to Partner Dashboard › Distribution › Shopify App Store › Create listing (English).
| Asset | Spec |
|---|---|
| App icon | 1200×1200 PNG or JPG, full bleed, no text, no Shopify logo |
| Feature image | 1600×900, no Shopify trademark or tagline, no pricing, reviews or outcome claims |
| Screenshots | 1600×900 desktop, 3–6 of them, with alt text for each; no pricing, reviews or claims on the image |
| Screencast | a URL only (YouTube Unlisted, Loom, Vimeo); see Phase 9 |
| Promo video | optional public YouTube link; can be skipped |
- **Screenshots:** capture the real UI from the dev store, then frame it in brand colours with a caption. A reusable script exists: `make_screenshots.py` takes raw images and outputs 1600×900 images plus `alt-text.txt`. Copy it from the Offerlyst repo's `brand/` folder.
- **Text fields:**
- name (it must match the toml `name`)
- subtitle
- introduction
- details
- feature list
- 5 search terms, one idea each, mixing broad terms with niche terms where you can rank
- primary category and tags
- Never name competitors.
- **URLs:** privacy policy, website, support FAQ (optional), support email, emergency contact (on the account).
- **App testing information:**
- **Screencast URL**
- **Testing instructions:** numbered steps covering setup, each core feature, storefront and checkout checks, how to reach paid features (test charge), and uninstall.
- The **demo store URL**, and the **storefront password**. The user types the password themselves.
- "No separate login: uses Shopify authentication" if true.
- Save, then check that the listing shows no issues.
**Checklist 8:** icon · feature image · 3–6 screenshots with alt text · all text fields · search terms · URLs · emergency contact · testing instructions with demo store and password
---
## Phase 9: Record the screencast
1. Prepare the dev store with realistic data and at least one live item to show.
2. The user records the **entire screen** with their own tool (Snipping Tool, OBS, Loom). Claude drives Chrome through Claude in Chrome while the user records.
- Before recording, confirm the Chrome window is visible and the storefront domain is allowed for the extension.
- Do not type into fields Claude can't see. Verify each click with a screenshot or a JS read.
- Add on-screen English captions via an injected fixed-position div (brand colour, bottom centre, `pointer-events:none`). Place it so it doesn't cover the buttons being clicked.
- Hide cookie banners and newsletter pop-ups with JS. Never click Accept.
3. **Scene order** (about 2–4 minutes):
1. Home and onboarding
2. Theme editor app embed
3. Create and configure the core item
4. Publish or save
5. List view
6. Secondary features
7. Storefront page
8. Add to cart
9. Cart
10. Checkout showing the effect
11. Plans page
12. Closing tagline
4. The user trims the recording and uploads it to YouTube as **Unlisted**, with Audience set to "Not made for kids". Claude writes the title and description. Then Claude pastes the URL into `screencastUrl` and saves, then reloads the page to confirm it saved.
**Checklist 9:** recorded · trimmed · uploaded Unlisted · URL saved in listing
---
## Phase 10: App Store review page and submission
Go to Partner Dashboard › Distribution › **App Store review**.
1. **Preliminary steps** must all be green:
- queries supported API versions
- configuration requirements fixed
- emergency contact added
- listing created and checked for common issues
- protected data request complete
2. **Capabilities:** select what applies (e.g. embedded, online store). Each one adds checks:
- **Embedded app checks:** session tokens, App Bridge, no redirects out of the admin.
- **Online Store checks:** these run automatically every 2 hours. "Use theme app extensions" must pass. Tick "Confirm you have included detailed onboarding instructions" only if Home really has the setup checklist and deep link.
3. **AI self review:** run `/shopify-app-store-review` (Shopify AI Toolkit, topic `app-store-review`) against the codebase and fix everything it finds. Common catches:
- a manual shop-domain form (2.3.1)
- missing compliance webhooks
- unencrypted personal data
- billing outside the Shopify Billing API
4. **Before you submit:**
- [ ] the live server runs the latest commit (verify with `curl`, e.g. no shop-domain form on `/`)
- [ ] `shopify app deploy` was run for the latest extensions and config
- [ ] the testing instructions contain no placeholders (`ADD-...-HERE`)
- [ ] the screencast URL opens without signing in
- [ ] the demo store is reachable with the stated password
5. **The user** ticks "I've reviewed all the App Store Requirements" and clicks **Submit for review**. Claude clicks Submit only after an explicit yes in chat.
**Checklist 10:** all review items green · AI self review clean · pre-submit gate passed · submitted
---
## Phase 11: After submission
- Watch the Partner email. Reviewers reply with numbered requirement IDs. Fix each one, redeploy, verify, and reply in the review thread.
- First reviews take days to a few weeks, so plan launch marketing around approval, not submission.
- After approval:
- clean up the dev store test data
- turn on listing translations
- collect the first honest reviews (incentivised reviews break Shopify's rules)
- apply for Built for Shopify once the app qualifies
- Keep `api_version` current. Shopify drops old versions roughly every 12 months.
## Known pitfalls (from real runs)
| Symptom | Cause | Fix |
|---|---|---|
| Function over the instruction limit | JS parsing a big cart | Port to Rust; use counting sorts instead of comparison sorts in hot loops |
| `unknown import shopify_function_v2` | Raw cargo build | `shopify app function build` |
| Linker not found on Windows | No MSVC / Git Bash `link` | GNU toolchain; build from PowerShell |
| toml lost webhooks, proxy, name | `shopify app config link` | Back up first; restore |
| Deploy blocked: protected customer data | Order or customer webhooks | Phase 4 request (Level 1) |
| Docker build fails at `npm run build` | Dev deps pruned too early | Multi-stage Dockerfile; commit the lockfile |
| Port 80/443 busy on the VPS | Existing Nginx | Bind the app to 127.0.0.1:PORT and proxy from Nginx |
| Storefront page unstyled | Proxy page on a draft or other theme | Inline the app's CSS and JS in proxy responses |
| Reviewer flags 2.3.1 | Shop-domain login form on `/` | Remove the form; redeploy; verify live |
| Feature "doesn't work" in test | Test products out of stock or not in the collection | Use in-stock products; check the data before recording |
| Chrome tab "hidden" or screenshot timeouts | Window minimised or not visible | Bring the window forward or open a new tab group; read state with JS |

View File

@ -0,0 +1,52 @@
# Worked example: Offerlyst (October 2026)
Concrete values from the first run of this process. Use them as a pattern, not as defaults for other apps.
| Item | Value |
|---|---|
| Listing name | Offerlyst: Bundles & BOGO (handle `offerlyst`) |
| Repo | https://git.metatroncube.in/MetatroncubeSoftwareSolutions/bundle-offers-app.git (branch `main`) |
| Local path | D:\MCS_Repos\2026\claude_bundle_offer_shopify_app\bundle-offers-app |
| App domain | https://bundles.metatronlabz.com (VPS, existing Nginx → `127.0.0.1:3310`) |
| VPS path | /opt/bundle-offers-app |
| Redeploy | `cd /opt/bundle-offers-app && git pull && docker compose -f docker-compose.yml -f docker-compose.nginx.yml up -d --build db app` |
| Partner org / app | partners.shopify.com/2451848/apps/435426983937 |
| Listing editor | apps.shopify.com/services/partner-app-submissions/<client_id>/en |
| Review page | partners.shopify.com/2451848/apps/435426983937/distribution/app-store |
| Dev store | veloxautomotive.myshopify.com (password protected) |
| API version | 2026-10 |
| Scopes | read_discounts, read_orders, read_products, read_themes, write_app_proxy, write_discounts, write_files |
| Surfaces | Embedded admin, Rust discount Function (`cart.lines.discounts.generate.run`), theme app extension (embed + 4 blocks), app proxy `/apps/bundles` |
| Protected data | Level 1 (no name/email/phone); order IDs HMAC-hashed, order numbers AES-256-GCM |
| Plans | Free $0 · Starter $9.99/mo ($99/yr) · Growth $24.99/mo ($249/yr) · Plus $59.99/mo ($599/yr); 14-day trial |
| Screencast | https://youtu.be/wYUTfZjhEI4 (Unlisted) |
| Brand files | `brand/` in repo: icon 1200, feature 1600×900, screenshots/listing/1-6 + alt-text.txt, make_screenshots.py |
| Launch runbook (artifact) | https://claude.ai/artifact/JPNkWKhLPfm7Wcid4LHktQ |
## Screencast YouTube description template
```
A walkthrough of <App name>, a Shopify app for <one-line purpose>.
What this video shows:
• Home page and setup checklist
• Turning on the app embed in the theme editor
• <Create the core item>
• <Publish / list view / priorities>
• <Secondary feature>
• Storefront page and <primary storefront action>
• Cart and checkout with <the effect> applied automatically
• Plans, billed through Shopify
Recorded on a Shopify development store.
Privacy policy: https://<domain>/privacy
Terms: https://<domain>/terms
Support: <support email>
```
## Caption overlay used while recording (inject per page)
```js
window.olcap=function(t){let d=document.getElementById('olcap'); if(!d){d=document.createElement('div');d.id='olcap';Object.assign(d.style,{position:'fixed',left:'50%',bottom:'40px',transform:'translateX(-50%)',background:'rgba(4,91,89,0.96)',color:'#fff',font:'600 22px/1.35 system-ui,Segoe UI,sans-serif',padding:'14px 28px',borderRadius:'12px',zIndex:2147483647,maxWidth:'80vw',textAlign:'center',boxShadow:'0 6px 24px rgba(0,0,0,.25)',pointerEvents:'none'});document.body.appendChild(d);} d.textContent=t;};
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 171 KiB

After

Width:  |  Height:  |  Size: 195 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 103 KiB

After

Width:  |  Height:  |  Size: 102 KiB