2 Commits
Author SHA1 Message Date
Felix KemmlerandClaude Sonnet 5 dcc8ea1510 Make omsorgapp's backend URL runtime-configurable, use dedicated API subdomain
Docker-Images bauen und veröffentlichen / build (, omsorgCore/Dockerfile, omsorgcore) (push) Successful in 3s
Docker-Images bauen und veröffentlichen / build (, omsorgWeb/Dockerfile, omsorgweb) (push) Successful in 3s
Docker-Images bauen und veröffentlichen / build (, omsorgapp/Dockerfile, omsorgapp) (push) Successful in 3s
- omsorgapp now reads the omsorgCore URL from a runtime env-config.js
  generated by the container entrypoint from OMSORG_CORE_URL, instead of
  only baking it in at image build time - docker-compose.yml pulls
  pre-built images from the registry, so a build-time-only value couldn't
  be changed without a rebuild.
- docker-compose.yml: omsorgCore gets its own subdomain
  (core.omsorg-pflegedienste.de) rather than being proxied under the
  frontend's domain - omsorgWeb never needs browser-side access to it
  anyway (server-side cURL only), and a dedicated API host is more
  future-proof without being any less secure (backend still only bound to
  127.0.0.1). Includes the nginx server-block snippet needed for the new
  subdomain.
- Drop the now-unused OMSORG_CORE_PUBLIC_URL build-arg wiring from the
  Gitea Actions workflow.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 18:14:32 +02:00
Felix KemmlerandClaude Sonnet 5 2a05c791f5 Use registry images in compose, drop MySQL/named volumes, fix omsorgWeb build
Docker-Images bauen und veröffentlichen / build (, omsorgCore/Dockerfile, omsorgcore) (push) Successful in 3s
Docker-Images bauen und veröffentlichen / build (, omsorgWeb/Dockerfile, omsorgweb) (push) Successful in 3s
Docker-Images bauen und veröffentlichen / build (VITE_OMSORG_CORE_URL=${{ vars.OMSORG_CORE_PUBLIC_URL }}, omsorgapp/Dockerfile, omsorgapp) (push) Successful in 3s
- docker-compose.yml: pull omsorgcore/omsorgapp/omsorgweb from the Gitea
  registry (pinnable via OMSORG_IMAGE_TAG) instead of building locally;
  remove the MySQL service (mitarbeiter-app-legacy is unmaintained legacy
  code) and switch all persistent storage from named Docker volumes to
  bind mounts under /root/data/.
- omsorgWeb/Dockerfile: create the upload/download/etc. directories before
  chown'ing them - they're excluded by .gitignore, so a fresh CI checkout
  doesn't have them and the build failed there (only worked locally because
  of leftover local test files).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-10 17:58:29 +02:00
