services:

# ----------------------------------------------------------------------
# Proxy inverse
#
# ----------------------------------------------------------------------
# Caddy
# Web server, load balancer, and reverse proxy
# https://caddyserver.com/
  caddy:
    image: lucaslorentz/caddy-docker-proxy:2.10
    restart: "no"
    ports:
      - "80:80"
      - "443:443/tcp"
      - "443:443/udp"
    networks:
      - caddy_net
    environment:
      CADDY_INGRESS_NETWORKS: ${COMPOSE_PROJECT_NAME}_caddy_net
    volumes:
      - caddy_config:/config
      - caddy_data:/data
      - /var/run/docker.sock:/var/run/docker.sock:ro
      - ./data:/srv/www:ro
    labels:
      caddy: localhost
      caddy.root: "* /srv/www"
      caddy.file_server: ""      # Active le serveur de fichiers statiques
      caddy.tls: internal        # HTTPS auto-signé géré par Caddy

  # WhoAmI
  # Tiny Go webserver that prints OS information and HTTP request to output.
  # https://github.com/traefik/whoami
  whoami:
    image: traefik/whoami
    depends_on:
      - caddy
    networks:
      - caddy_net
    labels:
      caddy: whoami.localhost
      caddy.reverse_proxy: "{{upstreams 80}}"
      caddy.tls: internal

# ----------------------------------------------------------------------
# Base de données relationnelles
#
# ----------------------------------------------------------------------
  database:
    image: iut/pgsql:2025-12
    environment:
      POSTGRES_INITDB_ARGS: "--locale-provider=icu --icu-locale=fr-FR"
      POSTGRES_PASSWORD: ${PG_PASSWORD:-!ChangeMe!}
      POSTGRES_USER: ${COMPOSE_PROJECT_NAME}
    volumes:
      - database_data:/var/lib/postgresql:rw
      - ./postgresql-entrypoint-initdb.d:/docker-entrypoint-initdb.d:Z
      - ./data:/tmp:z
    ports:
      - "5432:5432"
    networks:
      - caddy_net
    healthcheck:
      test: ["CMD", "pg_isready", "--username", "${COMPOSE_PROJECT_NAME}", "--dbname", "${COMPOSE_PROJECT_NAME}"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 20s

# ----------------------------------------------------------------------
# Administration
#
# ----------------------------------------------------------------------
# pgAdmin
# Rich administration and development platform for PostgreSQL.
# https://www.pgadmin.org/
  pgadmin:
    image: dpage/pgadmin4:9.8
    depends_on:
      database:
        condition: service_healthy
      caddy:
        condition: service_started
    restart: "no"
    configs:
      - source: pgadmin_config
        target: /pgadmin4/servers.json
    volumes:
      - pgadmin:/var/lib/pgadmin/
    environment:
      PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL}
      PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
      PGADMIN_DISABLE_POSTFIX: true
    networks:
      - caddy_net
    labels:
      caddy: pgadmin.localhost
      caddy.reverse_proxy: "{{upstreams 80}}"
      caddy.tls: internal

# Redis
# In-memory key-value database
# https://redis.io/fr/
  redis:
    image: redis:8.2
    command:
      - 'redis-server'
      - '--save 60 1'
      - '--loglevel verbose'
      - '--requirepass ${REDIS_PASSWORD}'
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "-a", "${REDIS_PASSWORD}", "--raw", "incr", "ping" ]
      interval: 30s
      timeout: 5s
      retries: 3
      start_period: 20s
    volumes:
      - redis_data:/data


# ----------------------------------------------------------------------
# Graphes
#
# ----------------------------------------------------------------------
# PostGraphile
# Instant GraphQL API
# https://www.graphile.org/postgraphile/
  postgraphile:
    image: iut/postgraphile:2025-12
    restart: "no"
    depends_on:
      database:
        condition: service_healthy
    command:
      [
        "--port", "80",
        "--schema", "${POSTGRAPHILE_SCHEMA:-public}",
        "--enhance-graphiql",
        "--cors",
        "--allow-explain",
        "--dynamic-json",
        "--append-plugins",
        "postgraphile-plugin-connection-filter,postgraphile-plugin-fulltext-filter,@graphile/postgis,postgraphile-plugin-connection-filter-postgis"
      ]
    networks:
      - caddy_net
    environment:
      - PGHOST=database
      - PGPORT=5432
      - PGUSER=${POSTGRAPHILE_USER:-postgraphile_user}
      - PGPASSWORD=${POSTGRAPHILE_PASSWORD:-9013}
      - PGDATABASE=${COMPOSE_PROJECT_NAME}
    labels:
      caddy: postgraphile.localhost
      caddy.reverse_proxy: "{{upstreams 80}}"
      caddy.tls: internal

