# Reprodução local da topologia de homologação: mesma imagem, dois processos, # Postgres e Redis de verdade. Serve para validar o artefato antes de subir ao # servidor. Aqui o ambiente é `development`: não há Supabase local, então o # armazenamento é um volume privado e a sessão usa o login local sem senha. # # docker compose up --build # docker compose exec web /app/docker/entrypoint.sh migrate # # Nenhuma porta de serviço do ecossistema é usada: tudo em 127.0.0.1 e em # portas altas, com nomes próprios de projeto, rede e volume. name: adaptador-planilhas-local services: postgres: image: postgres:16-alpine environment: POSTGRES_USER: adaptador POSTGRES_PASSWORD: adaptador_local POSTGRES_DB: adaptador ports: - "127.0.0.1:55432:5432" volumes: - postgres-data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U adaptador -d adaptador"] interval: 5s timeout: 3s retries: 20 networks: [adaptador] redis: image: redis:7-alpine command: ["redis-server", "--save", "", "--appendonly", "no"] ports: - "127.0.0.1:56379:6379" healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 20 networks: [adaptador] # Prepara o volume do armazenamento antes de web e worker e termina. É o único # passo como root: sem rede, só com as capacidades de ajustar dono e trocar de # usuário para provar a escrita como uid 1001. Idempotente e sem recursão. storage-init: image: ${ADAPTER_IMAGE:-adaptador-planilhas:local} build: context: . target: runner command: ["prepare-storage"] user: "0:0" network_mode: none cap_drop: [ALL] cap_add: [CHOWN, FOWNER, DAC_OVERRIDE, DAC_READ_SEARCH, SETUID, SETGID] security_opt: ["no-new-privileges:true"] healthcheck: disable: true restart: "no" volumes: - app-storage:/app/.data web: # Com ADAPTER_IMAGE definido, usa a imagem já construída (o CI faz isso). # Sem ela, `up --build` constrói e marca com este nome. image: ${ADAPTER_IMAGE:-adaptador-planilhas:local} build: context: . target: runner command: ["web"] environment: &app-env ADAPTER_ENV: development ADAPTER_NAMESPACE: adaptador-planilhas ADAPTER_JOB_MODE: worker ADAPTER_APPLY_IDENTITY_SHIM: "1" ADAPTER_DEV_AUTH: "1" ADAPTER_DEV_AUTH_SECRET: segredo-apenas-local DATABASE_URL: postgres://adaptador:adaptador_local@postgres:5432/adaptador REDIS_URL: redis://redis:6379 SPREADSHEET_TEMP_TTL_SECONDS: "3600" ELO_PRO_APP_URL: http://localhost:3000 PORT: "3000" HOSTNAME: 0.0.0.0 ports: - "127.0.0.1:3000:3000" volumes: - app-storage:/app/.data depends_on: storage-init: condition: service_completed_successfully postgres: condition: service_healthy redis: condition: service_healthy networks: [adaptador] worker: image: ${ADAPTER_IMAGE:-adaptador-planilhas:local} build: context: . target: runner command: ["worker"] environment: *app-env volumes: - app-storage:/app/.data # O worker grava heartbeat ao fim de cada tick; o healthcheck detecta # processo vivo mas travado, que um check de PID não pega. healthcheck: test: ["CMD", "/app/docker/entrypoint.sh", "worker-health"] interval: 30s timeout: 5s start_period: 15s retries: 3 stop_grace_period: 30s depends_on: storage-init: condition: service_completed_successfully web: condition: service_started postgres: condition: service_healthy redis: condition: service_healthy networks: [adaptador] networks: adaptador: name: adaptador-planilhas-local volumes: postgres-data: name: adaptador-planilhas-local-postgres app-storage: name: adaptador-planilhas-local-storage