6.6 KiB
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):- 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.txtand 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.
- One folder per language:
- supply (Google Play), under
fastlane/metadata/android/<locale>/(docs.fastlane.tools/actions/supply):title.txt,short_description.txt,full_description.txt,video.txt.changelogs/<versionCode>.txtandchangelogs/default.txt.images/:icon,featureGraphic,promoGraphic,tvBanner, plusphoneScreenshots/,sevenInchScreenshots/andtenInchScreenshots/.
- 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.
- Store ids. Parse the simple
key("value")/key "value"lines ofAppfileandDeliverfilewith a strict regex. That givesapple.bundleId,play.packageNameand the languages. Ruby logic (conditionals,ENV[...], lanes) is reported as "set it in storebound.config.ts", never guessed. - Languages. Join the deliver locales and the supply locales into storebound
languages[](apple,playcodes). - Listing text.
- Write
store/appstore.mdandstore/listing.mdfrom the.txtfiles, mappingdefault/into every language that lacks a file. - The newest
changelogs/<versionCode>.txtbecomeswhatsNew. - Check lengths against the store limits (
storebound check).
- Write
- Art. Copy or link the screenshot folders into the renders layout (per language and size), or list them as
shots.frameswhen they look like raw captures. The supply icon and feature graphic go to the configured paths. - Secrets and personal data.
json_key_fileandreview_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.
- 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.
- Submission and release flags (
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).
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:
- Create the RevenueCat product (store identifier, app id, type).
- Create the entitlements named in a new optional config field (
products[].entitlements: ['pro']) and attach the products. - Optionally create one default offering whose packages map to the subscriptions (
$rc_monthly/$rc_annualby 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 diffand 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.