Last Week

Week 51 ended with two competing realities: iOS testing finally went live, but the very first step in the funnel (logging in) was brittle because email OTP deliverability is not something you can “design your way out of” with better copy. I also had too much iOS release work that required sitting down at a Mac and clicking through App Store Connect.

This week was about reducing those two sources of friction: automate iOS distribution so I can ship without ceremony, and give testers a login path that doesn’t depend on a brand new sending domain being trusted by Gmail.

Federated Login and CI Debugging From Linux

Two big things landed this week:

  1. The iOS CI/CD pipeline now builds, signs, uploads, and submits TestFlight builds automatically.
  2. Federated login is in: Google sign-in on Android, Sign in with Apple on iOS.

The surprising bonus was that improving my “build loop” wasn’t just about GitHub Actions. It was also about how I debug failures when I’m developing on Linux but the build that fails only exists inside a macOS runner.

What does it mean in English?

The app is now much easier to test and iterate on.

  • iOS releases are automated, which means fewer manual steps and fewer chances to break something during upload/signing.
  • New testers can sign in with a single tap instead of waiting for an email that might land in spam.
  • When CI fails, I can inspect what happened quickly without context-switching into a browser rabbit hole.

Nerdy Details

Why email OTP is a bad “first impression” in an alpha

Email OTP is attractive because it’s platform-agnostic: there’s no platform SDK to integrate, no per-platform compliance quirks, and no long-lived passwords to manage. The problem is that it assumes the delivery path is reliable.

In practice, inbox placement is probabilistic. A new sending domain starts with little or no reputation, and the “correct” email can still be routed to spam. In onboarding, that failure mode looks identical to “the app is broken” because the user’s next step depends on an email they may never see.

You can try to recover by teaching users to hunt through spam and mark the message as “not spam” to improve future placement, but that’s not a strategy for early testing where every drop-off matters and volume is too low to warm up a domain quickly.

Adding federated login (Google on Android, Apple on iOS)

Federated login reduces that failure mode. The user doesn’t have to switch apps, copy codes, or wait for email delivery. On a “good day” email OTP is fine; on a “bad day” it’s a hard stop. Federated login makes the bad day much rarer.

There’s a tradeoff I’ve been trying to avoid with Kotlin Multiplatform: the surface area becomes platform-specific. The shared layer can still own session state and backend token exchange, but each platform has its own native authentication mechanism to initiate the sign-in flow and return credentials.

There’s also a practical prerequisite: the device needs to already be signed into the platform identity provider (Google Play Services on Android, iCloud/Apple ID on iOS). For my initial testing focus (U.S.-based devices), that’s an acceptable assumption.

Apple’s gotcha: enabling Sign in with Apple can force signing changes

Google sign-in was mostly “wire it up” work plus linking it to the backend provider (in my case, Supabase makes this pretty straightforward).

Apple was the one with the sharp edge: enabling Sign in with Apple isn’t just an in-app change. It can require that the signing certificate used for distribution is granted the correct capability, and if your existing certificate wasn’t created/configured with that in mind, the feature simply won’t work.

That cascades into CI/CD because once the certificate changes, the pipeline needs to be updated to use the new signing assets when generating and uploading TestFlight builds. It’s an easy change once you know it’s required, but it’s the kind of requirement that punishes you for discovering it late.

Debugging CI failures without a local macOS environment

I’m developing on Linux, but iOS builds (and some iOS-specific verification) can only run on macOS. When a build fails, the root cause often lives in the macOS job logs, not in my local environment.

One workflow upgrade this week wasn’t a code change at all: I started leaning on tooling that can watch GitHub Actions runs, pull logs, and surface the failure reason quickly. That turns “something failed on CI” into “here’s the specific error message” without the slow path of clicking around the Actions UI and manually hunting down the failing step.

The end result is a tighter feedback loop: I can keep my primary dev setup on Linux while still iterating on the macOS-only pieces with less friction.

Better docs, less context pollution (Context7)

Another tooling rabbit hole I went down: getting reliable, up-to-date library docs into a coding assistant.

Scraping a random web page into context is noisy (HTML/CSS scaffolding and navigation junk) and sometimes blocked outright. A docs-focused API approach is cleaner: fetch structured documentation snippets, inject only the relevant bits, and avoid bloating the session with irrelevant markup.

Context7 is one example of that approach. The pitch is simple: when the assistant needs framework-specific syntax or best practices, it can retrieve the relevant docs as-needed instead of “guessing” or stuffing a whole website into context. The practical benefit is fewer hallucinated APIs and less time wasted fighting stale or fabricated examples.

Next Week

Next week is more polishing around the new auth choices and more reliability work:

  • Add an in-app reminder on iOS asking users not to hide their email when signing in with Apple, so account ownership stays supportable.
  • Start implementing SMS notifications for waitlist events to bypass email deliverability issues entirely (with the acknowledgment that SMS costs in the U.S. add up fast).