Gå til indholdet

Deployment og rollback

Produktionsmiljøet er app.groopswork.dk, deployet af deploy_production-jobbet på main-pipelinen (build-serveren, Traefik via compose.ci.yml). Hver review-branch får sin egen isolerede stak på app-<branch-slug>.groopswork.dk. Coolify-opsætningen for eksterne miljøer er beskrevet i DEPLOY.md i repo-roden.

Pipeline

test → build → docs → deployingen test-jobs har allow_failure.

Stage Job Indhold
test backend-test tsc --noEmit (blokerende), prisma migrate deploy, 124 tests (E2E-flows, edge cases, sikkerhed/multi-tenancy/DS-JWT)
test frontend-build ADR-002 token-gate, build-markør-assertion, lint, vite-build
build build-images Bygger og pusher images tagget <branch-slug>/{frontend,backend}:<commit-sha>
docs docs-build mkdocs build --strict — fejler på døde links og sider uden nav
deploy deploy_review / deploy_production docker compose pull && up -d med commit-taggede images
deploy deploy_docs (kun main) Publicerer MkDocs-sitet på https://docs.groopswork.dk

Migrationer

  • Migrationer kører automatisk ved boot (entrypoint.shprisma migrate deploy) og er forward-only. Skriv aldrig destruktive migrationer uden en ledsagende plan i MR'en.
  • Verificeret mod produktionskopi 2026-06-12: dump af groopworks-main-db-1 gendannet i isoleret postgres, prisma migrate deploy → 8 migrationer fundet, "No pending migrations", migrate status → "Database schema is up to date".
  • Test selv en migration mod prod-kopi:
sudo docker exec groopworks-main-db-1 pg_dump -U postgres -d groopswork_db -F c -f /tmp/prodcopy.dump
sudo docker cp groopworks-main-db-1:/tmp/prodcopy.dump /tmp/
sudo docker run -d --rm --name prodcopy --network gw-test \
  -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=test -e POSTGRES_DB=groopswork_db postgres:14-alpine
sudo docker cp /tmp/prodcopy.dump prodcopy:/tmp/ \
  && sudo docker exec prodcopy pg_restore -U postgres -d groopswork_db --no-owner /tmp/prodcopy.dump
sudo docker run --rm --network gw-test -v "$PWD/backend":/app -w /app \
  -e DATABASE_URL=postgresql://postgres:test@prodcopy:5432/groopswork_db \
  oven/bun:1 sh -c "bunx prisma migrate deploy && bunx prisma migrate status"

Rollback-plan

Images er taggede med commit-SHA (<registry>/<branch-slug>/backend:<sha>), så en rollback er en redeploy af den forrige SHA — ingen rebuild.

1. Rollback af applikationen (minutter)

# Find den forrige grønne main-pipeline og dens SHA i GitLab (Pipelines → main)
PREV_SHA=<kort-sha>

cd /sti/til/groopworks-new   # repo-checkout på build-serveren
export CI_REGISTRY_IMAGE=<registry>/root/groopworks-new \
       CI_COMMIT_REF_SLUG=main CI_COMMIT_SHORT_SHA=$PREV_SHA \
       DEPLOY_HOST=app.groopswork.dk ROUTER_NAME=groopworks-prod \
       ROUTER_RULE='Host(`app.groopswork.dk`)'
docker compose -f docker-compose.yml -f compose.ci.yml -p groopworks-main \
  pull frontend backend
docker compose -f docker-compose.yml -f compose.ci.yml -p groopworks-main \
  up -d frontend backend

Alternativt via GitLab-UI'et: åbn den forrige grønne pipeline på main og kør deploy_production-jobbet igen (Retry) — det puller dén pipelines SHA-taggede images.

2. Rollback af databasen (kun hvis en migration skal fortrydes)

Migrationer er forward-only, så database-rollback = gendan fra dump:

# FØR enhver risikabel deploy: tag en dump
sudo docker exec groopworks-main-db-1 pg_dump -U postgres -d groopswork_db -F c -f /tmp/pre-deploy.dump

# Rollback: stop backend, gendan, start forrige image
docker compose -p groopworks-main stop backend
sudo docker exec groopworks-main-db-1 dropdb -U postgres groopswork_db
sudo docker exec groopworks-main-db-1 createdb -U postgres groopswork_db
sudo docker exec groopworks-main-db-1 pg_restore -U postgres -d groopswork_db --no-owner /tmp/pre-deploy.dump
# ...og deploy derefter den forrige app-SHA (trin 1)

Vigtigt: data oprettet mellem dump og rollback går tabt — tag altid en frisk dump umiddelbart før deploys med migrationer, og hold vinduet kort.

3. Dokumentfiler (uploads-volumen)

backend-servicens uploads ligger i en navngiven docker-volume og rulles IKKE tilbage sammen med databasen. Dokument-records uden fil falder tilbage til en blank skabelon (serveDocument), så uoverensstemmelser er ufarlige, men tag en kopi af volumen sammen med dumpen ved større operationer:

sudo docker run --rm --volumes-from groopworks-main-backend-1 -v /tmp:/backup \
  alpine tar czf /backup/uploads-$(date +%F).tgz /app/src/uploads

Sundhedstjek efter deploy/rollback

curl -s https://app.groopswork.dk/api/health        # {"status":"ok",...}
curl -s https://app.groopswork.dk/api/health/deep   # db + onlyoffice