version: "3.8" services: # ============================================================= # TRAEFIK — Reverse Proxy & SSL (Let's Encrypt) # ============================================================= traefik: image: traefik:v2.11 command: - "--api.dashboard=true" - "--providers.docker=true" - "--providers.docker.swarmMode=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" - "--entrypoints.websecure.address=:443" - "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web" - "--certificatesresolvers.letsencrypt.acme.email=admin@agendapro.com.br" - "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json" - "--entrypoints.web.http.redirections.entrypoint.to=websecure" - "--entrypoints.web.http.redirections.entrypoint.scheme=https" ports: - "80:80" - "443:443" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro" - "traefik-certs:/letsencrypt" networks: - webproxy deploy: replicas: 1 placement: constraints: [node.role == manager] labels: - "traefik.enable=true" - "traefik.http.routers.traefik.rule=Host(`traefik.agendapro.com.br`)" - "traefik.http.routers.traefik.entrypoints=websecure" - "traefik.http.routers.traefik.tls.certresolver=letsencrypt" - "traefik.http.routers.traefik.service=api@internal" - "traefik.http.services.traefik.loadbalancer.server.port=8080" # ============================================================= # POSTGRESQL — Banco de Dados Compartilhado # ============================================================= postgres: image: postgres:16-alpine environment: POSTGRES_DB: agendapro POSTGRES_USER: agendapro_user POSTGRES_PASSWORD_FILE: /run/secrets/db_password secrets: - db_password volumes: - pgdata:/var/lib/postgresql/data - ./database/init.sql:/docker-entrypoint-initdb.d/01-init.sql networks: - backend deploy: replicas: 1 placement: constraints: [node.role == manager] # ============================================================= # AGENDAPRO APP — Sistema Principal (app.agendapro.com.br) # ============================================================= agendapro: image: agendapro-app:latest build: context: . dockerfile: Dockerfile environment: DATABASE_URL: postgresql://agendapro_user:${DB_PASSWORD}@postgres:5432/agendapro JWT_SECRET_FILE: /run/secrets/jwt_secret NODE_ENV: production secrets: - jwt_secret networks: - webproxy - backend deploy: replicas: 2 update_config: parallelism: 1 delay: 10s order: start-first rollback_config: parallelism: 1 restart_policy: condition: on-failure delay: 5s max_attempts: 3 labels: - "traefik.enable=true" - "traefik.http.routers.agendapro.rule=Host(`app.agendapro.com.br`)" - "traefik.http.routers.agendapro.entrypoints=websecure" - "traefik.http.routers.agendapro.tls.certresolver=letsencrypt" - "traefik.http.services.agendapro.loadbalancer.server.port=3000" - "traefik.http.services.agendapro.loadbalancer.healthcheck.path=/api/health" - "traefik.http.services.agendapro.loadbalancer.healthcheck.interval=15s" # ============================================================= # ADMIN PANEL — Gerenciador de Assinaturas (admin.agendapro.com.br) # ============================================================= admin: image: agendapro-admin:latest build: context: ./admin dockerfile: Dockerfile environment: DATABASE_URL: postgresql://agendapro_user:${DB_PASSWORD}@postgres:5432/agendapro JWT_SECRET_FILE: /run/secrets/jwt_secret ADMIN_SECRET_FILE: /run/secrets/admin_secret NODE_ENV: production secrets: - jwt_secret - admin_secret networks: - webproxy - backend deploy: replicas: 1 update_config: parallelism: 1 delay: 10s restart_policy: condition: on-failure delay: 5s max_attempts: 3 labels: - "traefik.enable=true" - "traefik.http.routers.admin.rule=Host(`admin.agendapro.com.br`)" - "traefik.http.routers.admin.entrypoints=websecure" - "traefik.http.routers.admin.tls.certresolver=letsencrypt" - "traefik.http.services.admin.loadbalancer.server.port=3001" # Proteção extra: Basic Auth no admin - "traefik.http.routers.admin.middlewares=admin-auth" - "traefik.http.middlewares.admin-auth.basicauth.users=admin:$$apr1$$xyz$$hashedpassword" volumes: pgdata: traefik-certs: networks: webproxy: driver: overlay external: false backend: driver: overlay internal: true secrets: db_password: external: true jwt_secret: external: true admin_secret: external: true