# Canonical internal MySQL for the Jorge Cuadros platform.
#
# Target: Portainer "local" endpoint on cubex (192.168.4.212:9443), which is a
# 3-node Docker Swarm. This is the source-of-truth database from the plan's
# "internal server" — the migration transform+load and the NestJS API both
# point at it, and (later) it becomes the replication SOURCE for the VPS.
#
# DEV / PROD as two stacks from this one file. Deploy it twice with different
# stack names + env_data:
#   dev : stack jorgecuadros-dev-db  MYSQL_PORT=3307  MYSQL_SERVER_ID=11
#   prod: stack jorgecuadros-prod-db MYSQL_PORT=3306  MYSQL_SERVER_ID=1
# Swarm namespaces the named volume by stack name, so the two environments get
# fully isolated data (jorgecuadros-dev-db_mysql_data vs -prod-db_...) with no
# extra config. Distinct published ports let both run on the same node at once.
# server-id must be unique per environment (prod=1 is the replication source).
#
# Swarm statefulness rules (see portainer-gitea-deploy skill):
#  - named volume, never a relative bind mount (the API deploy path won't
#    create host dirs -> "bind source path does not exist").
#  - a named volume is LOCAL to whichever node the task lands on. With no
#    shared storage, the DB MUST be pinned to one node or a reschedule would
#    start against a fresh empty volume. Pinned here via a node label so it is
#    not tied to a hostname: label exactly one node with
#        docker node update --label-add jorgecuadros_db=true <node>
#    and MySQL will always run there, reusing the same volume.
#
# Secrets (MYSQL_ROOT_PASSWORD, MYSQL_PASSWORD) are injected at deploy time via
# Portainer env_data / stack environment, not committed here.

version: "3.8"

services:
  mysql:
    image: mysql:8.4
    command:
      # (caching_sha2_password is already the default in 8.4; the old
      #  --default-authentication-plugin flag was REMOVED in 8.4 and aborts boot.)
      # binlog + GTID on from day one so this node can be the replication
      # SOURCE for the VPS replica later without a restart/reconfigure.
      - --server-id=${MYSQL_SERVER_ID:-1}
      - --log-bin=mysql-bin
      - --binlog-format=ROW
      - --gtid-mode=ON
      - --enforce-gtid-consistency=ON
    environment:
      MYSQL_DATABASE: ${MYSQL_DATABASE:-jorgecuadros}
      MYSQL_USER: ${MYSQL_USER:-jorgecuadros}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD:?MYSQL_PASSWORD must be set}
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:?MYSQL_ROOT_PASSWORD must be set}
    ports:
      # Swarm ingress publishes on every node, so this is reachable at
      # 192.168.4.212:${MYSQL_PORT} regardless of which node the task pins to.
      - target: 3306
        published: ${MYSQL_PORT:-3306}
        protocol: tcp
        mode: ingress
    volumes:
      - mysql_data:/var/lib/mysql
    deploy:
      replicas: 1
      placement:
        constraints:
          - node.labels.jorgecuadros_db == true
      restart_policy:
        condition: any
      update_config:
        order: stop-first
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p$$MYSQL_ROOT_PASSWORD"]
      interval: 10s
      timeout: 5s
      retries: 12
      start_period: 40s

volumes:
  mysql_data:
