110 lines
6.6 KiB
Markdown
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.
|