Add App Store & Play Store packaging (Capacitor) + Install landing page + Fastlane#1
Merged
Merged
Conversation
- 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.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Joun-Mikhail
temporarily deployed
to
feature/app-store-packaging - careerflow-web-589d PR #1
June 24, 2026 22:44 — with
Render
Destroyed
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
temporarily deployed
to
feature/app-store-packaging - careerflow-web-589d PR #1
June 24, 2026 23:30 — with
Render
Destroyed
Joun-Mikhail
temporarily deployed
to
feature/app-store-packaging - careerflow-web PR #1
June 24, 2026 23:30 — with
Render
Destroyed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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
frontend/capacitor.config.json,frontend/src/lib/capacitor-auth.ts,frontend/public/native-assets/,cap:*npm scriptslanding/index.html(canonical), auto-mirrored topublic/install/by the newprebuildscript; Vercel rewrite addedfastlane/ios/{Fastfile,Appfile,Gemfile},fastlane/android/{Fastfile,Appfile,Gemfile},fastlane/metadata/{ios,android}/en-US/.github/workflows/mobile-build.yml— builds web bundle, AAB, IPA/xcarchivescripts/build-mobile.sh,scripts/generate-screenshots.shstore-meta/appstore/,store-meta/playstore/docs/privacy-policy.md,docs/app-store-submission.mdCORS_ORIGINSextended to cover Capacitor WebView origins (https://localhost,capacitor://localhost,ionic://localhost)mobile-buildCI badgeCommits
feat(mobile)Capacitor wrapper config and helpersfeat(landing)trusted Install page at /installfeat(release)Fastlane lanes and store metadata templatesci(mobile)mobile-build workflow + local build scriptsdocsprivacy policy and App Store submission guidefeat(backend)allow Capacitor WebView origins by default; README install badgesAcceptance checklist
npm run buildexits 0 —dist/produced,dist/install/index.html(8.3 KB) included.mobile-build.ymlworkflow produces:-
web-dist(always)-
careerflow-android-aab— signed ifANDROID_KEYSTORE_*secrets are set, debug AAB otherwise-
careerflow-ios— signed IPA if Apple secrets are set, unsignedxcarchiveotherwisedocs/app-store-submission.md./installlanding page renders store badges, detects iOS / Android / desktop, and exposes thebeforeinstallpromptPWA install.- frontend: ESLint clean,
tsc --noEmitclean, 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.jksANDROID_KEYSTORE_PASSWORDANDROID_KEY_ALIASANDROID_KEY_PASSWORDGOOGLE_PLAY_JSON_KEY— contents of the Play Console service-account JSONiOS
APPLE_TEAM_ID— 10-character team IDFASTLANE_USER— Apple IDFASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORDMATCH_PASSWORD— passphrase used byfastlane matchMATCH_GIT_URL— private git repo with signing materialUntil those exist, CI still produces an unsigned
xcarchiveand 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:keytoolcommand; see the doc).fastlane match).Next steps for the operator
main(or triggermobile-buildmanually) — CI uploads signed AAB + IPA artifacts.bundle exec fastlane betafromfastlane/ios/andfastlane/android/to deliver to TestFlight and the Play Internal track.bundle exec fastlane releasepromotes to production in both stores.APPSTORE_URLandPLAYSTORE_URLconstants at the bottom oflanding/index.htmlwith the live store URLs, then redeploy the frontend.