# ----------------------------------------------------------------------
# Web API
#
# ----------------------------------------------------------------------
# PostgREST
# Serve a fully RESTful API from any existing PostgreSQL database.
# It provides a cleaner, more standards-compliant, faster API than you are likely to write from scratch.
# https://docs.postgrest.org/en/v13/
  postgrest:
    image: postgrest/postgrest:v13.0.7
    restart: "no"
    depends_on:
      database:
        condition: service_healthy
      caddy:
        condition: service_started
    command: postgrest
    environment:
      PGRST_DB_URI: postgres://${POSTGREST_USER:-postgrest}:${POSTGREST_PASSWORD}@${POSTGREST_HOST:-database}:${POSTGREST_DB_PORT:-5432}/${COMPOSE_PROJECT_NAME}
      PGRST_DB_SCHEMAS: ${POSTGREST_DB_SCHEMAS:-public}
      PGRST_DB_ANON_ROLE: ${POSTGREST_DB_ANON_ROLE:-anonyme}
      PGRST_JWT_SECRET: ${POSTGREST_JWT_SECRET:-ChangeMeChangeMeChangeMeChangeMe}
      PGRST_ADMIN_SERVER_PORT: 3055
      PGRST_SERVER_PORT: 80
      PGRST_OPENAPI_SERVER_PROXY_URI: https://postgrest.localhost
    networks:
      - caddy_net
    labels:
      caddy: postgrest.localhost
      caddy.reverse_proxy: "{{upstreams 80}}"
      caddy.tls: internal

# Scalar
# Create world-class API Docs with a built-in interactive playground
# which seamlessly turns to a full featured API Client
  scalar:
    image: scalarapi/api-reference:0.4.2
    restart: "no"
    environment:
      API_REFERENCE_CONFIG: |
        {
          "sources":[
            { "url": "https://postgrest.localhost" }
          ],
          "theme": "purple"
        }
    networks:
      - caddy_net
    labels:
      caddy: scalar.localhost
      caddy.reverse_proxy: "{{upstreams 8080}}"
      caddy.tls: internal

# ----------------------------------------------------------------------
# Mock Web API
#
# ----------------------------------------------------------------------
  smocker:
    image: thiht/smocker:0.18.5
    restart: "no"
    networks:
      - caddy_net
    ports:
      - 8080:8080
      - 8081:8081

  toxiproxy:
    image: ghcr.io/shopify/toxiproxy
    restart: "no"

# ----------------------------------------------------------------------
# Business Intelligence
#
# ----------------------------------------------------------------------
  superset:
    image: apache/superset:3.1.3
    depends_on:
      database:
        condition: service_healthy
    environment:
      SUPERSET_CONFIG_PATH: /app/pythonpath/superset_config.py
      SUPERSET_SECRET_KEY: ${SUPERSET_SECRET:-YOUR_OWN_RANDOM_GENERATED_SECRET_KEY}
      SUPERSET_LOAD_EXAMPLES: no
    volumes:
      - superset_home:/app/superset_home
      - ./superset_config.py:/app/pythonpath/superset_config.py:Z
    command: >
      sh -c "
      superset db upgrade &&
      superset fab create-admin --username admin --firstname Admin --lastname User --email admin@superset.com --password admin &&
      superset init &&
      superset run -h 0.0.0.0 -p 80 --with-threads --reload --debugger
      "
    networks:
      - caddy_net
    labels:
      caddy: superset.localhost
      caddy.reverse_proxy: "{{upstreams 80}}"
      caddy.tls: internal

  metabase:
    image: metabase/metabase:v0.56.5.5
    depends_on:
      database:
        condition: service_healthy
    volumes:
      - /dev/urandom:/dev/random:ro
    environment:
      MB_DB_TYPE: postgres
      MB_DB_HOST: ${MB_DB_HOST:-database}
      MB_DB_PORT: 5432
      MB_DB_USER: metabase_user
      MB_DB_PASS: ${DB_ROOT_PASSWORD:-supermotdepasse}
      MB_DB_DBNAME: metabase
      MB_SITE_LOCALE: fr
      MB_ADMIN_EMAIL: etudiant@univ-lorraine.fr
      MB_ANON_TRACKING_ENABLED: false
      MB_CHECK_FOR_UPDATES: false
      MB_NO_SURVEYS: yes
      MB_START_OF_WEEK: monday
      MB_CUSTOM_FORMATTING: '{"type/Temporal":{"time_style":"HH:mm","date_style":"D MMMM, YYYY","date_abbreviate":true},"type/Currency":{"currency":"EUR"},"type/Number":{"number_separators":", "}}'
      MB_EMAIL_SMTP_HOST: mailpit
      MB_EMAIL_SMTP_PORT: 1025
      MB_EMAIL_FROM_ADDRESS: metabase@univ-lorraine.fr
    networks:
      - caddy_net
    labels:
      caddy: metabase.localhost
      caddy.reverse_proxy: "{{upstreams 3000}}"
      caddy.tls: internal

  metabase-init:
    build:
      context: ./metabase
    depends_on:
      - metabase
    networks:
      - caddy_net

  rabbitmq:
    image: rabbitmq:4.1.4-management
    ports:
      - "5672:5672"     # AMQP
      - "1883:1883"     # MQTT
    networks:
      - caddy_net
    environment:
      RABBITMQ_DEFAULT_USER: admin
      RABBITMQ_DEFAULT_PASS: admin
      RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS: "-rabbitmq_mqtt tcp_listeners [1883]"
    volumes:
      - rabbitmq_data:/var/lib/rabbitmq
    command: >
      sh -c "rabbitmq-plugins enable --offline rabbitmq_mqtt rabbitmq_management &&
             rabbitmq-server"
    labels:
      caddy: rabbitmq.localhost
      caddy.reverse_proxy: "{{upstreams 15672}}"
      caddy.tls: internal

