Merge remote-tracking branch 'origin/main' into play-app-record
# Conflicts: # CHANGELOG.md
This commit is contained in:
commit
704231457f
45 changed files with 1236 additions and 175 deletions
84
skills/store-pitfalls/SKILL.md
Normal file
84
skills/store-pitfalls/SKILL.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
---
|
||||
name: store-pitfalls
|
||||
description: Known pitfalls with App Store Connect, Google Play and storebound itself, learned from real releases, and what to do about each - store lists that lag right after a create, dry runs that print a count instead of a plan, App Store names taken on a storefront, keyword limits in bytes, Data safety answers without code evidence, missing font glyphs in screenshots, console sign-in and sessions, Capacitor monorepo plugins, Play's Create app form (no API, opener and submit share a name, Free is final). Read it before any store task, and when a store command does something you did not expect.
|
||||
---
|
||||
|
||||
# Store pitfalls
|
||||
|
||||
Each entry: **symptom** → cause → what to do → what guards it now. The full changelog of lessons with dates is
|
||||
`docs/pitfalls.md` in the storebound repository. When you hit a new one, tell the owner and add it there (and here).
|
||||
|
||||
## 1. A product you just created is "not there"
|
||||
- **Symptom:** `apple iap-review` uploads nothing for a product `apple iap` created a minute ago; a list looks short.
|
||||
- **Cause:** App Store Connect's `/inAppPurchasesV2` list (and Play's product list) can lag for a short while after a
|
||||
create. A command that walks the list skips what is not in it yet.
|
||||
- **Do:** wait a minute and re-run. Never assume a product was handled because the command finished.
|
||||
- **Guard:** `apple iap-review` compares the config's products with the store's list, names the missing ones
|
||||
("the store's list can lag a minute after creating; re-run") and exits 1. `apple iap` and `play products` read the
|
||||
list again after creating and warn about any new product that is not in it yet; their dry runs name products that
|
||||
are not on the store.
|
||||
|
||||
## 2. A dry run that only prints a count
|
||||
- **Symptom:** `--dry` says "listing: 20 locales" or "3 change(s)", but not which fields would change to what.
|
||||
- **Cause:** the command logged a summary instead of the plan.
|
||||
- **Do:** never ask the owner to approve a count. Show the rows that change (item, action, old → new). If a command
|
||||
only prints a count, say so and show the owner the diff from `pull` / `--json` output instead.
|
||||
- **Guard:** `cli/lib/dry.ts` `dryPlan(title, rows)` prints the standard plan table (`apple iap`, `apple iap-review`,
|
||||
`play products` use it); `tests/pitfalls.test.ts` scans `cli/**` for `--dry` branches that print nothing but a count.
|
||||
|
||||
## 3. "The app name you entered is already being used"
|
||||
- **Symptom:** creating the App Store record or saving the name fails although you own no app with that name.
|
||||
- **Cause:** App Store app names are unique per storefront, across all developers.
|
||||
- **Do:** ask the owner for a variant (a short suffix such as "Example Notes: Lists") and set `apple.name` in the config;
|
||||
keep `app.name` for Play and the brand. Do not pick the suffix yourself.
|
||||
- **Guard:** `apple.name` overrides the App Store name.
|
||||
|
||||
## 4. Keyword field "too long" at fewer than 100 characters
|
||||
- **Symptom:** App Store Connect rejects keywords that look short enough, mostly in Turkish, German, CJK.
|
||||
- **Cause:** the 100 limit counts UTF-8 bytes, not characters ("ş" is 2 bytes, a CJK character 3).
|
||||
- **Do:** shorten by bytes; drop words, not commas.
|
||||
- **Guard:** `storebound check` counts bytes for keywords.
|
||||
|
||||
## 5. Data safety says "email collected" for an app that never asks for one
|
||||
- **Symptom:** the proposal marks email (or phone) as collected because the app has accounts.
|
||||
- **Cause:** account features do not imply email collection (anonymous ids, Game Center, Play Games sign-in).
|
||||
- **Do:** answer only what the code proves; ask the owner for the rest (rule 5).
|
||||
- **Guard:** `storebound scan` marks email only with evidence (an email field, an email sign-up call) and otherwise
|
||||
says "ask owner".
|
||||
|
||||
## 6. Boxes or wrong glyphs in localized screenshots
|
||||
- **Symptom:** Turkish, Polish or Vietnamese captions show fallback glyphs (ş, ğ, ł, ệ) while the English ones are fine.
|
||||
- **Cause:** the font (or the Google Fonts subset that was downloaded) does not cover those characters, and the
|
||||
browser silently draws them with another font.
|
||||
- **Do:** check every language's characters before rendering, pick a font that covers them or let the fallback fill in.
|
||||
- **Guard:** `storebound shots fonts` / `shots check` check each language's characters against the fonts' glyphs.
|
||||
|
||||
## 7. Console automation stops at sign-in or loses the session
|
||||
- **Symptom:** `console fill` waits on a sign-in page, cannot find fields, or is signed out on the next run.
|
||||
- **Cause:** the App Store Connect sign-in runs inside an `idmsa.apple.com` iframe; "User Access" is a plain heading,
|
||||
not a labeled group; Chrome drops session cookies unless the last session is restored.
|
||||
- **Do:** let the owner sign in in the opened window (never type credentials); re-run after the sign-in.
|
||||
- **Guard:** the console session handles the iframe and the plain heading and starts Chrome with
|
||||
`--restore-last-session`; a partial miss fills every field found and leaves only the missing ones to the owner.
|
||||
|
||||
## 8. `scan` misses Capacitor plugins in a monorepo
|
||||
- **Symptom:** SDKs or privacy manifests of Capacitor plugins are not found.
|
||||
- **Cause:** the plugins live in `apps/native/node_modules` (a workspace package), not in the root `node_modules`.
|
||||
- **Do:** run `scan` from the project root; check that the stack line lists the plugins.
|
||||
- **Guard:** `storebound scan` and `privacy-manifest` resolve packages through workspace folders too.
|
||||
|
||||
## 9. A new Play app: "Create app" is both the opener and the submit
|
||||
- **Symptom:** an agent cannot create the Play app through the API, or clicks "Create app" without knowing whether it
|
||||
opens the form or submits it; or an app goes out as Free and the owner later wants it paid.
|
||||
- **Cause:** the Play Developer API cannot create apps. Play Console's Home has a "Create app" button that opens the
|
||||
form, and the form's final button has the same words. Free cannot become Paid later on Google Play. The package
|
||||
name is not in this form: the first AAB upload sets it.
|
||||
- **Do:** `storebound console fill play-app-record` (pick the account with `play.developerId` or
|
||||
`play.developerAccount`); tell the owner that Free is final; the owner ticks the declarations and presses Create
|
||||
app; then `storebound play upload --track internal` (or `flow run release`) sets the package name.
|
||||
- **Guard:** `createAppAllowed` lets the opener through only on the app list, never inside a form or dialog (English
|
||||
and Turkish); agreement checkboxes are never ticked; Free or paid is outlined as an owner check.
|
||||
|
||||
## Adding a lesson
|
||||
Every bug found in real use gets an entry in `docs/pitfalls.md` and here, and, where possible, a check or a test
|
||||
that fails without the fix (see CONTRIBUTING.md).
|
||||
Loading…
Add table
Add a link
Reference in a new issue