Skip to main content

Deploy Pipeline

Fastlane now has two deployment lanes:

  • The promotion lane starts from develop, builds the core apps once, auto-deploys dev, then promotes through qa, uat, staging, and production.
  • The release lane starts from GitLab Run pipeline for a release/* branch and deploys the selected lower environment (dev, qa, or uat) without exposing higher-environment jobs.

Full Deploy Flow

Build Once, Deploy Many

Images are built once in the build-images stage and pushed to the GitLab Container Registry ($CI_REGISTRY_IMAGE/<app>:$CI_COMMIT_SHA). Every subsequent deploy job promotes the pre-built image to Heroku by pulling from GitLab CR, retagging for Heroku, and pushing — no Docker build occurs during deploy.

Frontend Runtime Config

Frontend apps (portal, admin) use runtime config injection instead of build-time DOTENV_KEY. The nginx entrypoint generates /config.js from Heroku config vars at container startup, which sets window.__RUNTIME_CONFIG__. Application code reads config via getConfig() from @goosehead-fastlane/runtime-config, which reads from window.__RUNTIME_CONFIG__ in production and falls back to import.meta.env in local dev.

Required Heroku config vars for frontend apps:

VariableDescription
VITE_API_GATEWAY_URLAPI gateway base URL (e.g. https://dev-fastlane-api-gateway.goosehead.com/api)
VITE_DA_BASE_URLDA quote base URL (e.g. https://dev.quote.goosehead.com)

See Heroku Config Vars Reference for per-environment values.

Deploy Matrix

Each environment deploys apps in parallel using a matrix strategy:

parallel:
matrix:
- APP_NAME: fastlane-portal
HEROKU_APP_NAME: dev-fastlane-portal
PROCESS_TYPE: web
- APP_NAME: fastlane-admin
# ...
- APP_NAME: fastlane-api-gateway
# ...

The promotion lane deploys the 3 core apps (fastlane-portal, fastlane-admin, fastlane-api-gateway) to every environment. The optional build-images-docs path only deploys docs and components to dev.

Promote Script

Script: ci/scripts/promote-image.sh

Each deploy job runs inside a docker:latest image with Docker-in-Docker (dind) and executes:

  1. Pull from GitLab Container Registry ($CI_REGISTRY_IMAGE/$APP_NAME:$CI_COMMIT_SHA)
  2. Retag for Heroku (registry.heroku.com/$HEROKU_APP_NAME/$PROCESS_TYPE)
  3. Push to Heroku Container Registry
  4. Release via the Heroku Platform API (PATCH /apps/$HEROKU_APP_NAME/formation)
  5. Health Check — waits 15 seconds, then curls https://$HEROKU_APP_NAME.goosehead.com expecting HTTP 200 or 304

Manual Gates and Protected Environments

EnvironmentTriggerProtected Environment Approval
DevAutomatic on develop pushNone
QAwhen: manualQA lead / team
UATwhen: manualQA lead / team
Stagingwhen: manualPM / tech lead
Productionwhen: manualTech lead + PM

All manual gates use allow_failure: false, meaning the pipeline blocks until the gate is explicitly triggered.

Protected environments are configured in GitLab UI under Settings > CI/CD > Protected Environments.

Release Lane

Use the release lane when you need to validate a release/* branch in a lower environment without entering the normal develop -> dev -> qa -> uat -> staging -> production promotion path.

How It Works

  1. Open Build > Pipelines > Run pipeline
  2. Select a release/* branch
  3. Set target_env to dev, qa, or uat
  4. Optionally set run_migrations=true if you want the matching manual migration job to appear

The pipeline validates the branch/source combination early, builds the 3 core apps once, and exposes only one deploy job:

Selected InputVisible Deploy JobHigher-Environment Jobs
target_env=devdeploy-dev-releaseHidden
target_env=qadeploy-qa-releaseHidden
target_env=uatdeploy-uat-releaseHidden

Release-lane deploys are manual for every target environment, including dev. Release-lane migrations are also manual and appear only when run_migrations=true.

Post-Deploy: E2E Tests

The pipeline defines E2E jobs for dev and QA using Playwright with two test projects in parallel, but they are currently disabled in .gitlab-ci.yml to conserve CI minutes:

parallel:
matrix:
- E2E_PROJECT: [da-to-fastlane, carrier-pages]
  • Timeout: 1 hour
  • Allow failure: true (informational, does not block promotion)
  • Artifacts: Playwright HTML report, test output, and JSON results (7-day retention)
  • Result Upload: Playwright JSON results are uploaded to the API gateway's test reports endpoint

Scheduled E2E

A scheduled pipeline runs E2E tests against dev every weekday at 7:00 UTC, independent of any deployment. Manual E2E triggers are also available via the GitLab web UI.

Post-Deploy: Database Migrations

The run-migrations-dev job runs automatically after dev deployment when prisma/ files changed.

It creates a one-off Heroku dyno that runs npx prisma migrate deploy:

  1. Checks if prisma/ files changed in the commit
  2. Creates a run dyno via the Heroku Platform API with a 10-minute TTL
  3. Polls dyno state every 10 seconds (up to 30 attempts)
  4. Fetches dyno logs to verify exit status
  5. Fails the job if the migration exits non-zero or times out

Force Run (Manual Recovery)

For recovery scenarios (for example, a canceled deploy pipeline), you can force this job from New pipeline by setting:

FORCE_RUN_MIGRATIONS=true

When set to true (case-insensitive), the prisma-change gate is bypassed and the job proceeds to run the Heroku migration dyno.

Release-Lane Migrations

Release-lane pipelines do not reuse the automatic prisma-diff migration path from develop.

Instead:

  • run_migrations=false keeps all release-lane migration jobs hidden
  • run_migrations=true exposes the matching manual job for the selected environment
  • the manual job targets the API app for that environment only

Post-Deploy: Database Seed

The run-seed-dev job is manual only and runs npx ts-node prisma/seed.ts via a one-off Heroku dyno with a 30-minute TTL. It follows the same pattern as migrations but with a longer timeout (60 polling attempts) and allow_failure: true.

Troubleshooting: Skipped Migration Jobs

If run-migrations-dev shows green but logs indicate "skipping", the job detected no prisma/ file changes. If you need to run migrations anyway:

  1. Open CI/CD > Pipelines > Run pipeline
  2. Select branch develop
  3. Add variable: FORCE_RUN_MIGRATIONS=true
  4. Run the pipeline

Post-Deploy: Sync to Main

After a successful production deploy from develop, the sync-to-main job keeps main in sync:

  1. Fetches both main and develop
  2. Attempts a fast-forward merge of develop into main
  3. Falls back to a merge commit with [skip ci] if fast-forward isn't possible
  4. Pushes main using GL_PROJECT_TOKEN

This ensures main always reflects what's in production.

Heroku Config Vars Reference

Frontend apps require VITE_* config vars set on each Heroku app. These are read at container startup to generate /config.js.

Heroku AppVITE_API_GATEWAY_URLVITE_DA_BASE_URL
dev-fastlane-portalhttps://dev-fastlane-api-gateway.goosehead.com/apihttps://dev.quote.goosehead.com
dev-fastlane-adminhttps://dev-fastlane-api-gateway.goosehead.com/apiN/A
test-fastlane-portalhttps://test-fastlane-api-gateway.goosehead.com/apihttps://qa.quote.goosehead.com
test-fastlane-adminhttps://test-fastlane-api-gateway.goosehead.com/apiN/A
uat-fastlane-portalhttps://uat-fastlane-api-gateway.goosehead.com/apihttps://uat.quote.goosehead.com
uat-fastlane-adminhttps://uat-fastlane-api-gateway.goosehead.com/apiN/A
preprod-fastlane-portalhttps://preprod-fastlane-api-gateway.goosehead.com/apihttps://staging.quote.goosehead.com
preprod-fastlane-adminhttps://preprod-fastlane-api-gateway.goosehead.com/apiN/A
prod-fastlane-portalhttps://prod-fastlane-api-gateway.goosehead.com/apihttps://quote.goosehead.com
prod-fastlane-adminhttps://prod-fastlane-api-gateway.goosehead.com/apiN/A
Set these BEFORE the first deploy

The first deploy with runtime config will fail to connect to the API gateway if these config vars are not set on the Heroku app beforehand.

Teams Notifications

Every deploy job sends an Adaptive Card to Microsoft Teams (if TEAMS_WEBHOOK_URL is configured) with:

  • Success/failure status
  • App name and Heroku app name
  • Branch and commit SHA
  • Links to the pipeline and deployed app