# ----------------------------------------------------------------------
# Observabilité - Télémétrie
#
# ----------------------------------------------------------------------
# Grafana
# Open source analytics & monitoring solution for every database.
# https://grafana.com/
  grafana:
    image: grafana/grafana-oss:12.1.0
    restart: no
    deploy:
      resources:
        limits:
          memory: 100M
    configs:
      - source: grafana_provisioning
        target: /etc/grafana/provisioning
      - source: grafana_dashboards
        target: /etc/grafana/dashboards
    volumes:
      - grafana:/var/lib/grafana
    environment:
      #GF_SECURITY_ADMIN_EMAIL: ${ADMIN_EMAIL}
      #GF_SECURITY_ADMIN_PASSWORD: ${ADMIN_PASSWORD}
      GF_AUTH_ANONYMOUS_ENABLED: true  # Enabled the Anonymous user no user/pass needed
      GF_AUTH_ANONYMOUS_ORG_ROLE: Admin
      GF_AUTH_DISABLE_LOGIN_FORM: true
      GF_USERS_DEFAULT_THEME: light
      GF_USERS_ALLOW_SIGN_UP: false
      GF_FEATURE_TOGGLES_ENABLE: traceQLStreaming metricsSummary lokiFormatQuery alertmanagerRemoteOnly
      GF_INSTALL_PLUGINS: yesoreyeram-infinity-datasource
    networks:
      - caddy_net
    labels:
      caddy: grafana.localhost
      caddy.reverse_proxy: "{{upstreams 3000}}"
      caddy.tls: internal

# Prometheus
# Prometheus is an open-source systems monitoring and alerting toolkit
# https://prometheus.io/
  prometheus:
    image: prom/prometheus:v3.6.0
    configs:
      - source: prometheus_config
        target: /etc/prometheus/prometheus.yml
    volumes:
      - prometheus:/prometheus
      - /var/run/docker.sock:/var/run/docker.sock:ro
    ports:
      - 9090:9090
    #extra_hosts:
    #  - host.docker.internal=host-gateway

  gatus:
    image: twinproduction/gatus:v5.26.0
    networks:
      - caddy_net
    labels:
      caddy: gatus.localhost
      caddy.reverse_proxy: "{{upstreams 8080}}"
      caddy.tls: internal

  mailpit:
    image: axllent/mailpit:v1.27
    restart: "no"
    ports:
      - 1025:1025
    networks:
      - caddy_net
    environment:
      TZ: Europe/Paris
    volumes:
      - mailpit:/data
    labels:
      caddy: mailpit.localhost
      caddy.reverse_proxy: "{{upstreams 8025}}"
      caddy.tls: internal

volumes:
  caddy_config:
  caddy_data:
  pgadmin:
  database_data:
  couchdb_data:
  mongodb_data:
  mongodb_configdb:
  redis_data:
  neo4j_data:
  neo4j_logs:
  prometheus:
  grafana:
  superset_home:
  rabbitmq_data:
  mailpit:

configs:
  pgadmin_config:
    file: ./pgadmin-servers.json
  grafana_provisioning:
    file: ./grafana/provisioning
  grafana_dashboards:
    file: ./grafana/dashboards
  prometheus_config:
    file: ./prometheus.yml

networks:
  caddy_net:
    driver: bridge
