Skip to content

iPhone M1: the road to TestFlight and the App Store - #12

Closed
frahlg wants to merge 7 commits into
claude/ios-m1-foundationfrom
claude/ios-m1-release
Closed

frahlg wants to merge 7 commits into
claude/ios-m1-foundationfrom
claude/ios-m1-release

Conversation

@frahlg

@frahlg frahlg commented Oct 12, 2026 •

Copy link
Copy Markdown
Member

The path from a tag to TestFlight and the App Store for the iPhone app, and the steps a person takes in App Store Connect. Paired with srcfl/ftw-web#18, which adds the privacy and support pages the store texts point to. Base: #8.

What is here

File What it does
.github/workflows/ios-release.yml A tag ios-v1.2.3 (or ios-v1.2.3-1, -2 …: text after a dash only tells tags apart) or a manual run: swift test, archive with Xcode 27.0 on GitHub's xcode-27 image, sign with team L66M368PZ6 through an App Store Connect API key, upload. If Xcode's upload fails, it exports the .ipa and sends it with xcrun altool --upload-package. Version from the tag; build number from the run (.2 on a re-run). Sets FTW_SOURCE_REVISION=$GITHUB_SHA. Checks that the app and the widget carry the same version.
appleApp/ExportOptions.plist method: app-store-connect, destination: upload, automatic signing, version left alone.
appleApp/RELEASING.md The manual steps in order, with menu paths checked against Apple's pages today. First your own iPhone from Xcode (Developer Mode, xcodebuild, devicectl), then internal TestFlight (no Beta App Review), then external TestFlight and the App Store.
appleApp/store/ Name, subtitle, promotional text, description, keywords, release notes and URLs in en-US and sv-SE; App Review notes for the demo; check.sh holds each text to Apple's limits.
appleApp/scripts/store-screenshots.sh 6.9" pictures (1320 × 2868) of the demo in Swedish and English, in a simulator it makes and deletes.

No app code, FTW-Info.plist, FTW.xcconfig, project.pbxproj or apple.yml changes.

Proven

  • The release workflow ran as a dry run on this PR, without secrets: run 38278193268 and, after the environment change, run 38279607586. Image xcode-27-arm64 20261006.0244.1, Xcode 27.0 (27A266a), 95 tests green, unsigned Release archive, 0.1.0 (1) and iphoneos27.0 in both FTW.app and FTWWidgets.appex, then "Upload skipped".
  • store/check.sh passes for both languages.
  • store-screenshots.sh produced six 1320 × 2868 pictures locally.

Not proven: a signed upload. That needs the key, which only someone in the team can make.

Differences from the brief

  • The API key must be Admin, not App Manager. The runner has no certificate, so the export signs with a cloud-managed distribution certificate. Apple's roles table gives those to Account Holder and Admin; other roles need a per-user permission that team keys cannot carry. The secrets can be plain repository secrets (ASC_KEY_P8 is the .p8 PEM text, not base64). Because an Admin key can do much more, the job also reads them from an app-store environment, which RELEASING.md suggests limiting to main and ios-v* tags. Pull requests run without it.
  • The workflow also runs on pull requests that touch it or ExportOptions.plist. Those runs are always dry runs, so a change to the release path is tested before it ships.
  • App Review notes are one file (store/review-notes.txt), since App Store Connect has one Notes field for every language.
  • No pairing picture. In the simulator, Pair shows "Choose a picture of the QR", which a phone does not have.

For Fredrik to decide or do

  • ftw.energy has no address record, and the Pages project serves only ftw.sourceful.energy. Add the custom domain (RELEASING.md step 1), or the privacy and support URLs fail review.
  • app.ftw.energy/.well-known/apple-app-site-association answers 404 (Publish the apple-app-site-association file for the iPhone app ftw-webapp#77).
  • Contact for EU trader status, support and privacy: the pages use support@sourceful.energy from sourceful.energy/contact. No phone number is published, and Apple wants one for the support URL and DSA.
  • Name: no live app is called exactly "FTW" in the Swedish or US store; App Store Connect gives the final answer. Fallbacks are in RELEASING.md.
  • China is left out (needs an ICP filing). France waits (Fredrik, 12 Oct): the first release leaves it out until the ANSSI encryption declaration is filed; RELEASING.md has the step. Counsel: the Texas, Utah and Louisiana age laws.
  • App Privacy: "Data Not Collected" holds exactly once the relay's Caddy error log drops addresses (ftw-webapp); otherwise declare Other Diagnostic Data.

Waiting on other branches

🤖 Generated with Claude Code

A tag ios-v1.2.3, or a manual run, archives the app with Xcode 27 on
GitHub's xcode-27 image, signs it with Sourceful's team through an App
Store Connect API key and uploads it with method app-store-connect and
destination upload. The version comes from the tag, the build number
from the run. Without the ASC_* secrets, and on every pull request, it
archives unsigned and says the upload was skipped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
frahlg and others added 6 commits October 12, 2026 18:45
The upload needs an Admin API key, because only Account Holder and Admin
may use cloud-managed distribution certificates. A repository secret
would let any branch's workflow read it, so the job takes its secrets
from the app-store environment, which only main and ios-v* tags may
use. Pull requests run without the environment.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RELEASING.md lists, in order, what someone in team L66M368PZ6 does in
App Store Connect and on GitHub before the first upload: app record and
name, EU trader status, App Privacy, export, age rating, price, countries,
the API key, TestFlight and the review. store/ holds the product page in
English and Swedish, the App Review notes for the demo, and check.sh,
which holds each text to Apple's limits. scripts/store-screenshots.sh
takes the 6.9" pictures from the demo in its own simulator.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In the simulator it shows a button a phone does not have. Wait 12 s
so the charging picture shows the car charging, not starting.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RELEASING.md now starts with installing from Xcode on a connected iPhone
(Developer Mode, an Apple Account in Xcode, xcodebuild and devicectl),
then internal TestFlight, which needs no Beta App Review: the agreement,
the app record, an Admin key in plain repository secrets, a tag, and a
tester group. External TestFlight and the App Store follow.

The workflow accepts tags like ios-v0.1.0-1: text after a dash only
tells tags apart. If Xcode's upload fails, it exports the .ipa and sends
it with `altool --upload-package`, which Apple's "Upload builds" help
still lists.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
#13 sets ITSAppUsesNonExemptEncryption to NO and adds privacy manifests
with no collected data. RELEASING.md now gives the matching App Store
Connect answers ("None of the algorithms mentioned above", "Data Not
Collected"), #13's reading of US and French encryption rules, and the
choice about the relay's error log. The App Review notes say where the
privacy link is and that there is no account to delete.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fredrik decided that France waits until the ANSSI encryption
declaration is filed. RELEASING.md now removes France under Pricing and
Availability, keeps China out for want of an ICP filing, and adds a
step for the declaration, with ANSSI's forms page, before France is
added back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@frahlg

frahlg commented Oct 12, 2026

Copy link
Copy Markdown
Member Author

Included in #14, which lands the whole iPhone M1 app as one PR. The branch stays.

@frahlg frahlg closed this Oct 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant