Skip to content

Add App Store & Play Store packaging (Capacitor) + Install landing page + Fastlane#1

Merged
Joun-Mikhail merged 9 commits into
mainfrom
feature/app-store-packaging
Jun 24, 2026
Merged

Add App Store & Play Store packaging (Capacitor) + Install landing page + Fastlane#1
Joun-Mikhail merged 9 commits into
mainfrom
feature/app-store-packaging

Conversation

@Joun-Mikhail

Copy link
Copy Markdown
Owner

Summary

Make CareerFlow shippable to the App Store and Google Play, and give end
users one trusted install link that picks the right path for their device.

The web app and PWA are unchanged. The mobile apps wrap the same SPA
in a Capacitor WebView with the same auth flow — signup/login work
the standard way on every platform.

What this PR adds

Area Files
Capacitor wrapper frontend/capacitor.config.json, frontend/src/lib/capacitor-auth.ts, frontend/public/native-assets/, cap:* npm scripts
Install landing page landing/index.html (canonical), auto-mirrored to public/install/ by the new prebuild script; Vercel rewrite added
Fastlane fastlane/ios/{Fastfile,Appfile,Gemfile}, fastlane/android/{Fastfile,Appfile,Gemfile}, fastlane/metadata/{ios,android}/en-US/
CI .github/workflows/mobile-build.yml — builds web bundle, AAB, IPA/xcarchive
Build scripts scripts/build-mobile.sh, scripts/generate-screenshots.sh
Store metadata store-meta/appstore/, store-meta/playstore/
Docs docs/privacy-policy.md, docs/app-store-submission.md
Backend Default CORS_ORIGINS extended to cover Capacitor WebView origins (https://localhost, capacitor://localhost, ionic://localhost)
README App Store / Play / Install-PWA badges + mobile-build CI badge

Commits

  1. feat(mobile) Capacitor wrapper config and helpers
  2. feat(landing) trusted Install page at /install
  3. feat(release) Fastlane lanes and store metadata templates
  4. ci(mobile) mobile-build workflow + local build scripts
  5. docs privacy policy and App Store submission guide
  6. feat(backend) allow Capacitor WebView origins by default; README install badges

Acceptance checklist

  • npm run build exits 0 — dist/ produced, dist/install/index.html (8.3 KB) included.
  • Same auth flow on every platform — no demo-only mobile shortcut. The existing web "Try demo" button uses the standard login endpoint and works inside the WebView too.
  • mobile-build.yml workflow produces:
    - web-dist (always)
    - careerflow-android-aab — signed if ANDROID_KEYSTORE_* secrets are set, debug AAB otherwise
    - careerflow-ios — signed IPA if Apple secrets are set, unsigned xcarchive otherwise
  • Fastlane configs ready to run with credentials; lanes documented in docs/app-store-submission.md.
  • /install landing page renders store badges, detects iOS / Android / desktop, and exposes the beforeinstallprompt PWA install.
  • Privacy policy (GDPR-conformant) and submission walkthrough present.
  • Quality gate green on this branch:
    - frontend: ESLint clean, tsc --noEmit clean, vitest 10/10, vite build 23.16 s
    - backend: ruff clean, ruff format clean, mypy 71/71 clean, bandit clean, pytest 112/112

Required secrets to publish

Add these in Settings → Secrets and variables → Actions:

Android

  • ANDROID_KEYSTORE_BASE64 — base64 of the upload .jks
  • ANDROID_KEYSTORE_PASSWORD
  • ANDROID_KEY_ALIAS
  • ANDROID_KEY_PASSWORD
  • GOOGLE_PLAY_JSON_KEY — contents of the Play Console service-account JSON

iOS

  • APPLE_TEAM_ID — 10-character team ID
  • FASTLANE_USER — Apple ID
  • FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD
  • MATCH_PASSWORD — passphrase used by fastlane match
  • MATCH_GIT_URL — private git repo with signing material

Until those exist, CI still produces an unsigned xcarchive and a debug AAB so the operator can inspect builds and run Fastlane locally.

Blocking items requiring real credentials

These cannot be generated programmatically — see docs/app-store-submission.md §1–3:

  1. Apple Developer Program enrolment ($99/yr) — without it there is no Team ID and no path to App Store Connect.
  2. Google Play Console account ($25 one-time) and identity verification.
  3. Upload keystore for Android (one keytool command; see the doc).
  4. Signing certificate + provisioning profile for iOS (via Xcode or fastlane match).
  5. Service-account JSON for Play Console API access.
  6. Real store-listing assets (1024×500 feature graphic, phone/tablet screenshots, app icon if you want something other than the brand C).

Next steps for the operator

  1. Add the secrets listed above.
  2. Push to main (or trigger mobile-build manually) — CI uploads signed AAB + IPA artifacts.
  3. Run bundle exec fastlane beta from fastlane/ios/ and fastlane/android/ to deliver to TestFlight and the Play Internal track.
  4. After review approval, bundle exec fastlane release promotes to production in both stores.
  5. Edit the placeholder APPSTORE_URL and PLAYSTORE_URL constants at the bottom of landing/index.html with the live store URLs, then redeploy the frontend.

- capacitor.config.json wires iOS/Android wrappers to the existing Vite dist/
  bundle under the com.careerflow.app bundle ID with brand splash colors.
- src/lib/capacitor-auth.ts: thin platform detection helpers; existing
  localStorage token store works unchanged in the WebView.
- public/native-assets/icon.png + README: single source for app icons,
  regenerated per-platform by '@capacitor/assets generate'.
- package.json: cap:* scripts and a prebuild that mirrors landing/ into
  public/install/.
- vercel.json: explicit /install rewrite so the SPA fallback does not eat
  the landing page; cleanUrls enabled.
Single page that detects the visitor's device and surfaces the right
install path:
- iOS visitors see an emphasised App Store badge plus an 'Add to Home
  Screen' nudge.
- Android visitors see Google Play first, then the in-browser PWA prompt.
- Desktop visitors get the install-as-app callout that fires the
  beforeinstallprompt handler.

Lives at landing/index.html as the canonical source; the frontend prebuild
script mirrors it into public/install/ so /install ships with every Vercel
deploy. _redirects covers Netlify-style hosts.
- fastlane/ios/{Fastfile,Appfile,Gemfile}: certs (match), build (signed if
  secrets present, unsigned archive otherwise), beta (TestFlight), and
  release (App Store Connect via deliver).
- fastlane/android/{Fastfile,Appfile,Gemfile}: gradle bundleRelease with
  injected signing properties, beta (internal track), and release
  (production) via supply.
- fastlane/metadata and store-meta: en-US name/subtitle/description/
  keywords/promotional text/release notes/screenshots scaffolding for
  both Apple and Google submissions.

No credentials are committed; every secret is read from environment
variables documented in docs/app-store-submission.md.
- .github/workflows/mobile-build.yml: builds the web bundle (with lint,
  typecheck, tests, build), then attempts Android AAB and iOS archive in
  parallel. Signs builds when the relevant secrets exist; produces an
  unsigned debug AAB / xcarchive otherwise so operators always get a
  reviewable artifact.
- scripts/build-mobile.sh: same flow runnable locally (cap sync + gradle
  bundleRelease and/or xcodebuild archive).
- scripts/generate-screenshots.sh: wraps the existing puppeteer harness
  to write store-ready screenshots into store-meta/.
- docs/privacy-policy.md: GDPR-conformant policy listing every category of
  data the app stores, why, where it lives, how to delete it, and which
  third parties may see it. App Store and Play Store require a privacy
  policy URL; this is what the Fastlane metadata points at.
- docs/app-store-submission.md: step-by-step operator guide covering
  developer account setup, signing material generation, the exact GitHub
  Actions secrets required, and the lanes to run to publish.
…tall badges

The mobile wrapper's WebView serves bundled assets from https://localhost
(Android) or capacitor://localhost (iOS). Adding both — plus the ionic://
variant — to the default CORS list lets the iOS/Android app talk to a
local backend with no extra config. Production deployments override
CORS_ORIGINS as before.

README: top-of-page App Store / Google Play / Install PWA badges that
point at /install, plus a mobile-build CI badge.
Service worker (sw.js):
- Bumped cache version to v2 (force clean activation).
- /api/, /health, /openapi.json are never cached so user data cannot leak
  via a stale cache or persist after logout.
- Navigation requests are network-first with a cached shell fallback only
  when offline, so deploys roll out immediately.
- Hash-named /assets/* are cache-first (immutable).
- Everything else is stale-while-revalidate.
- A CAREERFLOW_LOGOUT postMessage from the app wipes all caches.

src/lib/notifications.ts:
- Schedules local notifications ahead of upcoming interviews via the
  Capacitor LocalNotifications plugin when present; on the web (or on a
  native build without the plugin) it is a quiet no-op.
- No static dependency on @capacitor/local-notifications, so the SPA
  bundle and CI typecheck are unaffected. Native builds get the plugin
  installed during cap sync.

This addresses two of the App-Store-readiness review notes: (1) make the
service worker conservative about API responses, and (2) add a real native
integration so the app isn't a pure webview wrapper.
@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
frontend Ready Ready Preview, Comment Jun 24, 2026 11:30pm

@Joun-Mikhail
Joun-Mikhail temporarily deployed to feature/app-store-packaging - careerflow-web-589d PR #1 June 24, 2026 22:44 — with Render Destroyed
@Joun-Mikhail
Joun-Mikhail temporarily deployed to feature/app-store-packaging - careerflow-web PR #1 June 24, 2026 22:44 — with Render Destroyed
- Regenerated all dashboard/board/detail/analytics/offers/interviews
  screenshots from the running app so they show the new accent-colored
  stat cards.
- Added docs/screenshots/mobile-dashboard.png: the phone layout with the
  slide-in navigation drawer open over a dimmed backdrop.
- screenshot.mjs: log in with demo credentials (the form no longer
  pre-fills) and capture a 390x844 mobile frame.
- README: feature list now calls out CSV export and the installable
  PWA / mobile drawer; screenshots table refreshed with the dashboard
  and a dedicated mobile shot.
@Joun-Mikhail
Joun-Mikhail temporarily deployed to feature/app-store-packaging - careerflow-web-589d PR #1 June 24, 2026 23:30 — with Render Destroyed
@Joun-Mikhail
Joun-Mikhail temporarily deployed to feature/app-store-packaging - careerflow-web PR #1 June 24, 2026 23:30 — with Render Destroyed
@Joun-Mikhail
Joun-Mikhail merged commit 054e1d3 into main Jun 24, 2026
5 of 7 checks passed
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