8 changed files with 111 additions and 69 deletions
+1 -1
View File
@@ -20,7 +20,7 @@ jobs:
build_args: "" build_args: ""
- image: omsorgapp - image: omsorgapp
dockerfile: omsorgapp/Dockerfile dockerfile: omsorgapp/Dockerfile
build_args: "VITE_OMSORG_CORE_URL=${{ vars.OMSORG_CORE_PUBLIC_URL }}" build_args: ""
- image: omsorgweb - image: omsorgweb
dockerfile: omsorgWeb/Dockerfile dockerfile: omsorgWeb/Dockerfile
build_args: "" build_args: ""
+70 -59
View File
@@ -1,12 +1,54 @@
name: omsorg name: omsorg
# WICHTIG (der fehleranfälligste Punkt in diesem Setup): # Zieht fertig gebaute Images aus der Gitea-Registry (siehe .gitea/workflows/docker-build.yml),
# - omsorgapp.build.args.VITE_OMSORG_CORE_URL muss die vom BROWSER erreichbare Adresse von # baut hier bewusst NICHT lokal - die Dockerfiles in omsorgCore/, omsorgapp/, omsorgWeb/ sind
# omsorgcore sein (hier: der auf dem Host published Port), NICHT der interne Compose-DNS-Name - # weiterhin da, werden aber nur noch von der CI verwendet. Vor `docker compose pull`/`up` einmal
# Vite bäckt diese URL zur Build-Zeit in den JS-Bundle ein (siehe omsorgapp/src/api/config.js). # `docker login git.omsorg-pflegedienste.de` auf dem Server ausführen, falls die Images/Packages
# - omsorgweb.environment.OMSORG_CORE_URL ist dagegen der interne Servicename (http://omsorgcore:8080), # nicht öffentlich lesbar sind. Über OMSORG_IMAGE_TAG lässt sich ein bestimmter Versions-Tag
# da PHP dort serverseitig per cURL aufruft (kein Browser-Kontext), siehe # pinnen (z.B. `OMSORG_IMAGE_TAG=v0.1.0 docker compose up -d`), Default ist `latest`.
# omsorgWeb/docker/bootstrap-config.php. #
# omsorgCore bekommt eine eigene Subdomain (core.omsorg-pflegedienste.de), nicht denselben
# Hostnamen wie omsorgapp - Begründung: omsorgWeb (beide mitarbeiter-app*-Apps) braucht ohnehin nie
# Browser-Zugriff auf omsorgCore (PHP ruft serverseitig per cURL auf, siehe
# omsorgWeb/docker/bootstrap-config.php/OMSORG_CORE_URL unten), nur omsorgapp tut das - eine eigene
# Subdomain macht die API trotzdem unabhängig von omsorgapps Hosting adressierbar (künftige
# Clients, Doku, Swagger) und ist nicht unsicherer als Pfad-basiertes Proxying: in beiden Fällen
# ist omsorgCore nur über 127.0.0.1 erreichbar (Port-Mapping unten), nie direkt öffentlich.
# Browser-seitiges Cross-Origin läuft über CORS + HttpOnly-Cookie mit credentials:"include" (siehe
# omsorgCore/CLAUDE.md, Abschnitt "Auth-Flow") - dafür muss Cors__AllowedOrigins__0 unten exakt
# der Origin von omsorgapp entsprechen (https://app.omsorg-pflegedienste.de).
#
# Nginx-Server-Block für die neue Subdomain (analog zum bestehenden app.omsorg-pflegedienste.de-
# Block, eigenes Zertifikat z.B. per `certbot --nginx -d core.omsorg-pflegedienste.de`):
#
# server {
# server_name core.omsorg-pflegedienste.de;
# location / {
# proxy_pass http://127.0.0.1:8080;
# proxy_http_version 1.1;
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
# }
# listen 443 ssl; # managed by Certbot
# ssl_certificate /etc/letsencrypt/live/core.omsorg-pflegedienste.de/fullchain.pem;
# ssl_certificate_key /etc/letsencrypt/live/core.omsorg-pflegedienste.de/privkey.pem;
# include /etc/letsencrypt/options-ssl-nginx.conf;
# ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
# }
#
# Alle persistenten Daten liegen bewusst als Bind-Mounts unter /root/data/ auf der Platte (keine
# benannten Docker-Volumes) - vor dem ersten `docker compose up` einmalig anlegen:
# mkdir -p /root/data/postgres /root/data/omsorgcore/documents \
# /root/data/omsorgweb/{uploads,downloads,fortbildung-materials,avatars,data}
# Postgres läuft im Container als uid 999 (nicht root) - /root/data/postgres muss dieser uid
# gehören, sonst schlägt der Start mit einem Permission-Fehler fehl:
# chown -R 999:999 /root/data/postgres
#
# mitarbeiter-app-legacy (Teil des omsorgweb-Images) ist Legacy-Code und braucht eigentlich MySQL -
# bewusst kein MySQL-Dienst mehr hier, die Legacy-App bleibt dadurch ohne DB-Anbindung (siehe
# omsorgWeb/CLAUDE.md - mitarbeiter-app-legacy wird nicht mehr weiterentwickelt).
services: services:
postgres: postgres:
@@ -16,32 +58,15 @@ services:
POSTGRES_USER: omsorg_core POSTGRES_USER: omsorg_core
POSTGRES_PASSWORD: omsorg_core_dev_password POSTGRES_PASSWORD: omsorg_core_dev_password
volumes: volumes:
- postgres_data:/var/lib/postgresql/data - /root/data/postgres:/var/lib/postgresql/data
healthcheck: healthcheck:
test: ["CMD-SHELL", "pg_isready -U omsorg_core"] test: ["CMD-SHELL", "pg_isready -U omsorg_core"]
interval: 5s interval: 5s
timeout: 5s timeout: 5s
retries: 10 retries: 10
mysql:
image: mysql:8.0
environment:
MYSQL_DATABASE: omsorg_web
MYSQL_USER: omsorg_web
MYSQL_PASSWORD: omsorg_web_dev_password
MYSQL_ROOT_PASSWORD: omsorg_web_root_dev_password
volumes:
- mysql_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 10
omsorgcore: omsorgcore:
build: image: git.omsorg-pflegedienste.de/admin/omsorg/omsorgcore:${OMSORG_IMAGE_TAG:-latest}
context: .
dockerfile: omsorgCore/Dockerfile
depends_on: depends_on:
postgres: postgres:
condition: service_healthy condition: service_healthy
@@ -49,53 +74,39 @@ services:
ASPNETCORE_ENVIRONMENT: Development ASPNETCORE_ENVIRONMENT: Development
ConnectionStrings__OmsorgCore: "Host=postgres;Port=5432;Database=omsorg_core;Username=omsorg_core;Password=omsorg_core_dev_password" ConnectionStrings__OmsorgCore: "Host=postgres;Port=5432;Database=omsorg_core;Username=omsorg_core;Password=omsorg_core_dev_password"
Jwt__Secret: "CHANGE_ME_LOCAL_DEV_SECRET_MIN_32_CHARS_LONG" Jwt__Secret: "CHANGE_ME_LOCAL_DEV_SECRET_MIN_32_CHARS_LONG"
Cors__AllowedOrigins__0: "http://localhost:5173" Cors__AllowedOrigins__0: "https://app.omsorg-pflegedienste.de"
ports: ports:
- "8080:8080" # Nur auf dem Host erreichbar (für den Reverse-Proxy oben), nie auf der öffentlichen
# Schnittstelle - matcht das 127.0.0.1:5173-Muster im bestehenden Host-nginx.
- "127.0.0.1:8080:8080"
volumes: volumes:
- omsorgcore_documents:/app/App_Data/documents - /root/data/omsorgcore/documents:/app/App_Data/documents
omsorgapp: omsorgapp:
build: image: git.omsorg-pflegedienste.de/admin/omsorg/omsorgapp:${OMSORG_IMAGE_TAG:-latest}
context: . environment:
dockerfile: omsorgapp/Dockerfile # Vom BROWSER erreichbare Adresse von omsorgCore - der Container-Entrypoint schreibt das
args: # zur Laufzeit in env-config.js (siehe omsorgapp/docker-entrypoint.sh/src/api/config.js),
VITE_OMSORG_CORE_URL: "http://localhost:8080" # kein Rebuild bei einer geänderten Backend-URL nötig.
OMSORG_CORE_URL: "https://core.omsorg-pflegedienste.de"
ports: ports:
- "5173:80" # Nur auf dem Host, wie omsorgcore oben - der Host-nginx proxied bereits 127.0.0.1:5173.
- "127.0.0.1:5173:80"
depends_on: depends_on:
- omsorgcore - omsorgcore
omsorgweb: omsorgweb:
build: image: git.omsorg-pflegedienste.de/admin/omsorg/omsorgweb:${OMSORG_IMAGE_TAG:-latest}
context: .
dockerfile: omsorgWeb/Dockerfile
depends_on: depends_on:
mysql:
condition: service_healthy
omsorgcore: omsorgcore:
condition: service_started condition: service_started
environment: environment:
DB_HOST: mysql
DB_NAME: omsorg_web
DB_USER: omsorg_web
DB_PASSWORD: omsorg_web_dev_password
OMSORG_CORE_URL: "http://omsorgcore:8080" OMSORG_CORE_URL: "http://omsorgcore:8080"
ports: ports:
- "8081:80" - "8081:80"
volumes: volumes:
- web_uploads:/var/www/html/mitarbeiter-app-legacy/uploads - /root/data/omsorgweb/uploads:/var/www/html/mitarbeiter-app-legacy/uploads
- web_downloads:/var/www/html/mitarbeiter-app-legacy/downloads - /root/data/omsorgweb/downloads:/var/www/html/mitarbeiter-app-legacy/downloads
- web_fortbildung:/var/www/html/mitarbeiter-app-legacy/fortbildung-materials - /root/data/omsorgweb/fortbildung-materials:/var/www/html/mitarbeiter-app-legacy/fortbildung-materials
- web_avatars:/var/www/html/mitarbeiter-app-legacy/assets/avatars - /root/data/omsorgweb/avatars:/var/www/html/mitarbeiter-app-legacy/assets/avatars
- web_data:/var/www/html/mitarbeiter-app-legacy/data - /root/data/omsorgweb/data:/var/www/html/mitarbeiter-app-legacy/data
volumes:
postgres_data:
mysql_data:
omsorgcore_documents:
web_uploads:
web_downloads:
web_fortbildung:
web_avatars:
web_data:
+10 -2
View File
@@ -18,8 +18,16 @@ COPY omsorgWeb/ /var/www/html/
COPY .htaccess /var/www/html/.htaccess COPY .htaccess /var/www/html/.htaccess
RUN chmod +x /var/www/html/docker/docker-entrypoint.sh \ RUN chmod +x /var/www/html/docker/docker-entrypoint.sh \
# Schreibbare Verzeichnisse für Datei-Uploads zur Laufzeit (siehe docker-compose.yml-Volumes) - # Schreibbare Verzeichnisse für Datei-Uploads zur Laufzeit (siehe docker-compose.yml-Volumes).
# Besitzer auf den Apache-User setzen, damit PHP dort schreiben kann. # Existieren im Repo NICHT zwingend (Root-.gitignore schließt sie komplett aus - lokal hatten
# sie bei mir Testdateien, ein frischer CI-Checkout hat sie gar nicht) - deshalb erst anlegen,
# dann Besitzer auf den Apache-User setzen, damit PHP dort schreiben kann.
&& mkdir -p \
/var/www/html/mitarbeiter-app-legacy/uploads \
/var/www/html/mitarbeiter-app-legacy/downloads \
/var/www/html/mitarbeiter-app-legacy/fortbildung-materials \
/var/www/html/mitarbeiter-app-legacy/assets/avatars \
/var/www/html/mitarbeiter-app-legacy/data \
&& chown -R www-data:www-data \ && chown -R www-data:www-data \
/var/www/html/mitarbeiter-app-legacy/uploads \ /var/www/html/mitarbeiter-app-legacy/uploads \
/var/www/html/mitarbeiter-app-legacy/downloads \ /var/www/html/mitarbeiter-app-legacy/downloads \
+7 -3
View File
@@ -13,9 +13,10 @@ RUN npm ci
COPY omsorgapp/ . COPY omsorgapp/ .
# Vite bäckt import.meta.env.VITE_OMSORG_CORE_URL (src/api/config.js) zur Build-Zeit ein - kein # Fallback für lokale/CI-Builds ohne Container (npm run dev/build) - im Container selbst
# Runtime-Wert. Default passt zum docker-compose.yml-Setup, für einen echten Deploy überschreibt # entscheidet ausschließlich die Laufzeit-Env-Var OMSORG_CORE_URL (siehe docker-entrypoint.sh),
# CI das per --build-arg mit der öffentlich erreichbaren omsorgCore-URL. # da dieses Image aus der Registry gezogen und per docker-compose.yml konfiguriert wird, nicht
# pro Zielumgebung neu gebaut (siehe src/api/config.js).
ARG VITE_OMSORG_CORE_URL=http://localhost:8080 ARG VITE_OMSORG_CORE_URL=http://localhost:8080
ENV VITE_OMSORG_CORE_URL=$VITE_OMSORG_CORE_URL ENV VITE_OMSORG_CORE_URL=$VITE_OMSORG_CORE_URL
RUN npm run build RUN npm run build
@@ -23,4 +24,7 @@ RUN npm run build
FROM nginx:1.27-alpine AS runtime FROM nginx:1.27-alpine AS runtime
COPY --from=build /app/dist /usr/share/nginx/html COPY --from=build /app/dist /usr/share/nginx/html
COPY omsorgapp/nginx.conf /etc/nginx/conf.d/default.conf COPY omsorgapp/nginx.conf /etc/nginx/conf.d/default.conf
COPY omsorgapp/docker-entrypoint.sh /docker-entrypoint.sh
RUN chmod +x /docker-entrypoint.sh
EXPOSE 80 EXPOSE 80
ENTRYPOINT ["/docker-entrypoint.sh"]
+11
View File
@@ -0,0 +1,11 @@
#!/bin/sh
set -eu
# Schreibt die Laufzeit-Backend-Adresse in env-config.js, bevor nginx startet - siehe
# src/api/config.js. OMSORG_CORE_URL kommt aus docker-compose.yml, muss vom BROWSER erreichbar
# sein (nicht der interne Compose-Servicename), z.B. https://core.omsorg-pflegedienste.de.
cat > /usr/share/nginx/html/env-config.js <<EOF
window.__OMSORG_ENV__ = { OMSORG_CORE_URL: "${OMSORG_CORE_URL:-}" };
EOF
exec nginx -g "daemon off;"
+1 -1
View File
@@ -1 +1 @@
<!doctype html><html lang="de"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><title>Omsorg Business Controls Pro</title></head><body><div id="root"></div><script type="module" src="/src/main.jsx"></script></body></html> <!doctype html><html lang="de"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><title>Omsorg Business Controls Pro</title></head><body><div id="root"></div><script src="/env-config.js"></script><script type="module" src="/src/main.jsx"></script></body></html>
+4
View File
@@ -0,0 +1,4 @@
// Dev-Default (Vite serviert alles unter public/ unverändert unter /) - im Docker-Image wird
// diese Datei vom Entrypoint (docker-entrypoint.sh) aus der OMSORG_CORE_URL-Env-Var überschrieben,
// siehe src/api/config.js.
window.__OMSORG_ENV__ = {};
+7 -3
View File
@@ -1,4 +1,8 @@
// Einzige Stelle im Projekt, die die Adresse von omsorgCore kennt. // Einzige Stelle im Projekt, die die Adresse von omsorgCore kennt.
// Default passt zum lokalen `dotnet run --project src/OmsorgCore.Api` (http-Profil, Port 5245), // Reihenfolge: 1) Laufzeit-Konfiguration (window.__OMSORG_ENV__, aus env-config.js - vom
// überschreibbar per Vite-Env-Variable (VITE_OMSORG_CORE_URL) für andere Umgebungen. // nginx-Entrypoint im Container aus der OMSORG_CORE_URL-Env-Var generiert, siehe
export const API_BASE = import.meta.env.VITE_OMSORG_CORE_URL || "http://localhost:5245"; // omsorgapp/docker-entrypoint.sh) - so lässt sich die Backend-Adresse rein über
// docker-compose.yml setzen, ohne das Image neu zu bauen. 2) Vite-Build-Zeit-Env
// (VITE_OMSORG_CORE_URL, für `npm run dev`/lokale Builds ohne Container). 3) localhost-Default.
export const API_BASE =
window.__OMSORG_ENV__?.OMSORG_CORE_URL || import.meta.env.VITE_OMSORG_CORE_URL || "http://localhost:5245";