docs: massive restructuring of documentation, development guides and agent playbooks

This commit is contained in:
2026-06-15 12:54:38 +02:00
parent e4988b4397
commit ce63303b2c
686 changed files with 45423 additions and 319 deletions
@@ -0,0 +1,210 @@
---
type: Runbook
status: ACTIVE
owner: QA Specialist
tags: [postman, testing, api, backend]
last_update: 2026-04-03
---
# Runbook: API-Tests mit Postman (für NichtProgrammierer)
> Ziel: Alle Kern-APIs der Meldestelle lokal prüfen sicher, reproduzierbar und ohne Programmierkenntnisse.
Inhalt:
1. Voraussetzungen (Docker-Profile starten)
2. Postman einrichten (Collection + Environment)
3. Login/Token beschaffen
4. SmokeTests (System & Health)
5. PingService durchtesten (ohne/mit Login, Resilience)
6. MasterData & Pferde (Beispiele)
7. Empfohlene TestReihenfolge
8. Troubleshooting & FAQ
---
## 1. Voraussetzungen
Bitte sicherstellen, dass die lokale Umgebung läuft:
- Infrastruktur starten: `docker compose --profile infra up -d`
- Backend starten: `docker compose --profile backend up -d`
StandardPorts (lokal):
- Gateway: `http://localhost:8081` (Einstiegspunkt für alle APIs)
- Keycloak: `http://localhost:8180`
- PingService (direkt): `http://localhost:8082`
- ZNSImport (direkt): `http://localhost:8095`
- Consul: `http://localhost:8500`
Hinweis: Nutze für Postman immer die `gateway_url` (`:8081`), um die Security- und Routing-Logik des Systems zu testen.
---
## 2. Postman einrichten
### 2.1 Collection importieren
1. Postman öffnen → „Import“ → Datei wählen:
```
backend/infrastructure/gateway/src/main/resources/static/docs/postman/Meldestelle_API_Collection.json
```
2. Die Collection „Meldestelle API Collection“ erscheint links.
### 2.2 Environment anlegen (z. B. „Meldestelle Local“)
Trage folgende Variablen ein:
| Variable | Wert (Initial) | Beschreibung |
|---|---|---|
| `gateway_url` | `http://localhost:8081` | APIGateway Einstieg |
| `auth_url` | `http://localhost:8180/realms/meldestelle/protocol/openid-connect/token` | TokenEndpoint |
| `client_id` | `postman-client` | Keycloak Client |
| `client_secret` | `postman-secret-123` | Secret zum Client |
| `username` | `admin` | Testuser |
| `password` | `Admin#1234` | Passwort |
| `ping_url` | `http://localhost:8082` | Direkter PingService |
| `zns_url` | `http://localhost:8095` | Direkter ZNSImport |
| `consul_url` | `http://localhost:8500` | Consul UI |
| `auth_token` | (leer) | Wird nach Login automatisch befüllt |
| `horse_id` | (leer) | Wird bei PferdeTests befüllt |
| `country_id` | (leer) | Wird bei LänderTests befüllt |
---
## 3. Login/Token beschaffen
In Postman im Reiter „Authorization“ (Request „Login“ in der Collection nutzen oder manuell):
- Type: „OAuth 2.0“
- Grant Type: „Password Credentials“
- Access Token URL: `{{auth_url}}`
- Client ID: `{{client_id}}`
- Client Secret: `{{client_secret}}`
- Username: `{{username}}`
- Password: `{{password}}`
- Button „Get New Access Token“ → „Use Token“
Das Token wird im Environment als `auth_token` gespeichert (PreRequest Scripts der Collection setzen es automatisch, sofern vorhanden).
---
## 4. SmokeTests (immer zuerst)
Zweck: Schnell prüfen, ob das System erreichbar und „UP“ ist.
1) APIGateway Info
- Methode: `GET`
- URL: `{{gateway_url}}/actuator/info`
- Auth: Keine
- Erwartet: `200 OK` (leerer JSONBody ist aktuell normal)
2) APIGateway Health
- Methode: `GET`
- URL: `{{gateway_url}}/actuator/health`
- Auth: Keine
- Erwartet: `200 OK` mit `{ "status": "UP" }`
3) OpenAPI (optional)
- Methode: `GET`
- URL: `{{gateway_url}}/v3/api-docs`
- Erwartet: `200 OK` (OpenAPI JSON)
---
## 5. PingService Tests
### 5.1 Öffentlich (ohne Login)
1) Simple Ping
- `GET {{gateway_url}}/api/ping/simple`
- Erwartet: `200 OK` mit `{"status":"pong", ...}`
2) Health
- `GET {{gateway_url}}/api/ping/health`
- Erwartet: `200 OK` mit `{"status":"up", ...}`
3) Public Ping
- `GET {{gateway_url}}/api/ping/public`
- Erwartet: `200 OK`
### 5.2 Sicherheit (NegativTest, ohne Login)
1) Secure Ping (unauthenticated)
- `GET {{gateway_url}}/api/ping/secure`
- Erwartet: `401 Unauthorized`
2) Sync Ping (unauthenticated)
- `GET {{gateway_url}}/api/ping/sync?since=0`
- Erwartet: `401 Unauthorized` (Sicherheit erhöht)
3) Enhanced Ping (unauthenticated)
- `GET {{gateway_url}}/api/ping/enhanced`
- Erwartet: `401 Unauthorized`
### 5.3 Authentifiziert (mit Token)
1) Secure Ping (authenticated)
- `GET {{gateway_url}}/api/ping/secure`
- Auth: OAuth 2.0 (Token)
- Erwartet: `200 OK` mit `{"status":"secure-pong", ...}`
2) Sync Ping (authenticated)
- `GET {{gateway_url}}/api/ping/sync?lastSyncTimestamp=0`
- Erwartet: `200 OK` (Liste von Events)
### 5.4 Resilience (Circuit Breaker Demo)
1) Enhanced Ping (normal)
- `GET {{gateway_url}}/api/ping/enhanced``200 OK`
2) Enhanced Ping (Fehler provozieren)
- `GET {{gateway_url}}/api/ping/enhanced?simulate=true` mehrfach senden
- Erwartet: teils `500`, danach FallbackAntwort mit `circuitBreakerState: "OPEN"`
---
## 6. MasterData & Pferde (Beispiele)
Hinweis: Endpunkte können sich ändern. Maßgeblich ist die OpenAPI unter `{{gateway_url}}/v3/api-docs` sowie die importierte PostmanCollection.
### 6.1 Countries
- Create: `POST {{gateway_url}}/api/masterdata/countries` (Body siehe Collection)
- Read: `GET {{gateway_url}}/api/masterdata/countries/{{country_id}}`
- Erwartet: `201 Created` bei Anlage, `200 OK` beim Lesen.
### 6.2 Horse Registry
- Create: `POST {{gateway_url}}/api/horses` → speichert `{{horse_id}}`
- Get: `GET {{gateway_url}}/api/horses/{{horse_id}}`
- Delete (optional): `DELETE {{gateway_url}}/api/horses/{{horse_id}}`
---
## 7. Empfohlene TestReihenfolge (Checkliste)
1) Infrastruktur & Backend starten (Docker Profiles)
2) Collection importieren, Environment setzen
3) SmokeTests (Info, Health, OpenAPI)
4) Ping öffentlich (simple, health, public)
5) NegativTests (secure/sync ohne Token → 401)
6) Login/Token holen
7) Ping authentifiziert (secure/sync)
8) Resilience testen (enhanced, simulate=true)
9) Optionale DomänenTests (Countries, Horses)
---
## 8. Troubleshooting & FAQ
- 401 Unauthorized trotz Login:
- Token wirklich gesetzt? In Postman „Use Token“ klicken; im Request unter „Authorization“ prüfen.
- Uhrzeit/Zeitzone korrekt? Abgelaufene Tokens werden abgewiesen.
- 502/503 vom Gateway:
- Service wirklich „UP“? `{{gateway_url}}/actuator/health` und ContainerLogs prüfen: `docker compose ps` / `docker compose logs -f <service>`
- Keycloak nicht erreichbar:
- Warten Sie nach Start 3060 Sekunden. Prüfen: `http://localhost:8180`.
- OpenAPI leer oder 404:
- Backend neu gestartet? Warten, bis Gateway die Routen geladen hat.
Weitere Details und Hintergründe finden Sie in der ursprünglichen, technischen Langfassung der QADokumentation (siehe ArchivHinweis unten).
---
Quellen & Verweise:
- PostmanCollection: `backend/infrastructure/gateway/src/main/resources/static/docs/postman/Meldestelle_API_Collection.json`
- BackendReferenz: `docs/05_Backend/Services/PingService_Reference.md`
- OpenAPI: `{{gateway_url}}/v3/api-docs`
ArchivHinweis:
- Die frühere, sehr detaillierte Arbeitsversion „Postman Tests — Vollständige Dokumentation“ aus dem AgentsBesprechungsordner wurde in dieses Runbook konsolidiert und ins Archiv verschoben.
@@ -0,0 +1,20 @@
---
type: Index
status: ACTIVE
owner: Curator
last_update: 2026-04-03
---
# Runbooks & Betriebsanleitungen
Dieser Ordner ist der zentrale Ablageort für alle Betriebsanleitungen (Runbooks) und Schritt-für-SchrittGuides, die auch von NichtProgrammierern genutzt werden können.
- Zielgruppe: Operations, Tester, Fachexperten, Auditoren
- Prinzip: DocsasCode, offlinefähig, reproduzierbar
Struktur:
- Postman & APITests: `POSTMAN_API_Tests_Runbook.md`
- Zora/Infra Setup: `zora-setup-runbook.md`
- Weitere Runbooks: jeweils als eigenständige MarkdownDatei in diesem Verzeichnis
Archivierung:
- Veraltete oder ersetzte Dokumente werden nach `docs/99_Journal/_archive/` oder in das jeweilige Themen`_archive/` verschoben und hier nicht mehr geführt.
@@ -0,0 +1,104 @@
# 🐎 ZNS-Importer Test-Anleitung (Runbook)
Diese Anleitung beschreibt den Prozess, um den ZNS-Importer in einer lokalen Entwicklungsumgebung zu starten und mit Postman vollständig zu testen.
## 1. Infrastruktur starten (Docker)
Bevor der Service gestartet werden kann, müssen die Basis-Dienste (Datenbank, Discovery, Auth) laufen.
### 1.1 Docker Container starten
Öffne ein Terminal im Projekt-Root (`/mocode/Meldestelle`) und führe folgenden Befehl aus:
```bash
docker compose up -d postgres consul keycloak valkey zipkin
```
### 1.2 Status prüfen
Stelle sicher, dass alle Container "healthy" sind:
* **PostgreSQL:** `localhost:5432`
* **Consul UI:** [http://localhost:8500](http://localhost:8500) (Hier muss der Status aller Dienste grün sein)
---
## 2. Backend Services starten
Der ZNS-Importer benötigt den `masterdata-service` (für die Datenbank-Tabellen) und den `zns-import-service`.
### 2.1 Masterdata Service (DB-Migrationen)
Starte den Masterdata-Service, damit die Tabellen (Verein, Reiter, Pferd, Funktionär) angelegt werden:
```bash
./gradlew :backend:services:masterdata:masterdata-service:bootRun
```
*Warte bis im Log erscheint: `Started MasterdataServiceApplication`*
### 2.2 ZNS-Import Service
Starte den Import-Service in einem neuen Terminal:
```bash
./gradlew :backend:services:zns-import:zns-import-service:bootRun
```
*Warte bis im Log erscheint: `Started ZnsImportServiceApplication`*
---
## 3. Postman Test-Ablauf
### 3.1 Health-Check (Optionaler Smoke-Test)
Prüfe ob der Service erreichbar ist:
* **Methode:** `GET`
* **URL:** `http://localhost:8095/actuator/health`
* **Erwartetes Ergebnis:** `{"status":"UP"}`
### 3.2 ZNS-ZIP Upload (Import starten)
Dieser Schritt lädt die ZNS-Daten (ZIP-Datei mit .DAT Files) hoch und startet den asynchronen Prozess.
* **Methode:** `POST`
* **URL:** `http://localhost:8095/api/v1/import/zns`
* **Body:** `form-data`
* Key: `file`
* Type: `File`
* Value: Wähle deine `ZNS_EXPORT.zip` aus.
* **Erwartete Antwort (202 Accepted):**
```json
{
"jobId": "7d3a...-..."
}
```
*(Kopiere die `jobId` für den nächsten Schritt!)*
### 3.3 Status Polling
Da der Import im Hintergrund läuft, musst du den Status abfragen:
* **Methode:** `GET`
* **URL:** `http://localhost:8095/api/v1/import/zns/{jobId}/status`
* **Erwartete Antwort (währenddessen):** `status: "VERARBEITUNG"`
* **Erwartete Antwort (Erfolg):**
```json
{
"jobId": "...",
"status": "ABGESCHLOSSEN",
"fortschritt": 100,
"meldungen": ["Import erfolgreich: 4 Dateien verarbeitet (150 Reiter, 200 Pferde, ...)"]
}
```
---
## 4. Erfolgskontrolle (Nach dem Import)
### 4.1 Datenbank prüfen (pgAdmin / SQL)
Prüfe in der Tabelle `reiter` oder `horse`, ob Daten vorhanden sind:
```sql
SELECT count(*) FROM reiter;
SELECT * FROM horse LIMIT 10;
```
### 4.2 Archiv-Ordner
Prüfe ob die Datei erfolgreich archiviert wurde:
* Pfad (laut `application.yaml`): `/data/zns/archive` (oder der konfigurierte Pfad)
* Die Datei sollte `zns_import_YYYYMMDD_HHMMSS.zip` heißen.
## 5. Troubleshooting
* **404 Not Found:** Prüfe ob der Service auf Port 8095 läuft.
* **500 Internal Server Error:** Prüfe die Konsolenausgabe des `zns-import-service` auf Stacktraces.
* **Import bleibt bei 0% hängen:** Prüfe ob die ZIP-Datei die richtigen Dateinamen enthält (z.B. `VEREIN01.DAT`, `LIZENZ01.DAT`).
@@ -0,0 +1,132 @@
---
type: Guide
status: ACTIVE
owner: DevOps Engineer
last_update: 2026-03-15
---
# Runbook: Lokale Entwicklungsumgebung
Dieses Dokument beschreibt, wie die Docker-basierte lokale Entwicklungsumgebung für das Projekt "Meldestelle" verwendet wird.
## 1. Voraussetzungen
- Docker und Docker Compose müssen installiert sein.
- Eine `.env`-Datei muss im Projekt-Root vorhanden sein. Eine Vorlage befindet sich in `.env.example`.
## 2. Starten der Umgebung
Die Docker-Compose-Konfiguration verwendet [Profile](https://docs.docker.com/compose/profiles/), um das Starten von verschiedenen Teilen des Systems zu ermöglichen.
### 2.1. Vollständiger Start (All-in-One)
Dieser Befehl startet alle definierten Services, einschließlich der Kerninfrastruktur, Backend-Services, Frontend und Monitoring-Tools.
```bash
docker-compose --profile all up --build -d
```
- `--build`: Baut die Images vor dem Start neu, falls Änderungen in den Dockerfiles oder im Quellcode vorliegen.
- `-d`: Startet die Container im "detached" Modus (im Hintergrund).
### 2.2. Nur Backend-Entwicklung
Wenn Sie nur an den Backend-Services arbeiten, können Sie die GUI- und Monitoring-Komponenten weglassen, um Ressourcen zu sparen.
```bash
docker-compose --profile backend --profile infra up --build -d
```
Dieser Befehl startet:
- Die Kerninfrastruktur (`infra`): `postgres`, `redis`, `keycloak`, `consul`.
- Alle Backend-Services (`backend`): `api-gateway`, `ping-service`, etc.
### 2.3. Nur Frontend-Entwicklung
Wenn Sie primär am Frontend arbeiten, benötigen Sie nur das API-Gateway und die Kerninfrastruktur.
```bash
docker-compose --profile gui --profile infra up --build -d
```
Dieser Befehl startet:
- Die Kerninfrastruktur (`infra`).
- Das `api-gateway`.
- Die `web-app` (Nginx-Server für das Frontend).
## 3. Stoppen der Umgebung
Um alle laufenden Container des Projekts zu stoppen:
```bash
docker-compose down
```
Um die Container zu stoppen und auch die benannten Volumes (Datenbankinhalte, etc.) zu löschen:
```bash
docker-compose down -v
```
## 4. Debugging eines Services
Alle Backend-Services sind so konfiguriert, dass sie im Debug-Modus gestartet werden können, wenn die Umgebungsvariable `DEBUG=true` gesetzt ist.
**Beispiel: `ping-service` debuggen**
1. **Setzen der Umgebungsvariable:**
Öffnen Sie die `docker-compose.yaml` und finden Sie den `ping-service`. Fügen Sie unter `environment` die folgende Zeile hinzu oder passen Sie sie an:
```yaml
environment:
# ... andere Variablen
DEBUG: "true"
```
*Hinweis: In der `docker-compose.yaml` ist dies bereits über `${PING_DEBUG:-true}` vorbereitet. Sie können also auch Ihre `.env`-Datei anpassen.*
2. **Port-Mapping:**
Der `ping-service` mappt den Debug-Port `5006` auf den Host.
3. **Starten und Verbinden:**
Starten Sie die Umgebung neu (`docker-compose up -d --build ping-service`). Sie können nun einen Remote-Debugger Ihrer IDE mit dem Host `localhost` und dem Port `5006` verbinden.
## 5. Nützliche Endpunkte und Tools
Wenn die Umgebung mit dem `all`-Profil läuft, sind die folgenden Tools verfügbar:
- **Keycloak Admin Console:** [http://localhost:8180](http://localhost:8180)
- Login: `kc-admin` / `kc-password` (Standard, siehe `.env`)
- **pgAdmin (Datenbank-Tool):** [http://localhost:8888](http://localhost:8888)
- Login: `meldestelle@mo-code.at` / `pgadmin` (Standard, siehe `.env`)
- **Grafana (Monitoring):** [http://localhost:3000](http://localhost:3000)
- Login: `gf-admin` / `gf-password` (Standard, siehe `.env`)
- **Consul UI (Service Discovery):** [http://localhost:8500](http://localhost:8500)
- **API Gateway:** [http://localhost:8081](http://localhost:8081)
- **Web App:** [http://localhost:4000](http://localhost:4000)
- **Mailpit (E-Mail Testing):** [http://localhost:8025](http://localhost:8025)
- Fängt alle E-Mails ab, die von Keycloak oder den Services gesendet werden.
## 6. Fortgeschrittene Anwendungsfälle: Override-Dateien
Im Projekt existieren leere Dateien wie `docker-compose.frontend.yaml` und `docker-compose.services.yaml`. Diese sind absichtlich leer und sollen **nicht** versioniert werden. Sie dienen als persönliche Override-Dateien für lokale Entwicklungsszenarien.
**Zweck:**
Anstatt die zentrale `docker-compose.yaml` zu verändern, können Sie lokale Anpassungen in diesen Dateien vornehmen.
**Beispiel: Frontend-Entwicklung mit Hot-Reload**
Um Hot-Reload für die Nginx-Konfiguration zu aktivieren, können Sie die `docker-compose.frontend.yaml` mit folgendem Inhalt füllen:
```yaml
# docker-compose.frontend.yaml
services:
web-app:
volumes:
- ./config/docker/nginx/web-app/nginx.conf:/etc/nginx/nginx.conf:ro
```
Starten Sie die Umgebung dann mit beiden Dateien:
```bash
docker-compose -f docker-compose.yaml -f docker-compose.frontend.yaml up
```
Docker Compose wird die Konfigurationen zusammenführen, wobei die Definitionen in der `docker-compose.frontend.yaml` Vorrang haben.
@@ -0,0 +1,454 @@
---
type: Runbook
status: ACTIVE
owner: DevOps Engineer
last_update: 2026-03-06
---
# Runbook: Zora — Vollständige Systemkonfiguration
Dieses Runbook beschreibt die vollständige Konfiguration aller drei Zora-Systeme:
**Gitea (CT 101)**, **Gitea-Runner (VM 102)** und **Meldestelle-Host (VM 110)**.
> **Referenz:** `docs/01_Architecture/Minisforum-MS-R1/SSoT_Konfigurations-Masterplan_Zora.md`
---
## Übersicht & IP-Adressen
| System | Typ | IP | Port | Zweck |
|:------------------|:-----|:-------------|:------|:-----------------------------|
| Gitea | LXC | `10.0.0.22` | `3000`| Git-Server + Registry |
| Gitea-Runner | VM | `10.0.0.23` | — | CI/CD ARM64-Builder |
| Meldestelle-Host | VM | `10.0.0.50` | — | Docker App-Stack |
| Proxmox Node | — | `10.0.0.20` | `8006`| Hypervisor Web-UI |
---
## 1. Gitea (CT 101 — `10.0.0.22`)
### 1.1 Erreichbarkeit prüfen
```bash
# Intern (im Heimnetz)
curl -s http://10.0.0.22:3000 | grep -i gitea
# Extern (via Pangolin)
curl -s https://git.mo-code.at | grep -i gitea
```
**Erwartetes Ergebnis:** HTTP 200, Gitea-Login-Seite.
### 1.2 Container-Registry verifizieren
Im Gitea Web-UI (`http://10.0.0.22:3000`):
1. **Einstellungen → Packages** → sicherstellen, dass Packages aktiviert sind.
2. **Organisation `mocode-software` → Packages** → folgende Images müssen vorhanden sein:
- `mocode-software/meldestelle/api-gateway:latest`
- `mocode-software/meldestelle/ping-service:latest`
- `mocode-software/meldestelle/web-app:latest`
- `mocode-software/meldestelle/keycloak:latest`
Falls Images fehlen: Pipeline manuell triggern (Push auf `main` oder Re-Run im Gitea Actions UI).
### 1.3 Org-Secrets prüfen
Im Gitea Web-UI:
**Organisation `mocode-software` → Einstellungen → Secrets & Variables → Actions**
Folgende Secrets müssen gesetzt sein:
| Secret-Name | Wert |
|:-----------------|:----------------------------|
| `REGISTRY_USER` | Gitea-Username des CI-Users |
| `REGISTRY_TOKEN` | Gitea Access-Token (Scope: `package:write`) |
Falls nicht gesetzt:
1. Gitea → Profil → **Settings → Applications → Generate Token**
2. Scope: `package:write` aktivieren
3. Token als `REGISTRY_TOKEN` in Org-Secrets speichern
---
## 2. Gitea-Runner (VM 102 — `10.0.0.23`) — Vollständige Installation
> **Status (06.03.2026):**
> - ✅ `daemon.json` korrekt gesetzt (`insecure-registries: 10.0.0.22:3000`)
> - ❌ `gitea-runner.service` **existiert nicht** — Binary und Service müssen installiert werden!
### 2.1 SSH-Verbindung
```bash
ssh gitearun@10.0.0.23
```
### 2.2 Docker Daemon konfigurieren ✅ (bereits erledigt)
```bash
# Verifizieren — muss bereits korrekt sein:
docker info | grep -A5 "Insecure Registries"
```
**Erwartetes Ergebnis:**
```
Insecure Registries:
10.0.0.22:3000
```
Falls nicht gesetzt:
```bash
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
"insecure-registries": ["10.0.0.22:3000"]
}
EOF
sudo systemctl restart docker
```
### 2.3 Gitea Actions Runner installieren
#### Schritt 1: Registrierungs-Token holen
Im Gitea Web-UI (`http://10.0.0.22:3000`):
**Site Administration → Actions → Runners → Create new Runner**
> Alternativ auf Organisations-Ebene:
> **Organisation `mocode-software` → Einstellungen → Actions → Runners → Create Runner**
Den angezeigten **Registration Token** kopieren (einmalig gültig).
#### Schritt 2: Binary herunterladen (ARM64)
```bash
# Aktuelle Version prüfen: https://gitea.com/gitea/act_runner/releases
ACT_RUNNER_VERSION="0.2.11"
# ARM64-Binary laden (passend zu Zora/MS-R1)
wget -O act_runner "https://gitea.com/gitea/act_runner/releases/download/v${ACT_RUNNER_VERSION}/act_runner-${ACT_RUNNER_VERSION}-linux-arm64"
# Ausführbar machen und in PATH legen
chmod +x act_runner
sudo mv act_runner /usr/local/bin/act_runner
# Verifizieren
act_runner --version
```
#### Schritt 3: Runner registrieren
```bash
# Interaktive Registrierung
act_runner register \
--no-interactive \
--instance http://10.0.0.22:3000 \
--token <REGISTRATION_TOKEN_AUS_SCHRITT_1> \
--name "zora-arm64-runner" \
--labels "ubuntu-latest:docker://node:20-bullseye"
# Ergebnis: .runner Datei im aktuellen Verzeichnis
ls -la .runner
```
> **Wichtig:** Den Runner-Config-Ordner festlegen:
```bash
mkdir -p ~/.gitea-runner
mv .runner ~/.gitea-runner/
```
#### Schritt 4: Systemd-Service anlegen
```bash
sudo tee /etc/systemd/system/gitea-runner.service > /dev/null <<'EOF'
[Unit]
Description=Gitea Actions Runner
After=docker.service
Requires=docker.service
[Service]
Type=simple
User=gitearun
WorkingDirectory=/home/gitearun/.gitea-runner
ExecStart=/usr/local/bin/act_runner daemon
Restart=always
RestartSec=5
Environment="HOME=/home/gitearun"
[Install]
WantedBy=multi-user.target
EOF
# Service aktivieren und starten
sudo systemctl daemon-reload
sudo systemctl enable --now gitea-runner
# Status prüfen
sudo systemctl status gitea-runner
```
**Erwartetes Ergebnis:**
```
● gitea-runner.service - Gitea Actions Runner
Active: active (running)
```
#### Schritt 5: Runner in Gitea bestätigen
Gitea Web-UI → **Site Administration → Actions → Runners**
Der Runner `zora-arm64-runner` muss als **Online** angezeigt werden.
### 2.4 Workflow-Workaround ablösen (optional, nach Verifikation)
Nach erfolgreichem Permanent-Fix kann der manuelle `config.json`-Schritt im Workflow
durch den Standard-`docker/login-action` ersetzt werden.
> **Hinweis:** Erst nach einem erfolgreichen Test-Run mit der neuen `daemon.json` durchführen.
Im Workflow (`.gitea/workflows/docker-publish.yaml`), den Schritt ersetzen:
```yaml
# ALT (Workaround):
- name: Registry-Credentials konfigurieren (kein Daemon-Kontakt)
run: |
mkdir -p ~/.docker
AUTH=$(echo -n "${{ secrets.REGISTRY_USER }}:${{ secrets.REGISTRY_TOKEN }}" | base64 -w 0)
printf '{"auths":{"%s":{"auth":"%s"}}}\n' "${{ env.REGISTRY_INTERNAL }}" "${AUTH}" > ~/.docker/config.json
# NEU (sauber, nach daemon.json-Fix):
- name: Login to Gitea Registry
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY_INTERNAL }}
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_TOKEN }}
```
---
## 3. Meldestelle-Host (VM 110 — `10.0.0.50`)
### 3.1 SSH-Verbindung
```bash
ssh user@10.0.0.50
```
### 3.2 Voraussetzungen prüfen
```bash
# Docker installiert?
docker --version # erwartet: Docker 27+
docker compose version # erwartet: v2.x
# Git installiert?
git --version # erwartet: 2.x
```
Falls Docker nicht installiert:
```bash
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Neu einloggen!
```
### 3.3 Git-Deployment einrichten
```bash
# Projektverzeichnis anlegen
mkdir -p ~/meldestelle && cd ~/meldestelle
# Git initialisieren und mit Gitea verknüpfen
git init
git remote add origin http://10.0.0.22:3000/mocode-software/meldestelle.git
# Neueste Konfiguration holen
git fetch origin
git reset --hard origin/main
# Deployment-Skript ausführbar machen
chmod +x config/scripts/deploy.sh
chmod +x config/scripts/backup.sh
```
### 3.4 Environment-Variablen konfigurieren
> **Status (06.03.2026):** `.env` ist befüllt, aber enthält noch **Placeholder-Passwörter**
> (`pg-password`, `kc-password`, `gf-password`). Diese **müssen** vor dem ersten Start
> durch starke Passwörter (min. 20 Zeichen) ersetzt werden!
```bash
nano .env
```
**Pflichtfelder für Production** (Konfig-Matrix beachten!):
```bash
# --- KEYCLOAK ---
KC_COMMAND=start --optimized --import-realm
KC_HOSTNAME=10.0.0.50
KC_HOSTNAME_STRICT=false
KC_HOSTNAME_STRICT_HTTPS=false
KC_ADMIN_PASSWORD=<SICHERES_PASSWORT_MIN_20_ZEICHEN>
KC_DB_PASSWORD=<SICHERES_PASSWORT_MIN_20_ZEICHEN>
KC_HEAP_MAX=4096m
# --- JWT ---
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_ISSUER_URI=http://10.0.0.50:8180/realms/meldestelle
SPRING_SECURITY_OAUTH2_RESOURCESERVER_JWT_JWK_SET_URI=http://keycloak:8080/realms/meldestelle/protocol/openid-connect/certs
# --- POSTGRES ---
POSTGRES_USER=meldestelle
POSTGRES_PASSWORD=<SICHERES_PASSWORT_MIN_20_ZEICHEN>
POSTGRES_DB=meldestelle
POSTGRES_SHARED_BUFFERS=16GB
POSTGRES_EFFECTIVE_CACHE_SIZE=48GB
# --- VALKEY ---
VALKEY_MAXMEMORY=4gb
VALKEY_PASSWORD=<SICHERES_PASSWORT>
# --- GRAFANA ---
GF_ADMIN_PASSWORD=<SICHERES_PASSWORT>
# --- BACKUP ---
BACKUP_DIR=/home/user/backups/meldestelle
BACKUP_RETENTION_DAYS=7
```
> **Wichtig:** `KC_HOSTNAME` darf auf dem Server **niemals** `localhost` sein!
> Ist Pangolin konfiguriert, kann `KC_HOSTNAME=auth.mo-code.at` gesetzt werden.
### 3.5 Interne Registry konfigurieren
Docker muss die Gitea-Registry intern (HTTP) kennen:
```bash
sudo tee /etc/docker/daemon.json > /dev/null <<'EOF'
{
"insecure-registries": ["10.0.0.22:3000"]
}
EOF
sudo systemctl restart docker
```
### 3.6 Images aus Registry pullen
```bash
cd ~/meldestelle
# Mit Gitea-Registry authentifizieren
docker login 10.0.0.22:3000 -u <REGISTRY_USER> -p <REGISTRY_TOKEN>
# Images pullen
docker pull 10.0.0.22:3000/mocode-software/meldestelle/keycloak:latest
docker pull 10.0.0.22:3000/mocode-software/meldestelle/api-gateway:latest
docker pull 10.0.0.22:3000/mocode-software/meldestelle/ping-service:latest
docker pull 10.0.0.22:3000/mocode-software/meldestelle/web-app:latest
```
### 3.7 Stack starten
```bash
cd ~/meldestelle
# Schritt 1: Infrastruktur (DB, Keycloak, Valkey, Consul)
docker compose -f dc-infra.yaml up -d
echo "Warte 30s auf Keycloak-Start..."
sleep 30
# Schritt 2: Backend (API-Gateway, Ping-Service)
docker compose -f dc-backend.yaml up -d
# Schritt 3: Ops (Prometheus, Grafana, Zipkin)
docker compose -f dc-ops.yaml up -d
```
### 3.8 Smoke-Tests
```bash
# 1. Keycloak Health
curl -s http://10.0.0.50:9000/health/ready | python3 -m json.tool
# Erwartet: {"status": "UP"}
# 2. Keycloak Admin-Dashboard erreichbar
curl -s -o /dev/null -w "%{http_code}" http://10.0.0.50:8180/admin/
# Erwartet: 200
# 3. API-Gateway Ping
curl -s http://10.0.0.50:8081/ping
# Erwartet: {"status":"UP"} o.ä.
# 4. Consul Service Discovery
curl -s http://10.0.0.50:8500/v1/agent/services | python3 -m json.tool
# Erwartet: api-gateway + ping-service registriert
# 5. Grafana erreichbar
curl -s -o /dev/null -w "%{http_code}" http://10.0.0.50:3000
# Erwartet: 200
```
### 3.9 Backup-Cron einrichten
```bash
# Backup-Verzeichnis anlegen
mkdir -p ~/backups/meldestelle
# Cron-Job: täglich um 02:00 Uhr
(crontab -l 2>/dev/null; echo "0 2 * * * /home/user/meldestelle/config/scripts/backup.sh >> /home/user/backups/meldestelle/backup.log 2>&1") | crontab -
# Verifizieren
crontab -l
```
---
## 4. Abschluss-Checkliste
> Stand 06.03.2026 — ✅ = erledigt, ❌ = offen
```
[✅] Gitea erreichbar (intern + extern via Pangolin)
[✅] Registry-Images (4x) vorhanden und aktuell
[✅] Org-Secrets REGISTRY_USER + REGISTRY_TOKEN gesetzt
[✅] VM 102: /etc/docker/daemon.json mit insecure-registries gesetzt
[❌] VM 102: act_runner Binary installiert (/usr/local/bin/act_runner)
[❌] VM 102: gitea-runner.service angelegt, enabled und active
[❌] VM 102: Runner in Gitea als "Online" sichtbar
[⚠️] VM 110: .env befüllt — Placeholder-Passwörter ersetzen!
[✅] VM 110: /etc/docker/daemon.json mit insecure-registries gesetzt (prüfen!)
[❌] VM 110: Stack gestartet (infra + backend + ops)
[❌] Keycloak Health: UP
[❌] Keycloak Admin-Dashboard: erreichbar
[❌] API-Gateway Ping: antwortet
[❌] Grafana: erreichbar
[❌] Backup-Cron: eingerichtet
```
---
## 5. Troubleshooting
### Keycloak startet nicht
```bash
docker logs meldestelle-keycloak --tail 50
```
- `start-dev` statt `start --optimized`? → `.env`: `KC_COMMAND=start --optimized --import-realm`
- `KC_HOSTNAME=localhost` auf Server? → `KC_HOSTNAME=10.0.0.50` setzen
### Docker-Pull schlägt fehl (x509/TLS)
```bash
# daemon.json prüfen
cat /etc/docker/daemon.json
docker info | grep -A5 "Insecure"
# Falls leer: daemon.json nochmals setzen + docker restart
```
### API-Gateway findet Keycloak nicht
```bash
# JWT_ISSUER_URI prüfen
docker exec meldestelle-api-gateway env | grep ISSUER
# Muss sein: http://10.0.0.50:8180/realms/meldestelle (Public)
# JWK_SET_URI muss sein: http://keycloak:8080/... (intern)
```
### Pipeline schlägt fehl (RAM-OOM)
- `max-parallel: 1` im Workflow prüfen — muss immer gesetzt sein auf VM 102 (16 GB RAM).