CI/CD Pipeline
Alt du trenger for a forsta og bruke CI/CD-pipelinen i Impulse AI. Skrevet for soloutviklere som vil ha full kontroll uten a vaere DevOps-ekspert.
Hurtigreferanse
heading.anchorLabel| Oppgave | Kommando |
|---|---|
| Ny feature-branch | git checkout -b feat/min-feature |
| Kjor med secrets lokalt | doppler run -- pnpm dev |
| Promoter staging til production | /deploy-prod eller git push origin main:production |
| iOS til TestFlight | fastlane ios bump type:patch (oppretter git tag v*) |
| Promoter til App Store | /promote eller fastlane ios promote |
| Manuell DB-migrasjon | db-deploy.yml -> dry-run / migrate |
| Sjekk CI-status | gh run list --limit 5 |
1. Hva er CI/CD?
heading.anchorLabelCI/CD star for Continuous Integration (CI) og Continuous Deployment (CD). I praksis betyr det at koden din blir automatisk testet og deployet nar du pusher den til GitHub.
Continuous Integration (CI)
heading.anchorLabelHver gang du pusher kode eller apner en pull request, kjorer GitHub Actions automatisk en serie sjekker: linting, typechecking, tester, kompilering. Alt dette skjer for koden merges til main.
Continuous Deployment (CD)
heading.anchorLabelNar kode er merget til main, deployes DB+API automatisk til staging (Railway + Supabase staging). Nar du promoterer til production (git push origin main:production), deployes DB+API til production (Railway + Supabase production).
iOS har en separat release-syklus: git tags (v*) trigger TestFlight-bygg via Fastlane, og promotering til App Store gjores manuelt.
Hvorfor er dette viktig for en soloutvikler?
heading.anchorLabel- Sikkerhetsnett: CI fanger feil for de nar brukerne. Du har ikke et QA-team — CI er QA-teamet ditt.
- Konsistens: Deploy-prosessen er identisk hver gang, uansett om det er mandagsmorgen eller fredagskveld.
- Hastighet: En git tag er alt som trengs for a release. Ingen manuell building, uploading, eller huskelister.
- Trygghet: Du kan merge med selvtillit fordi du vet at alt er sjekket.
2. Arkitekturoversikt
heading.anchorLabelHer er hele pipelinen visualisert — fra du skriver kode lokalt til den er live i produksjon:
Full pipeline
heading.anchorLabelLokal dev ──> Feature branch ──> CI Preflight ──> Merge til main(din maskin) (git push) (GitHub Actions) (PR godkjent)
DB + API (tett koblet):main branch ──> ┌─ DB staging ┐(push trigger) └─ API staging ┘── STAGING (Railway staging + Supabase staging)
main:production ─> ┌─ DB prod ┐(/deploy-prod) └─ API prod ┘── PRODUCTION (Railway prod + Supabase prod)
iOS (separat syklus):git tag v* ──> TestFlight ──> App Store(fastlane) (automatisk) (manuell promote)Systemer involvert
heading.anchorLabel| System | Rolle | Trigger |
|---|---|---|
| GitHub Actions | Kjorer CI-sjekker og orkestrerer deploys | Push, PR, git tag |
| Doppler | Secrets management — erstatter .env-filer | Injiseres automatisk |
| Supabase | Database (PostgreSQL) + Auth | Migrasjoner ved deploy |
| Railway | API-server hosting (Fastify) | Staging: auto-deploy fra main. Prod: auto-deploy fra production |
| Vercel | Web-app hosting (Next.js) | Auto-deploy fra main |
| Fastlane | iOS build-automatisering | Kalles fra GitHub Actions |
| App Store Connect | TestFlight-distribusjon og App Store | Upload fra Fastlane |
3. Secrets Management med Doppler
heading.anchorLabelHva er Doppler? Doppler er en sentral plattform for a haandtere secrets (API-nokler, passord, konfigurasjon). Istedenfor a ha
.env-filer liggende lokalt som du maa holde synkronisert, lever alle secrets i Doppler og injiseres automatisk der de trengs.
De tre konfigurasjonene
heading.anchorLabelDoppler har tre separate configs som matcher dine miljoer:
| Config | Miljo | Brukes av |
|---|---|---|
dev | Lokal utvikling | Din maskin via doppler run |
stg | Staging | GitHub Actions (CI + staging deploy) |
prd | Production | GitHub Actions (prod deploy) |
Hvordan secrets flyter
heading.anchorLabel ┌─ doppler run ────────────> din terminal │ Doppler ────────┼─ DOPPLER_TOKEN_STG ──────> GitHub Actions (CI) (sentralt lager)│ └─ DOPPLER_TOKEN_PRD ──────> GitHub Actions (prod deploy)Bruke Doppler lokalt
heading.anchorLabelProsjektet har en doppler.yaml i roten som setter opp riktig prosjekt og config:
setup: - project: im config: devEtter forste gangs oppsett (doppler login + doppler setup), kjorer du all lokal utvikling med:
# Starter dev-server med alle secrets injisert som env varsdoppler run -- pnpm dev
# Eller bare API-serverendoppler run -- pnpm --filter api devLegge til eller oppdatere en secret
heading.anchorLabel- Ga til Doppler Dashboard (app.doppler.com) — velg prosjektet “im” og riktig config (dev/stg/prd)
- Legg til eller endre secret — klikk “Add Secret” eller rediger en eksisterende. Gjor dette for alle configs der den trengs.
- Bruk den — lokalt: restart
doppler run -- pnpm dev. I CI: automatisk tilgjengelig neste kjoring.
Key rotation (bytte en noekkel)
heading.anchorLabel- Generer ny noekkel hos tjenesteleverandoren (f.eks. Anthropic, Supabase)
- Oppdater i Doppler for alle miljoer (dev, stg, prd)
- Restart/redeploy — lokalt: restart doppler run. Staging/prod: trigger ny deploy.
- Revoke gammel noekkel hos tjenesteleverandoren
4. GitHub Actions — Hva skjer nar du pusher kode?
heading.anchorLabelNar du pusher til en branch eller apner en PR mot main, starter ci.yml automatisk. Her er en oversikt over hva som skjer:
Steg 1: Detect Changes
heading.anchorLabelForste jobb bruker dorny/paths-filter for a finne ut hvilke deler av monorepo-et som er endret. Dette betyr at hvis du bare har endret iOS-kode, kjorer ikke API-sjekkene. Effektivt og raskt.
| Filter | Stier som overvakes |
|---|---|
db | packages/database/** |
api | apps/api/**, packages/shared/**, packages/auth/** |
packages | packages/** |
ios | apps/mobile-kmp/shared/**, apps/mobile-kmp/iosApp/**, Gradle-filer |
android | apps/mobile-kmp/shared/**, apps/mobile-kmp/androidApp/**, Gradle-filer |
Steg 2: Parallelle sjekker
heading.anchorLabelBasert pa hvilke endringer som ble oppdaget, kjores relevante jobber parallelt:
Database
Starter lokal Supabase, kjorer alle migrasjoner med supabase db reset, verifiserer at genererte TypeScript-typer er oppdaterte.
Kjorer kun nar: packages/database/** er endret.
API
Lint -> Type check (shared + auth + api) -> Test -> Build. Secrets hentes fra Doppler (stg).
Kjorer nar: apps/api/** eller packages/** er endret.
iOS Preflight
Kjorer pa macos-15. KMP shared-modul kompileres, deretter iOS simulator build via Fastlane preflight lane.
Kjorer nar: KMP shared, iosApp, eller Gradle-filer er endret.
Android Preflight
Kjorer pa ubuntu-latest. Bygger Android debug APK med assembleDebug.
Kjorer nar: KMP shared, androidApp, eller Gradle-filer er endret.
Steg 3: CI Gate
heading.anchorLabelDen siste jobben, CI Gate, venter pa alle andre jobber. Den feiler hvis noen av sjekkene feilet. Jobber som ble skippet (fordi de delene av koden ikke var endret) teller som ok.
Concurrency control
heading.anchorLabelWorkflowen bruker concurrency: ci-${{ github.ref }} med cancel-in-progress: true. Det betyr at hvis du pusher to ganger raskt etter hverandre pa samme branch, kanselleres den forste kjoringen automatisk. Ingen bortkastet tid.
5. Automatisk Deploy til Staging
heading.anchorLabelNar kode merges til main (push, ikke PR), skjer staging-deploy automatisk.
To brancher
heading.anchorLabel| Branch | Miljo | URL |
|---|---|---|
main | Staging | api-stg.impulseai.app |
production | Production | api.impulseai.app |
Hva trigger staging?
heading.anchorLabelif: github.ref == 'refs/heads/main' && github.event_name == 'push'Hva skjer?
heading.anchorLabelDatabase -> Staging
Kjorer supabase db push mot staging-prosjektet. Secrets (project ref, access token) hentes fra Doppler via DOPPLER_TOKEN_STG.
Kun nar DB-filer er endret.
API -> Staging
Railway overvaker main-branchen og deployer automatisk. Ingen manuell handling nodvendig.
6. Release til Production
heading.anchorLabelDB + API (tett koblet)
heading.anchorLabelDB og API deployes sammen ved a promotere main til production-branchen:
# Promoter staging til productiongit push origin main:production
# Eller via Claude Code:/deploy-prodRailway production-service overvaker production-branchen og deployer automatisk. Database-migrasjoner kjores mot produksjons-Supabase.
Forutsetning: Staging er testet og fungerer. main inneholder alltid den nyeste koden som er verifisert i staging.
iOS (separat release-syklus)
heading.anchorLabeliOS har sin egen release-syklus, uavhengig av DB+API:
# 1. Bump versjon og opprett git tagcd apps/mobile-kmp/iosAppbundle exec fastlane ios bump type:patch # 1.0.0 -> 1.0.1
# Eller via Claude Code:/release ios patch
# 2. Git tag v* trigger TestFlight-bygg automatiskTestFlight -> App Store:
Etter at iOS-bygget er oppe pa TestFlight, tester du det manuelt. Nar du er fornoyd, promoterer du til App Store:
# Via Claude Code:/promote
# Eller lokalt:cd apps/mobile-kmp/iosAppbundle exec fastlane ios promote
# Eller via GitHub Actions:# Actions > "iOS Release (manual)" > Run workflow > Velg "promote"7. Fastlane — iOS Build Pipeline
heading.anchorLabelHva er Fastlane? Fastlane er et Ruby-basert verktoy som automatiserer iOS (og Android) build, testing, og distribusjon. Istedenfor a gjore ting manuelt i Xcode, definerer du “lanes” (oppgaver) i en
Fastfile.Nokkelprinsipp: Fastfilen er “single source of truth”. GitHub Actions kaller bare Fastlane — all byggelogikk bor i Fastfilen.
Tilgjengelige lanes
heading.anchorLabel| Lane | Hva den gjor | Nar |
|---|---|---|
preflight | KMP compile + iOS simulator build (ingen signing) | CI pa hver PR |
test | Kjorer iOS-tester pa iPhone 16 simulator | Lokal utvikling |
beta | Signing -> KMP release -> archive -> TestFlight upload | Production deploy (git tag) |
promote | Siste TestFlight-bygg -> App Store Connect | Manuelt etter testing |
release | Full pipeline: beta + App Store upload | Force-release (manuelt) |
bump | Bump versjon (patch/minor/major) + commit + tag | For release |
doctor | Health check: Gradle, Xcode, signing, ASC API key | Debugging |
Signing med Match
heading.anchorLabelFastlane bruker Match for kodesignering. Match lagrer sertifikater og provisioning profiles i et privat Git-repo, slik at de kan deles mellom lokal maskin og CI.
Slik fungerer signing-flyten
heading.anchorLabel- API-noekkel: App Store Connect API key (ASC_KEY_ID, ASC_ISSUER_ID, ASC_PRIVATE_KEY) injiseres fra Doppler.
- Match synkroniserer: Henter certificates og profiles fra Git-repoet. I CI kjorer den
readonly(oppretter aldri nye). - Build: Xcode bruker provisioning profile fra Match for a signere appen.
Beta lane i detalj
heading.anchorLabelNar fastlane ios beta kjorer, skjer dette:
- Sjekk clean git (skippes i CI)
- Sync signing — henter sertifikater via Match
- Auto-inkrement build number — henter siste fra TestFlight, legger til 1
- KMP release framework —
linkReleaseFrameworkIosArm64 - Archive — release-build med
export_method: "app-store" - Upload til TestFlight — med changelog fra siste 15 commits
- Commit versjonsbump + tag —
beta/v1.2.3-42
8. Git Workflow
heading.anchorLabelBranch-basert flyt
heading.anchorLabelfeature/* ──> Pull Request ──> main ──────────────> production(utvikling) (CI kjorer) (-> staging auto) (/deploy-prod)
iOS: fastlane ios bump ──> git tag v* ──> TestFlight ──> App Store (/release ios) (auto) (/promote)Branch-navnkonvensjoner
heading.anchorLabel| Prefiks | Bruk | Eksempel |
|---|---|---|
feat/ | Ny funksjonalitet | feat/check-in-flow |
fix/ | Bugfix | fix/session-timeout |
chore/ | Vedlikehold, opprydding | chore/update-deps |
refactor/ | Kode-omstrukturering | refactor/store-architecture |
docs/ | Dokumentasjon | docs/cicd-guide |
Commit-meldinger
heading.anchorLabelFolg Conventional Commits-monsteret:
feat(ios): add check-in flow with AI coachingfix(api): cap breakthroughs to meaningful clusterschore: update AI prompts and dashboard cleanuprefactor(shared): simplify impulse classification modeldocs: add CI/CD complete guideFormat: <type>(<scope>): <beskrivelse>
Branch Protection
heading.anchorLabel- CI Gate required: PR kan ikke merges med mindre CI Gate er gronn
- Aldri push direkte til main: All kode gar via PR
- Squash merge anbefalt: Holder commit-historikken ren
9. Claude Code Integration
heading.anchorLabelClaude Code har innebygde kommandoer som mapper til CI/CD-pipelinen:
| Kommando | Hva den gjor | Mapper til |
|---|---|---|
/deploy-prod | Promoterer staging til production | git push origin main:production |
/release ios [patch|minor|major] | iOS versjonsbump + TestFlight | fastlane ios bump + git tag v* |
/promote | Promoterer TestFlight-bygg til App Store | fastlane ios promote |
/deploy-status | Viser status pa siste deploys | gh run list |
/pr | Oppretter PR med sammendrag | GitHub PR + trigger CI |
10. Daglig arbeidsflyt — Steg for steg
heading.anchorLabelMorgen: Sjekk status
heading.anchorLabel# Sjekk om noe har feilet i nattgh run list --limit 5
# Eller via Claude Code/deploy-statusUnder dagen: Feature-utvikling
heading.anchorLabel-
Lag feature branch
Terminal window git checkout -b feat/min-nye-feature -
Utvikle og commite
Terminal window # Jobb pa koden...git add -Agit commit -m "feat(ios): add awesome feature" -
Push og la CI gjore jobben
Terminal window git push -u origin feat/min-nye-feature# CI starter automatisk
Klar for merge
heading.anchorLabel-
Opprett PR
Terminal window # Via Claude Code/pr# Eller manueltgh pr create --fill -
Vent pa CI Gate — gronn checkmark i GitHub
-
Merge til main -> staging deployes automatisk
Klar for production (DB + API)
heading.anchorLabel-
Verifiser at staging fungerer
Terminal window # Sjekk staging-deploygh run list --branch main --limit 3 -
Promoter til production
Terminal window # Via Claude Code:/deploy-prod# Eller manuelt:git push origin main:production -
Verifiser production — sjekk Railway logs og API-respons
iOS-release (separat syklus)
heading.anchorLabel-
Bump versjon og send til TestFlight
Terminal window cd apps/mobile-kmp/iosAppbundle exec fastlane ios bump type:patch# Git tag v* opprettes automatisk -> TestFlight-bygg starter -
Test pa TestFlight — appen dukker opp etter 15-30 min
-
Promoter til App Store
Terminal window cd apps/mobile-kmp/iosAppbundle exec fastlane ios promote -
Submit for review i App Store Connect (manuelt steg)
11. Feilsoking
heading.anchorLabelNar CI feiler
heading.anchorLabelDatabase-sjekk feiler
heading.anchorLabelVanligste arsak: Genererte typer er utdaterte.
# Fix: Regenerer types lokalt og commitpnpm db:typesgit add packages/database/types/database.tsgit commit -m "chore: update generated database types"API-sjekk feiler
heading.anchorLabelVanligste arsaker: TypeScript type errors, lint-feil, testfeil.
# Kjor lokalt for a reproduserepnpm --filter api lintpnpm --filter api type-checkpnpm --filter api testiOS preflight feiler
heading.anchorLabelVanligste arsaker: KMP kompileringsfeil, Xcode build-feil.
# Rask KMP-sjekk lokaltcd apps/mobile-kmp./gradlew :shared:compileKotlinIosSimulatorArm64
# Full preflightcd iosAppbundle exec fastlane ios preflightNar deploy feiler
heading.anchorLabelDatabase-migrasjon feiler i staging/production
heading.anchorLabel- Sjekk loggen i GitHub Actions for a se den eksakte feilen
- Kjor dry-run via manuell workflow: Actions -> “DB Deploy (manual)” -> velg miljo -> “dry-run”
- Fiks migrasjonsfilen lokalt, test med
pnpm db:reset - Commit og push — CI + staging deploy kjorer pa nytt
iOS TestFlight-upload feiler
heading.anchorLabel- Sjekk signing: Er Match-sertifikatene gyldige? Kjor
fastlane ios doctor - Sjekk Doppler: Er ASC_KEY_ID, ASC_ISSUER_ID, ASC_PRIVATE_KEY satt for prd?
- Timeout? Build har 30 min timeout. Sjekk om Gradle-cache mangler.
- Force retry: Actions -> “iOS Release (manual)” -> velg “beta”
Railway deployer ikke
heading.anchorLabelRailway overvaker branchen direkte. Hvis den ikke deployer:
- Sjekk Railway dashboard for feilmeldinger
- Verifiser at Railway staging er koblet til
main-branchen - Verifiser at Railway production er koblet til
production-branchen - Sjekk at Doppler-secrets er synkronisert til Railway via integrasjonen (stg -> staging, prd -> production)
Sjekke logger
heading.anchorLabel# Se siste workflow-kjoringergh run list --limit 10
# Se detaljer for en spesifikk kjoringgh run view <run-id>
# Se logger for en feilet jobbgh run view <run-id> --log-failedManuelle fallback-workflows
heading.anchorLabel| Workflow | Hva | Nar |
|---|---|---|
db-deploy.yml | Manuell DB-migrasjon (dry-run eller migrate) mot staging/production | Feilretting, force-migrate, inspeksjon |
ios-release.yml | Manuell iOS-build (beta/promote/release) | Force-release, promote til App Store |
12. Nokkelfiler
heading.anchorLabelWorkflow-filer (GitHub Actions)
heading.anchorLabel| Fil | Trigger | Beskrivelse |
|---|---|---|
.github/workflows/ci.yml | Push/PR til main | Hoved-CI: change detection, parallelle sjekker (DB, API, iOS, Android), CI Gate, staging deploy |
.github/workflows/deploy-production.yml | Push til production branch | Production deploy: DB-migrasjoner + API deploy |
.github/workflows/ios-release.yml | Manuell | Fallback for iOS: beta (force), promote (TestFlight -> App Store), full release |
.github/workflows/db-deploy.yml | Manuell | Fallback for DB: dry-run eller migrate mot staging/production |
Konfigurasjonsfiler
heading.anchorLabel| Fil | Beskrivelse |
|---|---|
doppler.yaml | Lokal Doppler-konfig — kobler prosjektet til “im” med “dev” config |
apps/mobile-kmp/iosApp/fastlane/Fastfile | All iOS build-logikk: preflight, test, beta, promote, release, bump, doctor |
apps/mobile-kmp/iosApp/Gemfile | Ruby-avhengigheter for Fastlane |
packages/database/supabase/ | Supabase-konfig og migrasjonsfiler |
GitHub Secrets (konfigurert i repo Settings)
heading.anchorLabel| Secret | Brukes i | Beskrivelse |
|---|---|---|
DOPPLER_TOKEN_STG | CI + staging deploy | Doppler service token for staging-config |
DOPPLER_TOKEN_PRD | Production deploy | Doppler service token for production-config |
Sist oppdatert: Mars 2026