Compare commits

...
Author SHA1 Message Date
simandClaude Sonnet 5.5 95b83bc70a deploy: ai-app in Rollout-Skripte fuer Host 131 aufnehmen
CI / Core-Modul (Build/Vet/Test) (push) Successful in 43s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Successful in 2s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (push) Successful in 2s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Failing after 14s
CI / Web (dms-browser) (push) Failing after 58s
CI / Web (pdf-viewer) (push) Failing after 39s
CI / Web (shl) (push) Failing after 8s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Failing after 30s
CI / Core-Modul (Build/Vet/Test) (pull_request) Successful in 43s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Successful in 3s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (pull_request) Successful in 3s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Failing after 15s
CI / Web (dms-browser) (pull_request) Failing after 51s
CI / Web (pdf-viewer) (pull_request) Failing after 37s
CI / Web (shl) (pull_request) Failing after 7s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Successful in 2m42s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Failing after 49s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Failing after 1m24s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Successful in 8m49s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Successful in 12m49s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Failing after 3s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Failing after 33s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Failing after 5s
sync: ai-app.env-Grundgeruest. provision-secrets: Rolle ai_app, DB ai_app_tenant, Listen-Adresse.
apply: Build, Binaries ai-app/ai-migrate, Migrationen, Unit, Start. healthcheck und selfheal um ai-app erweitert.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-07 23:43:58 +01:00
patrickandClaude Sonnet 5.5 f708d0ea87 ai-app: Deployment-Anbindung (Port 8900, Migrationswerkzeug, systemd-Template)
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (push) Canceled after 0s
CI / Web-Barrierefreiheitspruefung (axe, Tastatur, Reflow, Textabstaende) (pull_request) Canceled after 0s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (push) Successful in 3s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (push) Failing after 15s
CI / Web (pdf-viewer) (push) Failing after 34s
Supply-Chain-Scan (Go) / govulncheck (push) Failing after 17s
CI / Core-Modul (Build/Vet/Test) (push) Successful in 42s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (push) Successful in 2s
CI / Web (dms-browser) (push) Failing after 53s
CI / Web (shl) (push) Failing after 7s
AI-Pflichttest-Gate / pflichttest-gate (pull_request) Successful in 1m57s
CI / Core-Modul (Build/Vet/Test) (pull_request) Successful in 41s
CI / DMS Security-Test-Gate (AC5, Merge-Gate) (pull_request) Successful in 3s
CI / Connect Security-Test-Gate (QA-01 AC4, Merge-Gate) (pull_request) Successful in 2s
CI / DMS-Modul Supply-Chain-Scan (govulncheck) (pull_request) Failing after 15s
CI / Web (dms-browser) (pull_request) Failing after 59s
CI / Web (pdf-viewer) (pull_request) Failing after 51s
CI / Web (shl) (pull_request) Failing after 9s
Core-Schnittstellen-Vertragstests / contract-tests (pull_request) Successful in 6m41s
Supply-Chain-Scan (Go) / govulncheck (pull_request) Failing after 42s
Supply-Chain-Scan (npm) / npm-audit (pull_request) Failing after 1m28s
Core-Pflichttest-Gate / pflichttest-gate (pull_request) Successful in 2m18s
RBAC-Rollenhierarchie-Pflichtgate / rbac-policy-invariant (pull_request) Successful in 2m12s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (push) Failing after 3s
CI / DMS-Modul (Lint/Build/Test/Coverage/Artefakt) (pull_request) Failing after 2s
DB-Integrationstests / db-tests (pull_request) Canceled after 0s
Standard-Port in den fuer ai reservierten Bereich verschoben (9600 belegt
workflow-app). Fortschrittstabelle ai_schema_migrations statt
connect_schema_migrations.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-06 23:07:51 +01:00
12 changed files with 261 additions and 16 deletions

No files matched your search

