Files
FarmaFinder/docker-compose.yml
T
Antoni Nuñez Romeu b4b2bf5834
Run Tests on Branches / Detect Changes (push) Successful in 12s
Run Tests on Branches / Backend Tests (push) Has been skipped
Run Tests on Branches / Frontend Tests (push) Has been skipped
Run Tests on Branches / Frontend Mobile Tests (push) Has been skipped
Run Tests on Branches / Parapharmacy API Tests (push) Has been skipped
Run Tests on Branches / PIP Platform Tests (push) Has been skipped
fix(n8n): resolve duplicate key constraint on tag_entity during workflow import
n8n import:workflow --separate imports each JSON file independently. All 4
workflows shared the same tags (parapharmacy, scraper), so the second import
tried to INSERT duplicate tag names, hitting the unique index on
tag_entity.name.

- Remove tags field from all 4 workflow JSON files (cosmetic, re-add via UI)
- Add cleanup-db.js to wipe workflow data before import
- Add --overwrite flag to import command as safety net
- Add cleanup-db.js volume mount to n8n-init container
2026-07-17 14:50:35 +02:00

198 lines
5.9 KiB
YAML

services:
redis:
image: redis:alpine
restart: unless-stopped
postgres:
image: postgres:16-alpine
restart: unless-stopped
environment:
POSTGRES_DB: farmafinder
POSTGRES_USER: farmafinder
POSTGRES_PASSWORD: ${PG_PASSWORD:-change-me-in-production}
healthcheck:
test: ["CMD-SHELL", "pg_isready -U farmafinder"]
interval: 5s
timeout: 3s
retries: 5
volumes:
- postgres_data:/var/lib/postgresql/data
backend:
image: git.hacecalor.net/ichitux/farmafinder-backend:latest
build:
context: .
dockerfile: apps/backend/Dockerfile
restart: unless-stopped
env_file:
- ./apps/backend/.env
ports:
- "3001:3001"
environment:
PORT: "3001"
NODE_ENV: production
SESSION_SECRET: ${SESSION_SECRET:-change-me-in-production}
CORS_ORIGIN: ${CORS_ORIGIN:-https://farmacias.hacecalor.net}
REDIS_HOST: redis
REDIS_PORT: "6379"
REDIS_PASSWORD: ${REDIS_PASSWORD:-}
DATABASE_PATH: /app/data/database.sqlite
FARMACIAS_WEBHOOK_URL: ${FARMACIAS_WEBHOOK_URL:-}
PG_URL: postgresql://farmafinder:${PG_PASSWORD:-change-me-in-production}@postgres:5432/farmafinder
# OpenTelemetry — exported via OTLP gRPC to the shared Alloy collector
OTEL_SERVICE_NAME: farmafinder-backend
OTEL_EXPORTER_OTLP_ENDPOINT: http://host.docker.internal:4317
OTEL_TRACES_EXPORTER: otlp
OTEL_METRICS_EXPORTER: otlp
OTEL_LOGS_EXPORTER: otlp
PARAPHARMACY_API_URL: http://parapharmacy-api:3002
OTEL_RESOURCE_ATTRIBUTES: service.namespace=farmafinder
volumes:
- backend_data:/app/data
depends_on:
- redis
- postgres
frontend:
image: git.hacecalor.net/ichitux/farmafinder-frontend:latest
build:
context: ./apps/frontend
args:
VITE_FARO_ENDPOINT: ${VITE_FARO_ENDPOINT:-http://localhost:4318}
VITE_FARO_APP_NAME: ${VITE_FARO_APP_NAME:-farmafinder-frontend}
VITE_FARO_ENV: ${VITE_FARO_ENV:-production}
VITE_FARO_APP_VERSION: ${VITE_FARO_APP_VERSION:-1.0.0}
restart: unless-stopped
ports:
- "4000:80"
depends_on:
- backend
# --- Observability exporters (scraped by the shared Prometheus on srv84-macos) ---
redis-exporter:
image: oliver006/redis_exporter:latest
restart: unless-stopped
ports:
- "9121:9121"
environment:
REDIS_ADDR: redis://redis:6379
REDIS_PASSWORD: ${REDIS_PASSWORD:-}
depends_on:
- redis
postgres-exporter:
image: prometheuscommunity/postgres-exporter:latest
restart: unless-stopped
ports:
- "9187:9187"
environment:
DATA_SOURCE_NAME: postgresql://farmafinder:${PG_PASSWORD:-change-me-in-production}@postgres:5432/farmafinder?sslmode=disable
depends_on:
- postgres
# --- Parapharmacy API ---
parapharmacy-api:
image: git.hacecalor.net/ichitux/farmafinder-parapharmacy-api:latest
build:
context: .
dockerfile: apps/parapharmacy-api/Dockerfile
env_file:
- ./apps/parapharmacy-api/.env
restart: unless-stopped
ports:
- "3002:3002"
environment:
PORT: "3002"
NODE_ENV: production
MONGODB_URI: mongodb://mongodb:27017/parapharmacy
CORS_ORIGIN: ${CORS_ORIGIN:-https://farmacias.hacecalor.net}
healthcheck:
test: ["CMD", "node", "-e", "require('http').get('http://localhost:3002/api/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) })"]
interval: 10s
timeout: 5s
retries: 5
start_period: 15s
depends_on:
- mongodb
# --- MongoDB for Parapharmacy ---
mongodb:
image: mongo:7
restart: unless-stopped
ports:
- "27017:27017"
volumes:
- mongodb_data:/data/db
# --- N8N Workflow Automation ---
n8n:
image: n8nio/n8n:latest
restart: unless-stopped
ports:
- "5678:5678"
environment:
# Owner account (skips /setup)
N8N_USER_MANAGEMENT_DISABLED: "false"
N8N_OWNER_EMAIL: ${N8N_EMAIL:-admin@farmafinder.com}
N8N_OWNER_PASSWORD: ${N8N_PASSWORD:-change-me}
# Auth
N8N_BASIC_AUTH_ACTIVE: "true"
N8N_BASIC_AUTH_USER: ${N8N_USER:-admin}
N8N_BASIC_AUTH_PASSWORD: ${N8N_PASSWORD:-change-me}
# Database
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_DATABASE: farmafinder
DB_POSTGRESDB_USER: farmafinder
DB_POSTGRESDB_PASSWORD: ${PG_PASSWORD:-change-me-in-production}
# Network
N8N_HOST: localhost
N8N_PORT: 5678
N8N_PROTOCOL: http
# Webhook URL for external calls
WEBHOOK_URL: http://localhost:5678/
healthcheck:
test: ["CMD", "wget", "-qO", "/dev/null", "http://localhost:5678/healthz"]
interval: 10s
timeout: 5s
retries: 5
start_period: 30s
volumes:
- n8n_data:/home/node/.n8n
- ./n8n/workflows:/home/node/workflows
depends_on:
postgres:
condition: service_healthy
# --- N8N Init: import + activate workflows BEFORE n8n starts, then seed DB ---
n8n-init:
image: n8nio/n8n:latest
entrypoint: ["/bin/sh", "/home/node/init-import.sh"]
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_DATABASE: farmafinder
DB_POSTGRESDB_USER: farmafinder
DB_POSTGRESDB_PASSWORD: ${PG_PASSWORD:-change-me-in-production}
N8N_OWNER_EMAIL: ${N8N_EMAIL:-admin@farmafinder.com}
N8N_OWNER_PASSWORD: ${N8N_PASSWORD:-change-me}
volumes:
- n8n_data:/home/node/.n8n
- ./n8n/workflows:/home/node/workflows
- ./n8n/init-import.sh:/home/node/init-import.sh:ro
- ./n8n/cleanup-db.js:/home/node/cleanup-db.js:ro
- ./n8n/seed.json:/home/node/seed.json:ro
depends_on:
postgres:
condition: service_healthy
parapharmacy-api:
condition: service_healthy
n8n:
condition: service_healthy
volumes:
backend_data:
postgres_data:
mongodb_data:
n8n_data: