storebound/docs/research/fastlane-revenuecat.md

110 lines
6.6 KiB
Markdown

# R&D: a fastlane importer and a RevenueCat adapter
Two questions for after desktop D3. Facts come from the official docs linked in each section; the
recommendations are ours.
## 1. `storebound import fastlane`
**What fastlane keeps on disk**
- **deliver (App Store)**, under `fastlane/metadata/`
([docs.fastlane.tools/actions/deliver](https://docs.fastlane.tools/actions/deliver/)):
- One folder per language: `name.txt`, `subtitle.txt`, `description.txt`, `keywords.txt`, `promotional_text.txt`,
`release_notes.txt`, `support_url.txt`, `marketing_url.txt`, `privacy_url.txt`.
- Non-localized files at the root: `copyright.txt`, `primary_category.txt`, `secondary_category.txt` and the
sub-category files.
- `review_information/`: `first_name.txt`, `last_name.txt`, `phone_number.txt`, `email_address.txt`,
`demo_user.txt`, `demo_password.txt`, `notes.txt`.
- A `default/` folder that fills any language without its own files.
- Screenshots and app previews in one folder per language. The device comes from the image size or the file name.
- **supply (Google Play)**, under `fastlane/metadata/android/<locale>/`
([docs.fastlane.tools/actions/supply](https://docs.fastlane.tools/actions/supply/)):
- `title.txt`, `short_description.txt`, `full_description.txt`, `video.txt`.
- `changelogs/<versionCode>.txt` and `changelogs/default.txt`.
- `images/`: `icon`, `featureGraphic`, `promoGraphic`, `tvBanner`, plus `phoneScreenshots/`, `sevenInchScreenshots/`
and `tenInchScreenshots/`.
- **Appfile / Deliverfile / Fastfile** are Ruby:
- `app_identifier`, `apple_id`, `team_id` / `itc_team_id`, `json_key_file`, `package_name`.
- Deliverfile options such as `languages`, `submit_for_review`, `automatic_release`, `phased_release`,
`price_tier`, `app_rating_config_path`.
**What an importer would do.** It would only read, it would never run Ruby, and it would write with `--dry` first.
1. **Store ids.** Parse the simple `key("value")` / `key "value"` lines of `Appfile` and `Deliverfile` with a strict
regex. That gives `apple.bundleId`, `play.packageName` and the languages. Ruby logic (conditionals, `ENV[...]`,
lanes) is reported as "set it in storebound.config.ts", never guessed.
2. **Languages.** Join the deliver locales and the supply locales into storebound `languages[]` (`apple`, `play` codes).
3. **Listing text.**
- Write `store/appstore.md` and `store/listing.md` from the `.txt` files, mapping `default/` into every language
that lacks a file.
- The newest `changelogs/<versionCode>.txt` becomes `whatsNew`.
- Check lengths against the store limits (`storebound check`).
4. **Art.** Copy or link the screenshot folders into the renders layout (per language and size), or list them as
`shots.frames` when they look like raw captures. The supply icon and feature graphic go to the configured paths.
5. **Secrets and personal data.**
- `json_key_file` and `review_information/*` (contact, demo user and password) go to
`.storebound/credentials.json`, which is gitignored, and never to the config (AGENTS.md rules 4 and 9).
- The importer prints that it moved them, masked.
6. **Not imported, with a note:**
- Submission and release flags (`submit_for_review`, `automatic_release`). storebound never submits.
- `price_tier`. Prices live in the products / CSV flow.
- The age rating config (answered with the owner in `store-declarations`).
- Fastfile lanes.
**Worth it? Yes.** fastlane is the most common existing setup, and its metadata folder maps almost one to one onto
storebound's listing files. A read-only importer gives a migration path that keeps the store text, the screenshots
and the credentials layout in a few seconds, and a dry run shows exactly what lands where.
**Effort:** about 2 to 3 days with tests on fixture folders: an Appfile / Deliverfile line parser, the two metadata
walkers, a dry-run report, and the `.storebound/` hand-off. Ship it as `storebound import fastlane [--dir fastlane]
[--dry]`, then as an "Import from fastlane" choice in the desktop first-run guide.
## 2. A RevenueCat adapter
**What the API offers.** RevenueCat REST API v2 lives at `https://api.revenuecat.com/v2`. It uses Bearer v2 secret
keys with per-endpoint permissions, set in the project settings ([revenuecat.com/docs/api-v2](https://www.revenuecat.com/docs/api-v2)).
It covers:
- Apps.
- Products: `/projects/{project_id}/products`.
- Entitlements, with `.../entitlements/{entitlement_id}/actions/attach_products`.
- Offerings and Packages.
So the RevenueCat catalog can be created and kept in sync by API.
**What storebound already replaces.** The store-side catalog: one product and subscription list in the config,
created and priced on both stores (`play products / subscriptions`, `apple iap / subscriptions`, the regional price
CSV), with cross-store parity (`catalog diff`). Teams that use RevenueCat only as a way to "set up the products"
don't need it for that.
**What storebound cannot replace.**
- Runtime receipt and purchase-token validation.
- Entitlement state per user, server notifications (App Store Server Notifications, Play RTDN).
- Renewals, grace periods, refunds, customer history, paywall experiments and charts.
- The client SDKs.
All of that runs on a server, against live users. It is outside a release tool, and storebound should not try.
**What an optional adapter could do:** `storebound revenuecat sync [--dry]`.
- Key: `REVENUECAT_API_KEY` (v2 secret) and project id, from the environment or `.storebound/` only.
- Source of truth: the storebound catalog. For every config product or subscription id and each store:
1. Create the RevenueCat product (store identifier, app id, type).
2. Create the entitlements named in a new optional config field (`products[].entitlements: ['pro']`) and attach
the products.
3. Optionally create one default offering whose packages map to the subscriptions (`$rc_monthly` / `$rc_annual`
by period).
- Idempotent: match by store identifier. A dry-run diff comes first, as with every storebound write. Nothing is
deleted.
- Read-only parity: show "missing in RevenueCat" in `catalog diff` and in the desktop Catalog tab.
**Recommendation.** Build the fastlane importer first: it is the migration path and the bigger win.
Make RevenueCat a small, optional adapter later, scoped to catalog sync (products, entitlements, a default offering)
plus parity in `catalog diff`. Market it as "keep RevenueCat in step with the stores", not as a replacement:
- storebound owns the store-side catalog and the release.
- RevenueCat (or the app's own server) owns runtime entitlements.
Do not add webhooks, customers or any runtime data, so storebound stays a local tool with no server and no user data.