+1 -1
View File
@@ -49,7 +49,7 @@ import (
const workerPollInterval = 2 * time.Second
const defaultListenAddr = "127.0.0.1:9600"
const defaultListenAddr = "127.0.0.1:8900"
const defaultModel = "default"
type config struct {
+40
View File
@@ -0,0 +1,40 @@
// Command migrate wendet die offenen Postgres-Migrationen des AI-Moduls an.
// Einmal gegen eine frische Datenbank ausfuehren, bevor ai-app startet.
package main
import (
"context"
"log"
"os"
"github.com/jackc/pgx/v5/pgxpool"
"gitea.perlbach24.de/scripte/nexarch/ai/internal/migrate"
)
func main() {
dsn := os.Getenv("NEXARCH_AI_APP_TENANT_DSN")
if dsn == "" {
log.Fatal("migrate: NEXARCH_AI_APP_TENANT_DSN ist erforderlich")
}
dir := "migrations"
if len(os.Args) > 1 {
dir = os.Args[1]
}
ctx := context.Background()
pool, err := pgxpool.New(ctx, dsn)
if err != nil {
log.Fatalf("migrate: datenbankverbindung: %v", err)
}
defer pool.Close()
migrations, err := migrate.Load(dir)
if err != nil {
log.Fatalf("migrate: migrationen laden: %v", err)
}
applied, err := migrate.Up(ctx, pool, migrations)
if err != nil {
log.Fatalf("migrate: migrationen anwenden: %v", err)
}
log.Printf("migrate: %d migration(en) angewendet", len(applied))
}
+26
View File
@@ -0,0 +1,26 @@
# Betrieb: ai-app
Port-Bereich 8900 bis 8999 (`deploy/ports.tsv`), Routenpräfix `/api/ai/v1` (`deploy/routes.tsv`). Secrets gehören ausschließlich in die Umgebung (`/etc/nexarch/ai-app.env`, Rechte 600), nie in Code, Logs oder Dokumentation.
## Einrichten
1. Datenbank und Rolle anlegen (nicht Teil der Units).
2. `/etc/nexarch/ai-app.env` mit den Variablen unten anlegen.
3. Migrationen anwenden: `NEXARCH_AI_APP_TENANT_DSN=... ./migrate ai/migrations` (Fortschrittstabelle `ai_schema_migrations`).
4. Unit aus `deploy/systemd/nexarch-ai-app.service.tmpl` installieren (`__INSTALL_DIR__` ersetzen), `systemctl enable --now nexarch-ai-app`.
5. Health: `GET /healthz`.
Eine Datenbank, die vor ENG-10 mit den AI-Migrationen angelegt wurde, führte den Fortschritt in `connect_schema_migrations`. Ist sie ausschließlich AI-Datenbank, vor dem ersten Lauf `ALTER TABLE connect_schema_migrations RENAME TO ai_schema_migrations;`. Bei gemeinsamer Datenbank mit Connect nicht umbenennen, sondern die AI-Einträge von Hand in die neue Tabelle übertragen.
## Variablen
| Variable | Standard | Wirkung |
|---|---|---|
| `NEXARCH_AI_APP_TENANT_DSN` | Pflicht | Datenbank des AI-Moduls |
| `NEXARCH_AI_APP_SERVICE_TOKEN` | Pflicht | Service-Token, das alle Aufrufer im Header `X-Service-Token` senden |
| `NEXARCH_AI_APP_LISTEN_ADDR` | `127.0.0.1:8900` | Lauschadresse |
| `NEXARCH_AI_APP_MODEL` | `default` | Modellname für Inferenzaufrufe |
| `NEXARCH_AI_APP_POLICY_URL` / `_POLICY_SERVICE_TOKEN` | Pflicht, oder Übergangsschalter | Rechteprüfung der semantischen Suche; Token Pflicht, sobald URL gesetzt |
| `NEXARCH_AI_APP_POLICY_DISABLED` | aus | `1` startet ohne Rechteprüfung (Übergang, Warnlog) |
| `NEXARCH_AI_APP_MODULE_BASE_URLS` | leer | `modul=url,modul2=url2`, Basis-URLs für den Rückschreib-Push |
| `NEXARCH_AI_APP_CORE_BASE_URL` / `_CORE_SERVICE_TOKEN` | leer | Core-Anbindung; ohne sie ist die Objekttyp-Registrierung (GOV-01) deaktiviert |
+40
View File
@@ -0,0 +1,40 @@
# ENG-10 – ai-app: Deployment-Anbindung – Prüfprotokoll
Datum: 2026-11-06. Host: Entwicklungshost 192.168.1.204 (Wegwerf-Rolle/DB `eng10_test`, nach Abschluss entfernt).
## Befund (Ausgangslage)
- `ai-app` lauschte standardmäßig auf `127.0.0.1:9600`, außerhalb des für `ai` reservierten Bereichs 8900 bis 8999 (`deploy/ports.tsv`). 9600 belegt außerdem `workflow-app` (`docs/BETRIEB-PORTAL.md`). `scripts/check-port-defaults.sh` erkennt nur `":NNNN"`-Literale und meldete den Verstoß nicht.
- Kein systemd-Template für `ai-app` (Connect und DMS haben eines).
- Kein Migrationswerkzeug für das AI-Modul; `ai/internal/migrate` führte den Fortschritt in der Tabelle `connect_schema_migrations` (Kopierfehler aus dem Connect-Modul).
## Umsetzung
- Standard-Lauschadresse `127.0.0.1:8900`.
- `ai/cmd/migrate` (Muster `connect/cmd/migrate`, DSN aus `NEXARCH_AI_APP_TENANT_DSN`, Verzeichnis als Argument).
- Fortschrittstabelle `ai_schema_migrations`.
- `deploy/systemd/nexarch-ai-app.service.tmpl` nach dem Muster von `nexarch-connect-app` (gleiche Härtung).
- `ai/docs/BETRIEB-UMGEBUNGSVARIABLEN.md` mit Einrichtungsschritten und Variablen.
## Akzeptanzkriterien
| # | Kriterium | Ergebnis |
|---|---|---|
| 1 | Standard-Port liegt im Bereich von `ai` | **Erfüllt.** 8900. `scripts/check-port-defaults.sh` meldet für `ai/cmd/ai-app` nichts (dort erkennt es allerdings das Format `127.0.0.1:NNNN` ohnehin nicht, siehe Einschränkungen). |
| 2 | systemd-Template vorhanden und gehärtet | **Erfüllt.** `scripts/check-systemd-hardening.sh`: ok, 18 Dienste geprüft. Start der Unit selbst nicht getestet. |
| 3 | Migrationen anwendbar, idempotent | **Erfüllt.** Frische DB: 16 Migrationen angewendet, zweiter Lauf 0; ohne DSN klare Fehlermeldung, Abbruch. |
| 4 | Eigene Fortschrittstabelle | **Erfüllt.** `ai_schema_migrations` existiert, `connect_schema_migrations` nicht (`TestUp_UsesOwnTrackingTable`, echte DB). |
## Prüfungen vor der Abnahme
| # | Prüfung | Ergebnis |
|---|---|---|
| 1 | Migrationswerkzeug gegen frische Wegwerf-DB | **Bestanden** (siehe AK3). |
| 2 | Bestehende Modultests | **Bestanden.** `./internal/migrate/`, `./cmd/ai-app/` grün, `go build ./...` und `go vet` sauber. |
| 3 | Unit startet `ai-app` real | **Offen.** Template nicht auf einem Host installiert, `systemctl` nicht ausgeführt. |
## Einschränkungen
- Umbenennung der Fortschrittstabelle betrifft bestehende AI-Datenbanken; Hinweis in `BETRIEB-UMGEBUNGSVARIABLEN.md`. Eine automatische Übernahme gibt es nicht.
- Nicht Teil der Kachel: Aufnahme in `deploy/rollout-131-*.sh` (Host-131-Rollout), Provisionierung von DB, Rolle und Secrets.
- Weitere Port-Verstöße außerhalb von `ai`, die beim Prüfen auffielen und nicht behoben wurden: `workflow-app` und `tasks-a11y-fixture` auf 9600 (Bereich 8800 bis 8899), Connect-Fixtures doppelt auf 9500, mehrere Fixtures und `verapdf-sidecar` außerhalb ihrer Bereiche. `check-port-defaults.sh` erkennt `127.0.0.1:NNNN`-Literale nicht; eine Erweiterung würde diese Verstöße sichtbar machen und braucht eine eigene Entscheidung.
+1 -1
View File
@@ -12,7 +12,7 @@ import (
type Migration = cmigrate.Migration
const TrackingTable = "connect_schema_migrations"
const TrackingTable = "ai_schema_migrations"
var migrator = cmigrate.MustNew(TrackingTable)
+41
View File
@@ -0,0 +1,41 @@
package migrate
import (
"context"
"os"
"path/filepath"
"testing"
"gitea.perlbach24.de/scripte/nexarch/common/testdb"
)
func TestUp_UsesOwnTrackingTable(t *testing.T) {
dsn := os.Getenv("TEST_TENANT_DSN")
if dsn == "" {
t.Skip("TEST_TENANT_DSN nicht gesetzt, Integrationstest uebersprungen")
}
pool := testdb.Pool(t, dsn)
dir, err := filepath.Abs("../../migrations")
if err != nil {
t.Fatal(err)
}
migrations, err := Load(dir)
if err != nil {
t.Fatal(err)
}
ctx := context.Background()
if _, err := Up(ctx, pool, migrations); err != nil {
t.Fatal(err)
}
again, err := Up(ctx, pool, migrations)
if err != nil || len(again) != 0 {
t.Fatalf("zweiter lauf soll nichts anwenden: %v %v", again, err)
}
var own, foreign bool
if err := pool.QueryRow(ctx, `SELECT to_regclass('ai_schema_migrations') IS NOT NULL, to_regclass('connect_schema_migrations') IS NOT NULL`).Scan(&own, &foreign); err != nil {
t.Fatal(err)
}
if !own || foreign {
t.Fatalf("fortschrittstabelle: ai=%v connect=%v", own, foreign)
}
}
+28 -8
View File
@@ -20,6 +20,7 @@ REPO_DIR="${NEXARCH_ROLLOUT_REPO_DIR:-/root/nexarch-code}"
ENV_DIR=/etc/nexarch
DMS_INSTALL_DIR="${NEXARCH_DMS_INSTALL_DIR:-/opt/nexarch-dms}"
CONNECT_INSTALL_DIR="${NEXARCH_CONNECT_INSTALL_DIR:-/opt/nexarch-connect}"
AI_INSTALL_DIR="${NEXARCH_AI_INSTALL_DIR:-/opt/nexarch-ai}"
DMS_STORAGE_DIR="${NEXARCH_DMS_STORAGE_DIR:-/var/lib/nexarch-dms/storage}"
DMS_STAGING_DIR="${NEXARCH_DMS_STAGING_DIR:-/var/lib/nexarch-dms/staging}"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -50,10 +51,18 @@ require_set() {
return 0
}
echo "== 1. Pruefe die 5 echten TODO-Werte =="
echo "== 1. Pruefe die echten TODO-Werte =="
missing=0
require_set "$ENV_DIR/connect-app.env" NEXARCH_CONNECT_APP_LISTEN_ADDR || missing=1
require_set "$ENV_DIR/connect-app.env" NEXARCH_CONNECT_APP_TENANT_DSN || missing=1
require_set "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_LISTEN_ADDR || missing=1
require_set "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_TENANT_DSN || missing=1
require_set "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_SERVICE_TOKEN || missing=1
if ! require_set "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_POLICY_URL 2>/dev/null \
&& ! grep -q '^NEXARCH_AI_APP_POLICY_DISABLED=1' "$ENV_DIR/ai-app.env" 2>/dev/null; then
echo "OFFEN: NEXARCH_AI_APP_POLICY_URL (mit _POLICY_SERVICE_TOKEN) oder NEXARCH_AI_APP_POLICY_DISABLED=1 in $ENV_DIR/ai-app.env" >&2
missing=1
fi
require_set "$ENV_DIR/dms-app.env" NEXARCH_DMS_APP_CORE_SERVICE_TOKEN || missing=1
require_set "$ENV_DIR/dms-app.env" NEXARCH_DMS_APP_KEK_CLIENT_ID || missing=1
require_set "$ENV_DIR/dms-app.env" NEXARCH_DMS_APP_KEK_CLIENT_SECRET || missing=1
@@ -63,10 +72,10 @@ if [ "$missing" -eq 1 ]; then
echo "Trage die fehlenden Werte von Hand in die genannten Dateien ein und starte das Skript erneut." >&2
exit 1
fi
echo "Alle 5 TODO-Werte sind gesetzt."
echo "Alle TODO-Werte sind gesetzt."
echo "== 2. Build (falls rollout-131-sync.sh das noch nicht getan hat) =="
for mod in dms connect; do
for mod in dms connect ai; do
if [ -f "$REPO_DIR/$mod/go.mod" ]; then
( cd "$REPO_DIR/$mod" && go build ./... && go vet ./... )
echo "gebaut/verifiziert: $mod"
@@ -77,14 +86,16 @@ for mod in dms connect; do
done
echo "== 3. Binaries kopieren =="
mkdir -p "$DMS_INSTALL_DIR/bin" "$CONNECT_INSTALL_DIR/bin"
mkdir -p "$DMS_INSTALL_DIR/bin" "$CONNECT_INSTALL_DIR/bin" "$AI_INSTALL_DIR/bin"
( cd "$REPO_DIR/dms" && go build -o "$DMS_INSTALL_DIR/bin/dms-app" ./cmd/app )
( cd "$REPO_DIR/dms" && go build -o "$DMS_INSTALL_DIR/bin/dms-worker" ./cmd/worker )
( cd "$REPO_DIR/connect" && go build -o "$CONNECT_INSTALL_DIR/bin/connect-app" ./cmd/connect-app )
echo "Binaries liegen unter ${DMS_INSTALL_DIR}/bin und ${CONNECT_INSTALL_DIR}/bin."
( cd "$REPO_DIR/ai" && go build -o "$AI_INSTALL_DIR/bin/ai-app" ./cmd/ai-app )
( cd "$REPO_DIR/ai" && go build -o "$AI_INSTALL_DIR/bin/ai-migrate" ./cmd/migrate )
echo "Binaries liegen unter ${DMS_INSTALL_DIR}/bin, ${CONNECT_INSTALL_DIR}/bin und ${AI_INSTALL_DIR}/bin."
if id nexarch >/dev/null 2>&1; then
chown -R nexarch:nexarch "$DMS_INSTALL_DIR" "$CONNECT_INSTALL_DIR"
chown -R nexarch:nexarch "$DMS_INSTALL_DIR" "$CONNECT_INSTALL_DIR" "$AI_INSTALL_DIR"
else
echo "WARNUNG: Systembenutzer 'nexarch' existiert nicht -- Units werden trotzdem als User=nexarch geschrieben (wie bei Core/Archive ueblich), legen den Benutzer aber nicht an. Falls er fehlt, vor dem Start anlegen: useradd --system --no-create-home --shell /usr/sbin/nologin nexarch" >&2
fi
@@ -129,7 +140,15 @@ else
echo "${ENV_DIR}/dms-worker.env existiert bereits -- wird nicht ueberschrieben."
fi
echo "== 5b. AI-Migrationen anwenden =="
AI_DSN="$(grep '^NEXARCH_AI_APP_TENANT_DSN=' "$ENV_DIR/ai-app.env" | head -n1 | cut -d= -f2-)"
NEXARCH_AI_APP_TENANT_DSN="$AI_DSN" "$AI_INSTALL_DIR/bin/ai-migrate" "$REPO_DIR/ai/migrations"
unset AI_DSN
echo "== 6. systemd-Units installieren =="
sed -e "s#__INSTALL_DIR__#${AI_INSTALL_DIR}#g" \
"$SCRIPT_DIR/systemd/nexarch-ai-app.service.tmpl" > /etc/systemd/system/nexarch-ai-app.service
sed -e "s#__INSTALL_DIR__#${CONNECT_INSTALL_DIR}#g" \
"$SCRIPT_DIR/systemd/nexarch-connect-app.service.tmpl" > /etc/systemd/system/nexarch-connect-app.service
@@ -142,7 +161,7 @@ sed -e "s#__INSTALL_DIR__#${DMS_INSTALL_DIR}#g" \
-e "s#__STORAGE_DIR__#${DMS_STORAGE_DIR}#g" \
"$SCRIPT_DIR/systemd/nexarch-dms-worker.service.tmpl" > /etc/systemd/system/nexarch-dms-worker.service
echo "Units geschrieben: nexarch-connect-app, nexarch-dms-app, nexarch-dms-worker"
echo "Units geschrieben: nexarch-ai-app, nexarch-connect-app, nexarch-dms-app, nexarch-dms-worker"
echo "== 7. daemon-reload =="
systemctl daemon-reload
@@ -167,7 +186,8 @@ if [ "$ok" -ne 1 ]; then
fi
echo "account-api liefert /auth/module-jwks."
echo "== 9. connect-app, dms-app, dms-worker aktivieren und starten =="
echo "== 9. ai-app, connect-app, dms-app, dms-worker aktivieren und starten =="
systemctl enable --now nexarch-ai-app.service
systemctl enable --now nexarch-connect-app.service
systemctl enable --now nexarch-dms-app.service
systemctl enable --now nexarch-dms-worker.service
+4
View File
@@ -37,6 +37,7 @@ DMS_APP_ADDR=$(listen_addr "$ENV_DIR/dms-app.env" NEXARCH_DMS_APP_LISTEN_ADDR "1
DMS_WORKER_METRICS_ADDR=$(listen_addr "$ENV_DIR/dms-worker.env" NEXARCH_DMS_WORKER_METRICS_ADDR "127.0.0.1:8601")
DMS_KOSIT_ADDR=$(listen_addr "$ENV_DIR/dms-worker.env" NEXARCH_DMS_WORKER_KOSIT_ADDR "127.0.0.1:8610")
CONNECT_APP_ADDR=$(listen_addr "$ENV_DIR/connect-app.env" NEXARCH_CONNECT_APP_LISTEN_ADDR "127.0.0.1:9500")
AI_APP_ADDR=$(listen_addr "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_LISTEN_ADDR "127.0.0.1:8900")
echo "== Core (bereits laufend erwartet) =="
check "nexarch-core" "http://127.0.0.1:8080/healthz"
@@ -53,6 +54,9 @@ check "dms-kosit-sidecar" "http://${DMS_KOSIT_ADDR}/healthz"
echo "== Connect (Erstinstallation durch diesen Rollout) =="
check "connect-app" "http://${CONNECT_APP_ADDR}/healthz"
echo "== AI =="
check "ai-app" "http://${AI_APP_ADDR}/healthz"
echo
echo "Hinweis: Adressen werden aus den echten Env-Dateien gelesen"
echo "(NEXARCH_*_LISTEN_ADDR); ohne gesetzten Wert greift der Platzhalter aus"
+38
View File
@@ -13,6 +13,7 @@ set -euo pipefail
CONNECT_ENV=/etc/nexarch/connect-app.env
DMS_ENV=/etc/nexarch/dms-app.env
CORE_ENV=/etc/nexarch/core.env
AI_ENV=/etc/nexarch/ai-app.env
if [ ! -f "$CONNECT_ENV" ] || [ ! -f "$DMS_ENV" ] || [ ! -f "$CORE_ENV" ]; then
echo "Abbruch: eine der Env-Dateien fehlt ($CONNECT_ENV, $DMS_ENV, $CORE_ENV)." >&2
@@ -50,6 +51,42 @@ else
echo "Uebersprungen: NEXARCH_CONNECT_APP_LISTEN_ADDR ist schon gesetzt."
fi
echo
echo "== 1b. AI-DB (Rolle + Datenbank) =="
if [ ! -f "$AI_ENV" ]; then
echo "Uebersprungen: $AI_ENV fehlt (rollout-131-sync.sh zuerst ausfuehren)."
else
if grep -q '^NEXARCH_AI_APP_TENANT_DSN=.*TODO' "$AI_ENV" 2>/dev/null || ! grep -q '^NEXARCH_AI_APP_TENANT_DSN=' "$AI_ENV"; then
PW=$(openssl rand -hex 20)
sudo -u postgres psql -v ON_ERROR_STOP=1 <<SQL
DO \$\$
BEGIN
IF EXISTS (SELECT FROM pg_roles WHERE rolname = 'ai_app') THEN
ALTER ROLE ai_app WITH PASSWORD '${PW}';
ELSE
CREATE ROLE ai_app LOGIN PASSWORD '${PW}';
END IF;
END
\$\$;
SELECT 'CREATE DATABASE ai_app_tenant OWNER ai_app'
WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'ai_app_tenant')\gexec
SQL
sed -i '/^NEXARCH_AI_APP_TENANT_DSN=/d' "$AI_ENV"
echo "NEXARCH_AI_APP_TENANT_DSN=postgresql://ai_app:${PW}@localhost:5432/ai_app_tenant?sslmode=disable" >> "$AI_ENV"
echo "OK: NEXARCH_AI_APP_TENANT_DSN gesetzt."
else
echo "Uebersprungen: NEXARCH_AI_APP_TENANT_DSN ist schon gesetzt."
fi
if grep -q '^NEXARCH_AI_APP_LISTEN_ADDR=.*TODO' "$AI_ENV" 2>/dev/null || ! grep -q '^NEXARCH_AI_APP_LISTEN_ADDR=' "$AI_ENV"; then
sed -i '/^NEXARCH_AI_APP_LISTEN_ADDR=/d' "$AI_ENV"
echo "NEXARCH_AI_APP_LISTEN_ADDR=127.0.0.1:8900" >> "$AI_ENV"
echo "OK: NEXARCH_AI_APP_LISTEN_ADDR gesetzt (127.0.0.1:8900)."
else
echo "Uebersprungen: NEXARCH_AI_APP_LISTEN_ADDR ist schon gesetzt."
fi
echo "OFFEN: NEXARCH_AI_APP_SERVICE_TOKEN und Policy-Anbindung (POLICY_URL/_POLICY_SERVICE_TOKEN oder POLICY_DISABLED=1) setzt der Betreiber von Hand."
fi
echo
echo "== 2. KEK-Client fuer DMS registrieren =="
if grep -q '^NEXARCH_DMS_APP_KEK_CLIENT_ID=.*TODO' "$DMS_ENV" 2>/dev/null; then
@@ -135,3 +172,4 @@ echo
echo "== Zusammenfassung =="
grep -c TODO "$CONNECT_ENV" | xargs -I{} echo "connect-app.env: {} offene TODOs"
grep -c TODO "$DMS_ENV" | xargs -I{} echo "dms-app.env: {} offene TODOs"
[ -f "$AI_ENV" ] && { grep -c TODO "$AI_ENV" | xargs -I{} echo "ai-app.env: {} offene TODOs" || true; }
+13 -6
View File
@@ -17,10 +17,12 @@ REPO_DIR="${NEXARCH_ROLLOUT_REPO_DIR:-/root/nexarch-code}"
ENV_DIR=/etc/nexarch
DMS_INSTALL_DIR="${NEXARCH_DMS_INSTALL_DIR:-/opt/nexarch-dms}"
CONNECT_INSTALL_DIR="${NEXARCH_CONNECT_INSTALL_DIR:-/opt/nexarch-connect}"
AI_INSTALL_DIR="${NEXARCH_AI_INSTALL_DIR:-/opt/nexarch-ai}"
DMS_STORAGE_DIR="${NEXARCH_DMS_STORAGE_DIR:-/var/lib/nexarch-dms/storage}"
DMS_STAGING_DIR="${NEXARCH_DMS_STAGING_DIR:-/var/lib/nexarch-dms/staging}"
CONNECT_ENV="$ENV_DIR/connect-app.env"
DMS_ENV="$ENV_DIR/dms-app.env"
AI_ENV="$ENV_DIR/ai-app.env"
CORE_ENV="$ENV_DIR/core.env"
MAX_ATTEMPTS=10
@@ -93,7 +95,7 @@ while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
fi
for pair in "$CONNECT_ENV:NEXARCH_CONNECT_APP_TENANT_DSN" "$CONNECT_ENV:NEXARCH_CONNECT_APP_LISTEN_ADDR" \
"$DMS_ENV:NEXARCH_DMS_APP_CORE_SERVICE_TOKEN" "$DMS_ENV:NEXARCH_DMS_APP_KEK_CLIENT_ID" "$DMS_ENV:NEXARCH_DMS_APP_KEK_CLIENT_SECRET"; do
"$AI_ENV:NEXARCH_AI_APP_TENANT_DSN" "$AI_ENV:NEXARCH_AI_APP_LISTEN_ADDR" "$AI_ENV:NEXARCH_AI_APP_SERVICE_TOKEN" "$DMS_ENV:NEXARCH_DMS_APP_CORE_SERVICE_TOKEN" "$DMS_ENV:NEXARCH_DMS_APP_KEK_CLIENT_ID" "$DMS_ENV:NEXARCH_DMS_APP_KEK_CLIENT_SECRET"; do
f="${pair%%:*}"; n="${pair#*:}"
if is_open "$f" "$n"; then
blockers+=("${n} in ${f} ist weiterhin offen -- braucht einen externen Wert, den nur der Nutzer kennt (kein Konfigurationsfehler, den dieses Skript loesen darf).")
@@ -125,7 +127,7 @@ while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
done
log "== Zielverzeichnisse pruefen =="
for d in "$DMS_INSTALL_DIR/bin" "$CONNECT_INSTALL_DIR/bin" "$DMS_STORAGE_DIR" "$DMS_STAGING_DIR"; do
for d in "$DMS_INSTALL_DIR/bin" "$CONNECT_INSTALL_DIR/bin" "$AI_INSTALL_DIR/bin" "$DMS_STORAGE_DIR" "$DMS_STAGING_DIR"; do
if [ ! -d "$d" ]; then
mkdir -p "$d"
log "repariert: Verzeichnis $d angelegt."
@@ -133,13 +135,15 @@ while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
fi
done
if id nexarch >/dev/null 2>&1; then
chown -R nexarch:nexarch "$DMS_INSTALL_DIR" "$CONNECT_INSTALL_DIR" "$DMS_STORAGE_DIR" "$DMS_STAGING_DIR" 2>/dev/null || true
chown -R nexarch:nexarch "$DMS_INSTALL_DIR" "$CONNECT_INSTALL_DIR" "$AI_INSTALL_DIR" "$DMS_STORAGE_DIR" "$DMS_STAGING_DIR" 2>/dev/null || true
fi
log "== Binaries pruefen (nachbauen falls sie fehlen) =="
for triple in "$DMS_INSTALL_DIR/bin/dms-app:$REPO_DIR/dms:./cmd/app" \
"$DMS_INSTALL_DIR/bin/dms-worker:$REPO_DIR/dms:./cmd/worker" \
"$CONNECT_INSTALL_DIR/bin/connect-app:$REPO_DIR/connect:./cmd/connect-app"; do
"$CONNECT_INSTALL_DIR/bin/connect-app:$REPO_DIR/connect:./cmd/connect-app" \
"$AI_INSTALL_DIR/bin/ai-app:$REPO_DIR/ai:./cmd/ai-app" \
"$AI_INSTALL_DIR/bin/ai-migrate:$REPO_DIR/ai:./cmd/migrate"; do
bin="${triple%%:*}"; rest="${triple#*:}"; moddir="${rest%%:*}"; pkg="${rest#*:}"
if [ ! -x "$bin" ]; then
if [ -f "$moddir/go.mod" ]; then
@@ -190,7 +194,7 @@ while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
fi
log "== systemd-Unit-Dateien pruefen (nur Datei-Kopie, kein systemctl) =="
for unit in nexarch-connect-app nexarch-dms-app nexarch-dms-worker; do
for unit in nexarch-ai-app nexarch-connect-app nexarch-dms-app nexarch-dms-worker; do
tmpl="$SCRIPT_DIR/systemd/${unit}.service.tmpl"
dest="/etc/systemd/system/${unit}.service"
if [ ! -f "$tmpl" ]; then
@@ -199,6 +203,9 @@ while [ "$attempt" -lt "$MAX_ATTEMPTS" ]; do
fi
if [ ! -f "$dest" ] || grep -q '__INSTALL_DIR__\|__STORAGE_DIR__\|__STAGING_DIR__' "$dest" 2>/dev/null; then
case "$unit" in
nexarch-ai-app)
sed -e "s#__INSTALL_DIR__#${AI_INSTALL_DIR}#g" "$tmpl" > "$dest"
;;
nexarch-connect-app)
sed -e "s#__INSTALL_DIR__#${CONNECT_INSTALL_DIR}#g" "$tmpl" > "$dest"
;;
@@ -234,7 +241,7 @@ if [ "$ready" -eq 1 ]; then
echo " systemctl daemon-reload"
echo " systemctl restart nexarch-account-api"
echo " sleep 3 && curl -sf http://127.0.0.1:8099/auth/module-jwks && echo OK"
echo " systemctl enable --now nexarch-connect-app nexarch-dms-app nexarch-dms-worker"
echo " systemctl enable --now nexarch-ai-app nexarch-connect-app nexarch-dms-app nexarch-dms-worker"
echo " $SCRIPT_DIR/rollout-131-healthcheck.sh"
echo
echo "(Alternativ deckt deploy/rollout-131-apply.sh genau diese Schritte in einem Lauf ab.)"
+6
View File
@@ -67,6 +67,12 @@ echo "-- connect-app.env (neu, Connect API-02) --"
ensure_var "$ENV_DIR/connect-app.env" NEXARCH_CONNECT_APP_LISTEN_ADDR "z.B. 127.0.0.1:9500"
ensure_var "$ENV_DIR/connect-app.env" NEXARCH_CONNECT_APP_TENANT_DSN "Postgres-DSN fuer den Connect-Mandanten"
echo "-- ai-app.env (neu, ENG-10) --"
ensure_var "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_LISTEN_ADDR "z.B. 127.0.0.1:8900"
ensure_var "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_TENANT_DSN "Postgres-DSN fuer die AI-Datenbank"
ensure_var "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_SERVICE_TOKEN "Token, das alle Aufrufer im Header X-Service-Token senden -- muss zu den Aufrufern passen"
ensure_var "$ENV_DIR/ai-app.env" NEXARCH_AI_APP_POLICY_URL "policy-api-Adresse fuer die Rechtepruefung der Suche (alternativ NEXARCH_AI_APP_POLICY_DISABLED=1 als Uebergang)"
echo "-- dms-app.env (Ergaenzungen aus dieser Session gehaerteter Konfiguration) --"
# Pflicht zum Start ueberhaupt (TENANT_DSN/TENANT_SLUG waren auf 131 bei der
# Bestandsaufnahme bereits gesetzt, hier nur zur Vollstaendigkeit abgesichert):
@@ -0,0 +1,23 @@
[Unit]
Description=NEXARCH AI - ai-app (ENG-10)
After=network.target postgresql.service
Wants=postgresql.service
[Service]
Type=simple
User=nexarch
Group=nexarch
EnvironmentFile=/etc/nexarch/ai-app.env
ExecStart=__INSTALL_DIR__/bin/ai-app
Restart=on-failure
RestartSec=3
WorkingDirectory=__INSTALL_DIR__
# QA-15 F-13/OPS-08: reiner Netzwerkdienst (HTTP + Postgres-DSN aus
# EnvironmentFile), keine eigene Schreibarbeit im Dateisystem.
NoNewPrivileges=true
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
[Install]
WantedBy=multi-user.target