Quelle anlegen, Verbindung testen, nach Zeitplan oder auf Knopfdruck abgleichen. Gelesen wird seitenweise mit searchPaginated, objectGUID kommt als Puffer und wird gemischt-endian zur GUID umsortiert. Wer im Verzeichnis verschwindet, wird hier inaktiv und nie geloescht. Drei Regeln verhindern, dass eine kaputte Eingabe wie "alle sind gegangen" aussieht: laesst sich kein einziger Eintrag zuordnen, wird niemand deaktiviert; uebersprungene Eintraege werden am dn erkannt und ausgenommen; eine von Hand angelegte Person wird uebernommen statt verdoppelt. Der Zeitplan laeuft ueber node-cron im selben Prozess, gestartet aus src/instrumentation.ts, und nimmt keine eigene Sperre - die liegt in der Datenbank, damit zwei Instanzen sich einig sind. Closes #16 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
101 lines
3.3 KiB
YAML
101 lines
3.3 KiB
YAML
# Laufzettel – Betriebsstand.
|
||
#
|
||
# Die Datenbank ist bewusst von aussen NICHT erreichbar: kein ports:-Mapping und
|
||
# ein Netz ohne Gateway (internal: true). Nur web und migrate kommen ueber den
|
||
# Dienstnamen daran. Fuer die Entwicklung gibt es docker-compose.dev.yml.
|
||
#
|
||
# Sicherung trotz geschlossenem Port:
|
||
# docker compose exec -T postgres pg_dump -U laufzettel laufzettel > sicherung.sql
|
||
|
||
name: laufzettel
|
||
|
||
services:
|
||
postgres:
|
||
image: postgres:17-alpine
|
||
restart: unless-stopped
|
||
environment:
|
||
POSTGRES_USER: ${POSTGRES_USER:-laufzettel}
|
||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:?POSTGRES_PASSWORD fehlt in der .env}
|
||
POSTGRES_DB: ${POSTGRES_DB:-laufzettel}
|
||
# Absichtlich expose statt ports: im LAN und auf dem Host nicht erreichbar.
|
||
expose:
|
||
- "5432"
|
||
networks:
|
||
- intern
|
||
volumes:
|
||
- datenbank:/var/lib/postgresql/data
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-laufzettel}"]
|
||
interval: 10s
|
||
timeout: 5s
|
||
retries: 10
|
||
|
||
# Laeuft einmal beim Start und spielt nur die Migrationen ein.
|
||
# Der Seed wird bewusst nicht automatisch ausgefuehrt, siehe README.
|
||
migrate:
|
||
build:
|
||
context: .
|
||
target: bauen
|
||
restart: "no"
|
||
environment:
|
||
DATABASE_URL: ${DATABASE_URL:-postgresql://${POSTGRES_USER:-laufzettel}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-laufzettel}?schema=public}
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
networks:
|
||
- intern
|
||
command: ["pnpm", "exec", "prisma", "migrate", "deploy"]
|
||
|
||
web:
|
||
build:
|
||
context: .
|
||
target: laufzeit
|
||
args:
|
||
APP_VERSION: ${APP_VERSION:-0.1.0}
|
||
GIT_SHA: ${GIT_SHA:-}
|
||
restart: unless-stopped
|
||
environment:
|
||
DATABASE_URL: ${DATABASE_URL:-postgresql://${POSTGRES_USER:-laufzettel}:${POSTGRES_PASSWORD}@postgres:5432/${POSTGRES_DB:-laufzettel}?schema=public}
|
||
APP_SECRET: ${APP_SECRET:?APP_SECRET fehlt in der .env}
|
||
APP_URL: ${APP_URL:?APP_URL fehlt in der .env}
|
||
AUTH_LOCAL_ENABLED: ${AUTH_LOCAL_ENABLED:-false}
|
||
OIDC_ISSUER: ${OIDC_ISSUER:-}
|
||
OIDC_CLIENT_ID: ${OIDC_CLIENT_ID:-}
|
||
OIDC_CLIENT_SECRET: ${OIDC_CLIENT_SECRET:-}
|
||
OIDC_NAME: ${OIDC_NAME:-authentik}
|
||
OIDC_GROUP_ADMIN: ${OIDC_GROUP_ADMIN:-}
|
||
OIDC_GROUP_EDITOR: ${OIDC_GROUP_EDITOR:-}
|
||
OIDC_GROUP_TECHNICIAN: ${OIDC_GROUP_TECHNICIAN:-}
|
||
OIDC_GROUP_VIEWER: ${OIDC_GROUP_VIEWER:-}
|
||
OIDC_CUSTOMER_GROUP_PREFIX: ${OIDC_CUSTOMER_GROUP_PREFIX:-}
|
||
# Der Verzeichnis-Abgleich laeuft im selben Prozess (#016). Hier steht er
|
||
# an, weil dieser Dienst der einzige ist, der dauerhaft laeuft.
|
||
ZEITPLAN_AKTIV: ${ZEITPLAN_AKTIV:-true}
|
||
# Standardmaessig nur auf localhost; davor gehoert ein Reverse Proxy.
|
||
ports:
|
||
- "${BIND_ADDR:-127.0.0.1}:${APP_PORT:-3000}:3000"
|
||
depends_on:
|
||
postgres:
|
||
condition: service_healthy
|
||
migrate:
|
||
condition: service_completed_successfully
|
||
networks:
|
||
- intern
|
||
- extern
|
||
healthcheck:
|
||
test: ["CMD", "wget", "-qO-", "http://localhost:3000/api/gesundheit"]
|
||
interval: 30s
|
||
timeout: 5s
|
||
retries: 5
|
||
start_period: 20s
|
||
|
||
networks:
|
||
# Kein Gateway: die Datenbank kann weder heraus noch ist sie von aussen erreichbar.
|
||
intern:
|
||
internal: true
|
||
# Nur fuer web: Reverse Proxy, OIDC zu authentik, LDAP zum AD.
|
||
extern:
|
||
|
||
volumes:
|
||
datenbank:
|