services: # --- Datenbank: PostgreSQL --- db: image: postgres:16-alpine container_name: archive-db restart: unless-stopped environment: POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: ${POSTGRES_DB} volumes: - ./data/postgres:/var/lib/postgresql/data ports: - "${PORT_DB}:5432" networks: - archive-net healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 5s timeout: 5s retries: 5 # --- Object Storage: MinIO (S3 kompatibel) --- minio: image: minio/minio:latest container_name: archive-minio restart: unless-stopped command: server /data --console-address ":9001" environment: MINIO_ROOT_USER: ${MINIO_ROOT_USER} MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD} volumes: - ./data/minio:/data ports: - "${PORT_MINIO_API}:9000" # API Port - "${PORT_MINIO_CONSOLE}:9001" # Web-Oberfläche networks: - archive-net healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"] interval: 30s timeout: 20s retries: 3 # --- Helper: Erstellt automatisch den Bucket --- create-buckets: image: minio/mc depends_on: minio: condition: service_healthy entrypoint: > /bin/sh -c " /usr/bin/mc alias set myminio http://minio:9000 ${MINIO_ROOT_USER} ${MINIO_ROOT_PASSWORD}; /usr/bin/mc mb myminio/${MINIO_DEFAULT_BUCKETS} --ignore-existing; /usr/bin/mc anonymous set private myminio/${MINIO_DEFAULT_BUCKETS}; exit 0; " networks: - archive-net # --- Mail catcher: Mailpit (dev only) --- # Catches all outgoing emails and displays them in a web UI. # Access the inbox at http://localhost:${PORT_MAILPIT_UI} after starting the stack. mailpit: image: axllent/mailpit:latest container_name: archive-mailpit restart: unless-stopped ports: - "${PORT_MAILPIT_UI:-8025}:8025" # Web UI - "${PORT_MAILPIT_SMTP:-1025}:1025" # SMTP networks: - archive-net # --- OCR: Python microservice (Surya + Kraken) --- ocr-service: build: context: ./ocr-service dockerfile: Dockerfile container_name: archive-ocr restart: unless-stopped expose: - "8000" mem_limit: 8g memswap_limit: 8g volumes: - ocr_models:/app/models - ocr_cache:/root/.cache environment: KRAKEN_MODEL_PATH: /app/models/german_kurrent.mlmodel TRAINING_TOKEN: "${OCR_TRAINING_TOKEN:-}" OCR_CONFIDENCE_THRESHOLD: "0.3" OCR_CONFIDENCE_THRESHOLD_KURRENT: "0.5" RECOGNITION_BATCH_SIZE: "16" DETECTOR_BATCH_SIZE: "8" networks: - archive-net healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8000/health"] interval: 10s timeout: 5s retries: 12 start_period: 60s # --- Backend: Spring Boot --- backend: build: context: ./backend dockerfile: Dockerfile container_name: archive-backend restart: unless-stopped volumes: - ./backend:/app - ./import:/import - maven_cache:/root/.m2 depends_on: db: condition: service_healthy minio: condition: service_healthy mailpit: condition: service_started ocr-service: condition: service_started environment: SPRING_DATASOURCE_URL: jdbc:postgresql://db:5432/${POSTGRES_DB} SPRING_DATASOURCE_USERNAME: ${POSTGRES_USER} SPRING_DATASOURCE_PASSWORD: ${POSTGRES_PASSWORD} S3_ENDPOINT: http://minio:9000 S3_ACCESS_KEY: ${MINIO_ROOT_USER} S3_SECRET_KEY: ${MINIO_ROOT_PASSWORD} S3_BUCKET_NAME: ${MINIO_DEFAULT_BUCKETS} S3_REGION: us-east-1 SPRING_PROFILES_ACTIVE: dev,e2e APP_BASE_URL: ${APP_BASE_URL:-http://localhost:3000} # Defaults to the local Mailpit catcher — override in .env for production SMTP MAIL_HOST: ${MAIL_HOST:-mailpit} MAIL_PORT: ${MAIL_PORT:-1025} MAIL_USERNAME: ${MAIL_USERNAME:-} MAIL_PASSWORD: ${MAIL_PASSWORD:-} APP_MAIL_FROM: ${APP_MAIL_FROM:-noreply@familienarchiv.local} # Mailpit needs no auth or STARTTLS; production SMTP overrides these via .env SPRING_MAIL_PROPERTIES_MAIL_SMTP_AUTH: ${MAIL_SMTP_AUTH:-false} SPRING_MAIL_PROPERTIES_MAIL_SMTP_STARTTLS_ENABLE: ${MAIL_STARTTLS_ENABLE:-false} APP_OCR_BASE_URL: http://ocr-service:8000 ports: - "${PORT_BACKEND}:8080" networks: - archive-net healthcheck: test: ["CMD-SHELL", "wget -qO- http://localhost:8080/actuator/health | grep -q UP || exit 1"] interval: 15s timeout: 5s retries: 10 start_period: 60s # --- Frontend: SvelteKit (Dev Server) --- frontend: build: context: ./frontend dockerfile: Dockerfile container_name: archive-frontend restart: unless-stopped depends_on: db: condition: service_healthy minio: condition: service_healthy backend: condition: service_healthy volumes: - ./frontend:/app # Keep container's node_modules separate from host to avoid OS binary conflicts - frontend_node_modules:/app/node_modules environment: # SSR calls (server-side) use the internal Docker network API_INTERNAL_URL: http://backend:8080 # Vite dev proxy forwards /api from browser to the backend container API_PROXY_TARGET: http://backend:8080 ports: - "${PORT_FRONTEND}:5173" networks: - archive-net networks: archive-net: driver: bridge volumes: frontend_node_modules: maven_cache: ocr_models: ocr_cache: