Deployment & CI
How the app is built and signed on CI, and how Stripe billing is wired.
This page covers how the mobile app is built and released, and how the Stripe billing that powers Premium is configured.
iOS builds on GitHub Actions
The app repo ships a GitHub Actions workflow that produces a signed, installable iOS
.ipa. It triggers on a push to main/master or on a pull request.
The workflow has two paths:
- Signed — when the signing secrets are present, it imports the certificate and
provisioning profile into a temporary runner keychain and compiles with
flutter build ipa --release. - Unsigned fallback — when they're missing, it builds with
flutter build ios --no-codesignso CI still produces an artifact.
Required secrets
| Secret | Purpose |
|---|---|
BUILD_CERTIFICATE_BASE64 | Apple distribution/development certificate (Base64). |
P12_PASSWORD | The .p12 certificate export password. |
BUILD_PROVISION_PROFILE_BASE64 | Provisioning profile (Base64). |
KEYCHAIN_PASSWORD | A temporary keychain passphrase for the runner. |
Export the certificate from Keychain Access as .p12, download the provisioning
profile from the Apple Developer portal, Base64-encode both, and add them as repository
secrets.
Stripe billing
Premium billing is Stripe. A single product — MacroMath Premium — has two recurring prices: €4.99 / month and €34.99 / year. Two Supabase Edge Functions drive the flow:
| Function | Notes |
|---|---|
stripe-checkout | Creates the Checkout session; authenticated with the Supabase JWT. |
stripe-webhook | Receives Stripe events; deployed --no-verify-jwt since Stripe calls it directly. |
Webhook events
The webhook keeps the subscription in sync by handling four events:
checkout.session.completedcustomer.subscription.createdcustomer.subscription.updatedcustomer.subscription.deleted
Each updates the user's Stripe columns in Supabase (migration 012_stripe_columns), so
the app and the
website both reflect the current plan.
Required secrets
| Variable | Purpose |
|---|---|
STRIPE_SECRET_KEY | The Stripe secret key — only in Edge Functions, never in the app. |
STRIPE_PRICE_MONTHLY / STRIPE_PRICE_ANNUAL | The price IDs for each plan. |
STRIPE_WEBHOOK_SECRET | Signing secret for the webhook endpoint. |
TRIAL_DAYS, CHECKOUT_SUCCESS_URL, CHECKOUT_CANCEL_URL | Optional checkout tuning. |
Keep the Stripe secret key, Gemini key and SMTP credentials in Edge Function secrets — never bundled in the app. Migrating any remaining hardcoded keys to environment variables is a release prerequisite. See Security.
Website & docs hosting
The marketing site (Astro) and this documentation
(Next.js/Fumadocs) are both deployable to any static/edge host — Vercel, Netlify or
Cloudflare Pages — with the website's api/ billing functions running as serverless
functions.