storebound/skills/migrate-from-fastlane/SKILL.md

61 lines
5.2 KiB
Markdown

---
name: migrate-from-fastlane
description: Move a mobile app or game from fastlane (deliver, supply, snapshot / screengrab, Appfile, Deliverfile) to storebound with `storebound import fastlane` - store ids, App Store and Google Play listing text in every language, categories, review notes, Play icon and feature graphic, screenshots as frames - without copying keys, team ids or the App Review demo account. Use when a project has a fastlane/ (or ios/fastlane, android/fastlane) folder, when the user says "we use fastlane", "migrate from fastlane", or before running `storebound init` in such a project.
---
# Migrate from fastlane
CLI: `storebound import fastlane [--dir fastlane] [--out .] [--profile app|game|subscription-app] [--dry]` (MCP:
`import_fastlane`, `dry_run` defaults to true). It only reads fastlane's files and never runs Ruby. Default `--dir`:
every one of `fastlane/`, `ios/fastlane/`, `android/fastlane/` that exists; pass several with commas.
## Steps
1. `storebound import fastlane --dry`. Show the owner the plan and the report. The report has five parts:
**mapped** (source -> target), **not mapped** (with where each item goes by hand), **keys, accounts and personal
data** (named only), **placeholders** and **warnings** (missing fields, store limits, unknown locale codes).
2. With the owner's yes, run it without `--dry`. Nothing that exists is overwritten:
- a text file that exists gets a `<name>.imported.<ext>` copy next to it. Compare with
`git diff --no-index store/listing.md store/listing.imported.md` and merge what the owner wants;
- an image that exists is kept.
3. `storebound init --profile <same profile>`: it adds the remaining templates (declarations, App Privacy, Data
safety CSV, privacy policy, `.storebound/credentials.json`) and keeps the imported files.
4. Secrets, done by the owner (never in chat, never in the config; AGENTS.md rules 4 and 9):
- Play `json_key_file`: move the key into `.storebound/`, set `PLAY_SERVICE_ACCOUNT` to its path. If the key was
ever committed, rotate it in Google Cloud.
- `app_store_connect_api_key` in the Fastfile: `ASC_KEY_ID`, `ASC_ISSUER_ID`, `ASC_P8` (the .p8 path).
- `review_information/` contact and demo account: `reviewContact` and `reviewDemoAccount` in
`.storebound/credentials.json`. The import sets `reviewAccess.signInRequired: true` when fastlane had a demo user.
5. Replace the placeholders the report lists (`app.contactEmail` always: the App Review contact is personal data and
is not used for it).
6. `storebound check`, then `storebound shots capture --source folder` to check the imported frames.
## What maps where
| fastlane | storebound |
|---|---|
| Appfile `app_identifier` / `package_name` | `apple.bundleId` / `play.packageName` |
| deliver locale folders + supply language folders | `languages[]`, one entry per language with both codes (`tr` + `tr-TR`, `zh-Hans` + `zh-CN`, `he` + `iw-IL`, `es-MX` + `es-419`) |
| `metadata/<locale>/name, subtitle, promotional_text, keywords, description, release_notes` (+ `default/`) | `store/appstore.md` (`name`, `subtitle`, `promotionalText`, `keywords` without spaces after commas, `description`, `whatsNew`) |
| `privacy_url`, `support_url`, `marketing_url` | `app.privacyPolicyUrl`, `app.supportUrl`, `app.marketingUrl` + `app.website` (one for all languages) |
| `copyright.txt`, `primary_category.txt` ... | `app.copyright`, `apple.info.categories` (`GAMES` picks the game profile) |
| `review_information/notes.txt` | `apple.info.reviewNotes` |
| `metadata/android/<lang>/title, short_description, full_description` | `store/listing.md` |
| newest `changelogs/<versionCode>.txt` (else `default.txt`) | Play "What's new" |
| `video.txt` (YouTube) | `play.video` |
| `images/icon.png`, `images/featureGraphic.*` | `store/icons/play-512.png` (`play.icon`), `store/renders/<lang>/feature/1024x500.*` |
| `screenshots/<locale>/` (largest iPhone set, iPad), else `phoneScreenshots/`, `tenInchScreenshots/` | `store/shots/frames/<lang>/<phone\|tablet>/NN.png`, scenes `shot-01`..., `shots.capture.source: 'folder'`, empty copy in `store/shots/copy.json` |
## Not imported (on purpose)
- `submit_for_review`, `automatic_release`, `reject_if_possible`: the owner submits and releases (AGENTS.md rule 1);
phased release is `release-management`.
- `price_tier`: products and the prices CSV (`store-iap-setup`). Age rating config: `store-declarations`.
Export compliance: `export-compliance` (`apple.usesNonExemptEncryption` stays commented out).
- Lanes, `match`, `gym` / `gradle`: building and signing stay where they are; storebound has no lanes.
- Ruby logic (`for_platform`, `for_lane`, `ENV[...]`, interpolation): reported by key and line; set those in storebound.config.ts.
- Promo graphic, TV banner, TV / Wear screenshots, Apple TV privacy policy, Korean trade representative contact:
consoles.
## Screenshots
fastlane screenshots are often finished store art (framed, captioned). The import puts them in the frames folder so
`shots render` can rebuild them from one source in every size; full-screen captures usually need the status bar cut
(`shots capture --source folder` reports the aspect ratio per frame). If the owner prefers to keep the finished art,
leave the copy empty and upload as before. JPEG screenshots are listed, not copied (frames are PNG).