Betrieb: Dockge-Stack, Images, Prüfung

compose.yaml aus docs/11-betrieb.md, ergänzt um Healthchecks für db-backup und
offsite-backup. Das Dokument verlangt für jeden Dienst einen, die abgedruckte
Fassung hatte für die beiden keinen, und ohne ihn zeigt Dockge nur "läuft",
auch wenn seit Wochen nichts mehr gesichert wird.

Die Migration läuft im Startkommando von web, nicht in einem Init-Container.
Die Prisma-CLI samt Schema-Engine liegt dafür unter /app/migrator im Image:
ein Container, der nur startet, wenn gerade eine Registry erreichbar ist, wäre
auf einem Homeserver die falsche Bauart.

Alle drei Images gebaut und laufen gegen eine echte Postgres-Instanz geprüft:
web wendet Migrationen an und liefert /api/health aus, worker schreibt sein
Lebenszeichen, pdf rendert ein echtes PDF.

Die CI prüft Lint, Typen, Tests und E2E gegen den Standalone-Server, also so,
wie der Container startet, und hält das Bündel-Budget aus
docs/09-performance-und-ux.md ein.

Phase 0 aus TASKS.md ist damit abgehakt.
This commit is contained in:
Harlekin
2026-09-01 00:02:00 +02:00
parent 8375d1cb03
commit f77a589dda
8 changed files with 647 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
name: Prüfung
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
pruefen:
name: Lint, Typen, Tests
runs-on: ubuntu-latest
services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_DB: afis
POSTGRES_USER: afis
POSTGRES_PASSWORD: afis
ports: ['5432:5432']
options: >-
--health-cmd "pg_isready -U afis -d afis"
--health-interval 10s --health-timeout 5s --health-retries 5
env:
DATABASE_URL: postgresql://afis:afis@localhost:5432/afis
DIRECT_DATABASE_URL: postgresql://afis:afis@localhost:5432/afis
APP_URL: http://127.0.0.1:3100
AUTH_SECRET: nur-fuer-die-pruefung-mindestens-32-zeichen-lang
DISCORD_CLIENT_ID: pruefung
DISCORD_CLIENT_SECRET: pruefung
DISCORD_BOT_TOKEN: pruefung
DISCORD_GUILD_ID: '0'
NEXT_TELEMETRY_DISABLED: '1'
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
# Erzeugt den Prisma-Client nach packages/db/src/generated und übersetzt
# @afis/db. Muss vor lint, typecheck und test laufen.
- name: Datenbankpaket bauen
run: pnpm --filter @afis/db run build
- name: Datenbank aufbauen
run: pnpm db:deploy
- run: pnpm db:seed
- run: pnpm lint
- run: pnpm typecheck
# Die Regeltests in packages/db laufen gegen die echte Postgres-Instanz.
- run: pnpm test
- name: Playwright-Browser
run: pnpm --filter @afis/web exec playwright install --with-deps chromium
# Baut die Anwendung und prüft sie über den Standalone-Server, also genau
# so, wie der Container sie startet.
- run: pnpm test:e2e
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report
path: web/playwright-report/
retention-days: 7
# Budget aus docs/09-performance-und-ux.md: erste Route unter 120 kB
# JavaScript nach Kompression.
- name: Bündelgröße prüfen
run: pnpm --filter @afis/web exec node ../scripts/check-bundle-budget.mjs
images:
name: Images bauen
runs-on: ubuntu-latest
needs: pruefen
if: github.event_name == 'pull_request'
strategy:
fail-fast: false
matrix:
dienst: [web, worker, pdf]
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
# Auf Pull Requests nur bauen, nicht schieben. Das Schieben macht
# .github/workflows/images.yml auf main.
- uses: docker/build-push-action@v6
with:
context: .
file: docker/${{ matrix.dienst }}.Dockerfile
push: false
cache-from: type=gha,scope=${{ matrix.dienst }}
cache-to: type=gha,mode=max,scope=${{ matrix.dienst }}
+62
View File
@@ -0,0 +1,62 @@
name: Images
# Baut die drei Images und schiebt sie in die GitHub Container Registry.
# Dockge zieht sie beim Update, siehe docs/11-betrieb.md.
on:
push:
branches: [main]
tags: ['v*']
workflow_dispatch:
env:
REGISTRY: ghcr.io
jobs:
bauen:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
strategy:
fail-fast: false
matrix:
include:
- dienst: web
dockerfile: docker/web.Dockerfile
- dienst: worker
dockerfile: docker/worker.Dockerfile
- dienst: pdf
dockerfile: docker/pdf.Dockerfile
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository_owner }}/afis-${{ matrix.dienst }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=sha,format=short
type=raw,value=latest,enable={{is_default_branch}}
- uses: docker/build-push-action@v6
with:
context: .
file: ${{ matrix.dockerfile }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.dienst }}
cache-to: type=gha,mode=max,scope=${{ matrix.dienst }}