-
Notifications
You must be signed in to change notification settings - Fork 0
feat: Railway migration, Shorebird OTA, CI/CD overhaul & infrastructure docs #111
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from all commits
ac5ac31
4352752
66d07e0
93442b5
e47c820
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| name: Deploy Backend to Railway | ||
|
|
||
| on: | ||
| push: | ||
| branches: [prod] | ||
| paths: | ||
| - 'backend/**' | ||
| - '.github/workflows/backend-deploy.yml' | ||
|
|
||
| jobs: | ||
| # ── Test backend before deploying ────────────────────────── | ||
| test-backend: | ||
| name: Test Backend | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Setup Dart SDK | ||
| uses: dart-lang/setup-dart@v1 | ||
| with: | ||
| sdk: stable | ||
|
|
||
| - name: Install dependencies | ||
| working-directory: backend | ||
| run: dart pub get | ||
|
|
||
| - name: Analyze backend code | ||
| working-directory: backend | ||
| run: dart analyze --fatal-infos | ||
|
|
||
| - name: Run backend tests | ||
| working-directory: backend | ||
| run: dart test | ||
|
|
||
| # ── Deploy to Railway on push to prod ────────────────────── | ||
| deploy-backend: | ||
| name: Deploy to Railway | ||
| needs: test-backend | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout repository | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Install Railway CLI | ||
| run: npm install -g @railway/cli | ||
|
|
||
| - name: Deploy to Railway | ||
| working-directory: backend | ||
| run: railway up --service familiarise-mobile-api --detach | ||
| env: | ||
| RAILWAY_TOKEN: ${{ secrets.RAILWAY_TOKEN }} | ||
|
|
||
| - name: Verify deployment health | ||
| run: | | ||
| echo "Waiting for deployment to stabilize..." | ||
| sleep 30 | ||
| curl --fail --retry 5 --retry-delay 10 \ | ||
| "${{ secrets.PRODUCTION_API_BASE_URL }}/api/health" || \ | ||
| echo "::warning::Health check failed - check Railway dashboard" | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2,11 +2,22 @@ name: Flutter CI/CD | |||||||||||||||||||
|
|
||||||||||||||||||||
| on: | ||||||||||||||||||||
| push: | ||||||||||||||||||||
| branches: [main, develop] | ||||||||||||||||||||
| branches: [prod, dev] | ||||||||||||||||||||
| tags: ['v*.*.*'] | ||||||||||||||||||||
| pull_request: | ||||||||||||||||||||
| branches: [main, develop] | ||||||||||||||||||||
| branches: [prod, dev] | ||||||||||||||||||||
| release: | ||||||||||||||||||||
| types: [published] | ||||||||||||||||||||
| workflow_dispatch: | ||||||||||||||||||||
| inputs: | ||||||||||||||||||||
| deploy_type: | ||||||||||||||||||||
| description: 'Deployment type' | ||||||||||||||||||||
| required: false | ||||||||||||||||||||
| default: 'patch' | ||||||||||||||||||||
| type: choice | ||||||||||||||||||||
| options: | ||||||||||||||||||||
| - patch | ||||||||||||||||||||
| - release | ||||||||||||||||||||
|
Comment on lines
+12
to
+20
|
||||||||||||||||||||
| inputs: | |
| deploy_type: | |
| description: 'Deployment type' | |
| required: false | |
| default: 'patch' | |
| type: choice | |
| options: | |
| - patch | |
| - release |
Copilot
AI
Mar 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shorebird-release is configured to run on tag pushes (if: startsWith(github.ref, 'refs/tags/')) but it needs: [deploy-android, deploy-ios]. Those deploy jobs only run when github.event_name == 'release', so on a tag push they will be skipped and this job won’t run either. To make Shorebird releases actually happen on tags, adjust the dependencies/conditions (e.g., depend on the build jobs for tag pushes, or run Shorebird release on release events instead of tag pushes).
| if: startsWith(github.ref, 'refs/tags/') | |
| if: github.event_name == 'release' && startsWith(github.ref, 'refs/tags/') |
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shorebird release ios requires a macOS runner (Xcode toolchain). Running the Shorebird release job on ubuntu-latest will fail for iOS; split Android/iOS into separate jobs (ubuntu for android, macos for ios) or use a matrix with per-platform runs-on.
Copilot
AI
Apr 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This job runs on ubuntu-latest but executes shorebird patch ios, which typically requires macOS/Xcode. To avoid guaranteed failures, run the iOS patch step on a macOS runner (separate job or matrix) and keep Android patching on Linux.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| # Familiarise Mobile — System Architecture | ||
|
|
||
| ## Infrastructure | ||
|
|
||
| ### Backend hosting — Railway | ||
|
|
||
| The Dart Frog API (`backend/`) is deployed on Railway. | ||
|
|
||
| - Auto-deploys on every push to `prod` that touches `backend/**` | ||
| - Health check endpoint: `GET /api/health` | ||
| - Environment variables are set in the Railway dashboard (not in code) | ||
| - Uses Supabase connection pooler (port 6543) for `DATABASE_URL` at runtime | ||
| - Uses direct connection (port 5432) for `DIRECT_URL` (migrations only) | ||
| - The backend uses `DotEnv(includePlatformEnvironment: true)` so it works both locally (with `.env` file) and in Docker/Railway (where env vars are injected by the platform) | ||
|
|
||
| **Local dev:** `cd backend && dart_frog dev` → `http://localhost:8080` | ||
|
|
||
| ### OTA updates — Shorebird | ||
|
|
||
| Shorebird enables Dart-only patches to be delivered to users without App Store/Play Store review. | ||
|
|
||
| - A Shorebird **release** is created automatically alongside every tagged store release | ||
| - A Shorebird **patch** is applied automatically when pushing to any `hotfix/*` branch | ||
| - Patches can also be triggered manually via GitHub Actions → workflow_dispatch | ||
| - Patches apply silently on the user's next app launch (no update prompt) | ||
|
|
||
| **Limitation:** Shorebird patches Dart code only. Changes to native Android/iOS code, new Flutter plugins with native bindings, or new assets require a full store release. | ||
|
|
||
| ### Update decision tree | ||
|
|
||
| ``` | ||
| Need to fix something? | ||
| │ | ||
| ├── Backend logic / API / DB query | ||
| │ └── Push to prod → auto-deploys to Railway → users see it instantly | ||
| │ | ||
| ├── Flutter Dart code (UI, state, business logic, API calls) | ||
| │ ├── Minor hotfix → push to hotfix/* branch → shorebird patch | ||
| │ └── Larger change with tests → PR → merge to dev → tag release | ||
| │ | ||
| └── Native code (new plugin, permission, asset, icon) | ||
| └── Full release: tag → GitHub Actions builds + deploys to stores | ||
| ``` | ||
|
|
||
| ### Branch strategy | ||
|
|
||
| - `dev` — development branch (default) | ||
| - `prod` — production branch (Railway deploys from here) | ||
| - `feature/*` — feature branches (PR to dev) | ||
| - `hotfix/*` — hotfix branches (triggers Shorebird patch) | ||
|
|
||
| ### Environment configuration | ||
|
|
||
| - **Flutter app:** Uses `envied` package to read from `.env` at build time. CI generates `.env` from GitHub Secrets. Do NOT use `--dart-define` — it's incompatible with the envied approach. | ||
| - **Backend:** Uses `dotenv` package with `includePlatformEnvironment: true`. Works with both `.env` file (local) and platform env vars (Railway/Docker). | ||
|
|
||
| ### CI/CD workflows | ||
|
|
||
| | Workflow | File | Triggers | | ||
| |----------|------|----------| | ||
| | Flutter CI/CD | `flutter-ci.yml` | Push to prod/dev, PRs, releases, tags, manual | | ||
| | Backend Deploy | `backend-deploy.yml` | Push to prod (backend/** changes) | | ||
|
|
||
| ### Known gotchas | ||
|
|
||
| - `backend/lib/generated/` has a `Platform` enum (from Prisma schema) that conflicts with `dart:io.Platform`. Use `import 'dart:io' as io show Platform;` or explicit `show` clauses. | ||
| - `flutter analyze` runs on both frontend AND backend (the whole workspace). | ||
| - Use `scripts/regenerate-build.sh --prisma` when generated models are stale. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The post-deploy health check can’t fail the workflow because it’s followed by
|| echo "::warning::...". That means a bad deploy still reports success, which undermines the purpose of a health check gate. If you want this to block approval/deploy, letcurl --fail ...exit non-zero (or explicitlyexit 1on failure) so the job fails when the service is unhealthy.