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 → deploy — ingen 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.sh→prisma 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-1gendannet 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