CI/CD & Automated Testing
Rejourney uses GitHub Actions for four separate release surfaces:
- the production app and backend deployment
- the React Native SDK package
- the native Swift iOS SDK package
- the Browser/Web SDK package
All workflows run on pull requests to main, pushes to main, and manual workflow_dispatch unless noted below. The production deploy and package publishing steps only run from main.
Workflow Map
| Workflow | File | Main responsibility |
|---|---|---|
| Rejourney CI | .github/workflows/rejourney-ci.yml | Backend, dashboard, Kubernetes config checks, image builds, and production deploy |
| React Native SDK CI | .github/workflows/rejourney-sdk.yml | React Native package validation, bare/Expo integration, npm publish, release tag |
| Native iOS CI | .github/workflows/rejourney-ios.yml | Swift package validation, iOS builds/tests, native iOS release tag |
| Web SDK CI | .github/workflows/rejourney-web-sdk.yml | Browser SDK validation, npm publish, release tag |
Production App Pipeline
The production app pipeline is the Rejourney CI workflow.
Pull Request And Push Checks
| Job | Runs | What it checks |
|---|---|---|
backend | PRs and pushes | Backend install, worker parity, schema/migration guard, lint, full tests, billing tests, billing ESLint |
web | PRs and pushes | Root install, dashboard typecheck, dashboard SSR build |
k8s-config | PRs and pushes | Storage cutover validation and secret-hygiene scanning |
The backend guard runs:
scripts/check-worker-parity.mjsscripts/check-schema-migration.sh
The Kubernetes/config guard runs:
scripts/k8s/validate-storage-cutover.shscripts/ci/check-secret-hygiene.sh
Image Build
On main, after backend, web, and k8s-config pass, CI builds and pushes these images to GitHub Container Registry:
| Image | Dockerfile | Tags |
|---|---|---|
api | backend/Dockerfile | latest, ${github.sha} |
web | dashboard/web-ui/Dockerfile | latest, ${github.sha} |
migration | backend/Dockerfile.migration | latest, ${github.sha} |
The web image receives production build args for the dashboard URL, API URL, docs URL, Stripe publishable key, and Turnstile site key.
Deploy Gate
Deployment is intentionally gated. The check-version job runs only on main and compares:
- local root
package.jsonversion in the checked-out repo - remote
/opt/rejourney/package.jsonversion on the VPS
The deploy job runs only when:
- the workflow is on
main - image builds succeeded
- and either the root version changed or the workflow was manually dispatched
Production Deploy
The deploy job SSHes into the VPS as root, ensures /opt/rejourney exists, resets it to origin/main, then runs:
bash scripts/k8s/deploy-release.sh "${IMAGE_TAG}" "${GITHUB_REPOSITORY}"The deploy script is the source of truth for production Kubernetes rollout behavior. It:
- renders manifests with the target image tag
- applies namespace, Traefik config, exporters, ingress, and storage-class support
- applies the CloudNativePG Postgres manifest
- verifies
k8s/archive.yamlis in sync withscripts/k8s/session-backup.mjs - prints migration status before and after setup
- resets and waits for the
db-setupjob - applies PgBouncer and PodDisruptionBudget manifests
- applies Grafana dashboards with server-side apply
- applies rendered app manifests with Kubernetes prune enabled
- protects/restores the Helm-managed Redis service if prune touches it
- waits for app, worker, and monitoring deployments to roll out
- pins selected workloads to the intended nodes or Postgres primary where required
- patches imported Grafana dashboards and clears stale session-backup jobs
After deployment, the GitHub Actions SSH script also prunes old images, removes completed/failed pods, deletes stale debug pods, and restarts session-backup seed jobs so they pick up the latest script ConfigMap.
React Native SDK Pipeline
The React Native SDK pipeline lives in Rejourney SDK CI and validates packages/react-native.
Package Checks
The sdk job runs:
- TypeScript check
- lint
- dependency audit
- unit tests
prepackbuild- optional peer safety verification
- package content verification
- package structure verification
Metro Optional-Peer Check
The metro-optional-peers job creates a fresh React Native validation app, installs a packed local SDK plus @react-navigation/native, configures the app, and runs a Metro bundle. This catches bundling issues in optional navigation peer paths without needing Xcode or Gradle.
Mobile Integration Matrix
The mobile-integration job runs a matrix across:
iosandandroid- bare React Native and Expo apps
For bare apps, CI runs the SDK install smoke scripts:
packages/react-native/scripts/test-ios-install.shpackages/react-native/scripts/test-android-install.sh
For Expo apps, CI creates a fresh Expo app, installs the packed local SDK, runs expo prebuild, then builds the native project:
- iOS:
xcodebuildagainst the simulator workspace - Android:
./gradlew assembleDebug
Publish And Release
On main, after integration checks pass, publish-sdk builds the package and compares the local packages/react-native/package.json version with the npm registry. If the version is different, CI publishes @rejourneyco/react-native.
After a successful publish, release-rn-tag creates:
- tag:
react-native/vX.Y.Z - GitHub release:
React Native SDK vX.Y.Z
The tag is only created when packages/react-native/package.json changed from the previous commit.
Native iOS SDK Pipeline
The native Swift SDK pipeline lives in Rejourney Native iOS CI and validates the root Swift package plus packages/ios.
It runs on:
- pushes to
main - pull requests to
main - tags matching
v* - manual dispatch
The main validation job:
- verifies package boundary files exist
- rejects React Native imports, React bridge names, and non-native-prefixed Objective-C runtime names inside the Swift package
- checks
packages/ios/VERSIONmatchesRejourneySDKInfo.swift - checks tag version matches the SDK version for
vX.Y.Ztag builds - builds the Swift package for iOS Simulator
- builds the Swift package for generic iOS
- runs Swift tests on an available iPhone simulator
- builds the native iOS example project
On direct pushes to main, if packages/ios/VERSION changed, CI creates:
- tag:
vX.Y.Z - GitHub release:
iOS SDK vX.Y.Z
Web SDK Pipeline
The Browser/Web SDK pipeline lives in Rejourney Web SDK CI and validates packages/browser.
The web-sdk job runs:
- TypeScript check
- unit tests
prepackbuildnpm pack --dry-run- package structure verification
On main, web-version checks whether packages/browser/package.json changed. It refuses to publish or tag the bootstrap version 0.0.0.
If the web package version changed, publish-web-sdk compares the local version with npm and publishes @rejourneyco/browser when the local version is different.
After a successful publish, release-browser-tag creates:
- tag:
browser/vX.Y.Z - GitHub release:
Browser SDK vX.Y.Z
Local CI Parity
Local Kubernetes parity is driven by the root package scripts:
npm run ci:local
npm run ci:local:fast
npm run ci:local:checks
npm run ci:local:deployThese call scripts/local-k8s/rejourney-ci.sh.
| Command | Purpose |
|---|---|
npm run ci:local | Full local parity run: install, validate, build images, import into k3d, deploy, migrate, restart host services |
npm run ci:local:fast | Same flow but skips reinstall steps |
npm run ci:local:checks | Validation checks only |
npm run ci:local:deploy | Rebuild/import/deploy local images without rerunning validation |
The local parity runner uses the production-style migration path, not a schema push shortcut. It also runs the worker parity and schema migration guards before local deployment.
Required Secrets
| Secret | Used by | Purpose |
|---|---|---|
VPS_SSH_KEY | check-version, deploy | SSH key for root@VPS |
VPS_HOST | check-version, deploy | VPS host or Tailscale IP |
GITHUB_TOKEN | release and package workflows | GitHub-provided token for tags/releases/packages |
NPM_TOKEN | React Native and Web SDK publish jobs | npm publish token |
VITE_STRIPE_PUBLISHABLE_KEY | web image build | Dashboard Stripe public key |
TURNSTILE_SITE_KEY | web image build | Dashboard Cloudflare Turnstile site key |
Primary Files
.github/workflows/rejourney-ci.yml.github/workflows/rejourney-sdk.yml.github/workflows/rejourney-ios.yml.github/workflows/rejourney-web-sdk.ymlscripts/k8s/deploy-release.shscripts/local-k8s/rejourney-ci.shscripts/local-k8s/deploy.sh