107 lines
10 KiB
Markdown
107 lines
10 KiB
Markdown
---
|
|
name: store-preflight
|
|
description: Run and read the storebound readiness checks before submitting a mobile app or game - `storebound scan` (offline rejection-risk scan of the project files, SDKs and listings with guideline, evidence and fix), `storebound check` (offline config, copy limits, files), `storebound check --aso`, `storebound validate` (read-only App Store Connect + Google Play report with ordered blockers) and `storebound privacy-manifest`. Use before every submission, when the user asks "is my app ready to submit", or after changing listings, builds, IAPs or SDKs.
|
|
---
|
|
|
|
# Store preflight
|
|
|
|
CLI: `storebound` (or the MCP tools `scan`, `check`, `check_aso`, `validate`, `privacy_manifest`). All are read-only on
|
|
the stores; run them freely.
|
|
|
|
## Order
|
|
0. `storebound scan`: reads the project itself (Xcode project, Info.plist, entitlements, privacy manifest, Podfile.lock /
|
|
Package.resolved, Gradle, AndroidManifest.xml, package.json / app.json / capacitor.config, pubspec, Unity and Godot
|
|
settings, Unity ProjectVersion.txt, CMake / ndk-build files, res/xml and strings.xml, and the merged manifest under
|
|
build/intermediates when the project was built locally) and the listing files. Prints the stack, the SDKs (version, file:line) and every rejection risk with
|
|
guideline, evidence, fix, severity (BLOCKER, HIGH, MEDIUM, low) and the skill to open; then the Data safety / App
|
|
Privacy / ATT / privacy manifest proposal, each item "detected (file:line)" or "ask owner", as a diff against the
|
|
config. Exit 1 on an open blocker. `--write` adds only the detected answers to the config (show the diff and ask
|
|
the owner first; MCP never writes). `--store apple|play`, `--json`. A finding the owner accepts goes into
|
|
`scan.ignore: [{ rule, reason, match?, evidence? }]` (`match` = text in the finding title, to accept one check of a rule with several; `evidence` = text in one evidence line, e.g. `src/main.ts:12`); never add one without the owner's reason. `scan` and `check` name an entry that matches no finding. The Play rules also read
|
|
`play.targetAges` (Families), `play.accountType` / `play.accountCreated` (closed-testing requirement) and
|
|
`play.billingPrograms` (payments): ask the owner for them, never guess.
|
|
1. `storebound check`: config, both listing files (limits are checked locally: title 30, subtitle 30, keywords 100
|
|
bytes, Play short 80, notes 500 ...), screenshot copy, Data safety answers, IAP texts (Apple description 45),
|
|
files the config points at, `.storebound/` gitignored, and the app profile: accounts need `accounts.deletionUrl`
|
|
(+ `inApp`), a sign-in for review needs the demo account in `.storebound/`, subscriptions need `app.termsUrl`.
|
|
Fix everything it lists; it exits 1 on problems.
|
|
2. `storebound check --aso`: keyword field use, repeats, stuffing (`aso-basics`). Errors exit 1, warnings are advice.
|
|
3. `storebound privacy-manifest --ios ios/App` (iOS): app manifest, required-reason APIs, SDKs without manifests
|
|
(`privacy-manifest` skill).
|
|
4. `storebound validate` (or `--apple` / `--play`): talks to both APIs read-only and prints findings in fix order,
|
|
plus the open scan findings (codes `scan-<rule>`; `--no-scan` skips). Exit 1 while there is a blocker. `--json`.
|
|
5. With in-app products or subscriptions: `storebound catalog diff` (read-only): both stores against the config,
|
|
prices per region, offers. Exit 1 on missing or mismatched items.
|
|
6. One list for the version you ship: `storebound release plan <version>` (MCP `release_plan`, read-only) puts the
|
|
check problems, the version's state on each store and the validate blockers in fix order, then names the owner's
|
|
next step (submit, promote, release). Report it as it is; the owner does the owner steps.
|
|
|
|
Many apps (a `storebound.workspace.json` above the app folders, `storebound ws init` writes it): `storebound ws check`
|
|
and `storebound ws validate [--apps a,b]` run the same checks over every app, a few at a time, each with its studio's
|
|
credential profile; `storebound ws run <command> --apps a,b` runs any other read command (writes only as dry runs).
|
|
|
|
## Share the report: `storebound report`
|
|
|
|
For the owner, a teammate or a client who should not need a terminal: `storebound report` runs `scan`, `check` and
|
|
`validate` (read-only; a store without credentials shows "Not checked" with the reason) and writes one self-contained
|
|
page, `.storebound/reports/readiness-<date>.html`, then opens it in the browser. A verdict per store, every finding
|
|
with its fix and console link, and the questions only the owner can answer. Secrets are masked. `--md` for Markdown,
|
|
`--json` for the data, `--no-open` in scripts. MCP: `report`; desktop: Checks > Report.
|
|
|
|
## Reading `scan`
|
|
| finding | fix | skill |
|
|
|---|---|---|
|
|
| 2.1(a) sign-in but no demo account | demo account in `.storebound/credentials.json`, `apple review-details` | `review-access` |
|
|
| 5.1.1(v) / Play account deletion | in-app delete + `accounts.inApp`, a web page in `accounts.deletionUrl` | `account-deletion` |
|
|
| 4.8 Google / Facebook login without Sign in with Apple | add Sign in with Apple (or an equivalent private login) | `review-rejections` |
|
|
| 3.1.1 no Restore Purchases / outside payment | a visible restore button; digital goods through IAP | `store-iap-setup` |
|
|
| 3.1.2(c) subscription info | `app.termsUrl`, Terms + renewal wording in the description, links in the app | `store-subscriptions` |
|
|
| 5.1.2(i) ATT | NSUserTrackingUsageDescription + the prompt before SDKs start, or no tracking | `ads-mediation-checks` |
|
|
| 5.1.1(ii) purpose strings | a specific sentence per used permission | `review-rejections` |
|
|
| privacy manifest (ITMS-91053 / 91061) | PrivacyInfo.xcprivacy with reasons; update old SDKs | `privacy-manifest` |
|
|
| 2.3.10 / 2.3.7 / 2.1(a) metadata | no other platforms, competitor names, prices or template text | `aso-basics` |
|
|
| export compliance | ask the owner | `export-compliance` |
|
|
| Play target SDK, foreground services, exact alarm, QUERY_ALL_PACKAGES, SMS / call log | manifest / Gradle changes + declarations | `play-first-release` |
|
|
| Play background location, photo / video, All files access, AccessibilityService, install packages, Health Connect, full-screen intent, VpnService | remove the permission (tools:node="remove" when an SDK adds it) or fill its App content declaration with a video | `store-declarations` |
|
|
| Play prominent disclosure / privacy policy in the app | a disclosure right before the prompt that names the data and its use; the policy linked inside the app | `store-declarations`, `privacy-policy` |
|
|
| Play Families / advertising ID | certified ad SDKs only, no AD_ID or location in child-only apps; AD_ID declared on targetSdk 33+ | `ads-mediation-checks`, `store-declarations` |
|
|
| Play 16 KB page sizes | newer Unity / React Native / NDK r28+ / AGP 8.5.1+, check prebuilt .so files | `play-first-release` |
|
|
| Play testing for new personal accounts | closed test, 12 testers for 14 days, then apply for production | `play-first-release` |
|
|
| Play metadata / impersonation | title 30, no emoji, caps, claims, keyword repetition, other brands | `aso-basics` |
|
|
| Play ads at launch / payments | interstitials only at natural breaks; digital goods through Play Billing or `play.billingPrograms` | `ads-mediation-checks`, `store-iap-setup` |
|
|
| privacy labels vs SDKs | `scan --write` after the owner agrees, then App Privacy / `play data-safety` | `store-declarations` |
|
|
|
|
## Reading `validate`
|
|
Each line: number, level (`BLOCKER`, `warn`, `ok`), store, message, and a `fix:` with the command or skill.
|
|
|
|
| finding | means | fix |
|
|
|---|---|---|
|
|
| no build attached / build PROCESSING | the version has no usable binary | wait for VALID, then `apple listing --version x --build N` (explicit number) |
|
|
| export compliance not answered | the build has no encryption answer | `export-compliance` skill |
|
|
| `<locale>`: missing description / keywords / subtitle | text not pushed for a locale | edit `store/appstore.md`, `apple listing` |
|
|
| no APP_IPHONE_67 screenshots | 6.9" set missing (required) | `apple screenshots`; iPad apps add the 13" type to `apple.screenshotTypes` |
|
|
| review contact missing | App Review information incomplete | `apple review-details` |
|
|
| age rating unanswered | new questions Apple added | `apple appinfo` |
|
|
| no app price schedule / availability | pricing never set | `apple appinfo`; if the API refuses the first availability record, set it once in App Store Connect > Pricing and Availability |
|
|
| IAP MISSING_METADATA / no review screenshot | product incomplete | `apple iap`, `apple iap-review` |
|
|
| privacy policy HTTP 404 / unreachable | URL broken | `privacy-policy` skill |
|
|
| subscription MISSING_METADATA / no review screenshot / no group localization | subscription incomplete | `apple subscriptions` (`store-subscriptions`) |
|
|
| Play subscription base plan DRAFT | not active | `play subscriptions` |
|
|
| accounts.deletionUrl not set / unreachable | Play needs a delete-account page | `account-deletion` skill |
|
|
| sign-in required but no demo account | App Review cannot get in (2.1) | `review-access` skill, `apple review-details` |
|
|
| no Terms of Use URL / description without a Terms link | subscriptions need the EULA link (3.1.2) | `store-subscriptions` skill |
|
|
| Play `<lang>`: phoneScreenshots 1/2 | graphics missing | `shots render`, `play images` |
|
|
| app-ads.txt lacks lines / 404 | ad networks cannot verify you | `ads-mediation-checks`; the file lives at the root of the developer website |
|
|
| no release on any track | nothing uploaded | `play release <aab>` |
|
|
| product purchase option DRAFT | not active | `play products` |
|
|
| user-perceived crash / ANR rate over 1.09 % / 0.47 % (live apps) | Play's bad behavior threshold is crossed | `store-health` skill: `storebound health`, fix the top issues, ship a higher versionCode |
|
|
| Apple metric rated poor / heavy diagnostic signature | hangs, launches, disk writes | `store-health` skill (Xcode Organizer for the stack) |
|
|
|
|
Vitals need the Play Developer Reporting API enabled for the service account; without it `validate` only notes
|
|
"vitals not readable". `--no-health` skips these checks.
|
|
|
|
## What validate cannot see (UI-only: check them yourself in the console with your browser tool)
|
|
App Privacy labels published, Play App content declarations (ads, target audience, content rating, advertising ID,
|
|
App access with the demo account), in-app account deletion working, first subscriptions added to the version,
|
|
agreements / tax / banking, countries for production on Play. (TestFlight groups and testers: `storebound apple
|
|
testflight status`.) Fix what you can; tell the owner only what is an owner step (agreements, tax, banking).
|