diff --git a/docker-compose.yml b/docker-compose.yml index f2bbc46..99bc510 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,11 @@ services: 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 @@ -156,9 +161,12 @@ services: - n8n_data:/home/node/.n8n - ./n8n/workflows:/home/node/workflows depends_on: - - postgres + postgres: + condition: service_healthy + n8n-init: + condition: service_completed_successfully - # --- N8N Init: import workflows, activate, and seed DB --- + # --- 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"] @@ -174,10 +182,9 @@ services: - n8n_data:/home/node/.n8n - ./n8n/workflows:/home/node/workflows - ./n8n/init-import.sh:/home/node/init-import.sh:ro - - ./n8n/activate-workflows.js:/home/node/activate-workflows.js:ro - ./n8n/seed.json:/home/node/seed.json:ro depends_on: - n8n: + postgres: condition: service_healthy parapharmacy-api: condition: service_healthy diff --git a/n8n/activate-workflows.js b/n8n/activate-workflows.js deleted file mode 100644 index 1fa9515..0000000 --- a/n8n/activate-workflows.js +++ /dev/null @@ -1,82 +0,0 @@ -// Activate all inactive n8n workflows via API. -// Usage: node activate-workflows.js -import http from 'node:http'; - -const [, , email, password] = process.argv; -if (!email || !password) { - console.error('Usage: node activate-workflows.js '); - process.exit(1); -} - -const HOST = 'n8n'; -const PORT = 5678; - -function request(method, path, body, cookie) { - return new Promise((resolve, reject) => { - const opts = { - hostname: HOST, port: PORT, path, method, - headers: { 'Content-Type': 'application/json' }, - }; - if (cookie) opts.headers['Cookie'] = cookie; - - const req = http.request(opts, (res) => { - const chunks = []; - res.on('data', (c) => chunks.push(c)); - res.on('end', () => { - const raw = Buffer.concat(chunks).toString(); - const setCookie = res.headers['set-cookie']; - let cookieVal = cookie; - if (setCookie) { - const match = setCookie.find((c) => c.startsWith('n8n-auth=')); - if (match) cookieVal = match.split(';')[0]; - } - let data; - try { data = JSON.parse(raw); } catch { data = raw; } - resolve({ status: res.statusCode, data, cookie: cookieVal }); - }); - }); - req.on('error', reject); - if (body) req.write(JSON.stringify(body)); - req.end(); - }); -} - -async function main() { - // 1. Login - console.log('[activate] Logging in...'); - const login = await request('POST', '/api/v1/login', { email, password }); - if (!login.cookie) { - console.error('[activate] Login failed — no session cookie.'); - process.exit(1); - } - console.log('[activate] Login OK.'); - - // 2. List workflows - const list = await request('GET', '/api/v1/workflows', null, login.cookie); - const workflows = list.data?.data || list.data || []; - if (!Array.isArray(workflows)) { - console.error('[activate] Unexpected response:', JSON.stringify(list.data).slice(0, 200)); - process.exit(1); - } - - // 3. Activate inactive ones - let activated = 0; - for (const wf of workflows) { - if (!wf.active) { - const res = await request('PATCH', `/api/v1/workflows/${wf.id}`, { active: true }, login.cookie); - if (res.status < 300) { - console.log(`[activate] Activated: ${wf.name || wf.id}`); - activated++; - } else { - console.error(`[activate] Failed to activate ${wf.id}: HTTP ${res.status}`); - } - } - } - - console.log(`[activate] Done. ${activated} workflow(s) activated.`); -} - -main().catch((err) => { - console.error('[activate] Error:', err.message); - process.exit(1); -}); diff --git a/n8n/init-import.sh b/n8n/init-import.sh index 5f5500a..c0008bf 100755 --- a/n8n/init-import.sh +++ b/n8n/init-import.sh @@ -1,5 +1,6 @@ #!/bin/sh -# One-shot init: import workflows, activate them, and seed the DB. +# One-shot init: import + activate workflows (before n8n starts), then seed DB. +# Runs BEFORE n8n so it reads the activated state from DB on startup. # Skips if already done (flag file in shared n8n_data volume). set -e @@ -10,29 +11,29 @@ if [ -f "$FLAG" ]; then exit 0 fi -# ── 1. Wait for n8n ────────────────────────────────────────────────── -echo "[n8n-init] Waiting for n8n to be ready..." -until wget -qO /dev/null http://n8n:5678/healthz 2>/dev/null; do - sleep 2 -done -echo "[n8n-init] n8n is up." - -# ── 2. Import workflows ────────────────────────────────────────────── +# ── 1. Import workflows via CLI (writes to DB) ─────────────────────── echo "[n8n-init] Importing workflows..." -n8n import:workflow --separate --input=/home/node/workflows/ -echo "[n8n-init] Workflows imported." +n8n import:workflow --separate --input=/home/node/workflows/ 2>/dev/null -# ── 3. Activate workflows via n8n API (Node.js) ───────────────────── -if [ -f /home/node/activate-workflows.js ]; then - echo "[n8n-init] Activating workflows via n8n API..." - node /home/node/activate-workflows.js "${N8N_OWNER_EMAIL}" "${N8N_OWNER_PASSWORD}" || \ - echo "[n8n-init] WARNING: Workflow activation failed. Activate manually via n8n UI." -else - echo "[n8n-init] WARNING: activate-workflows.js not found, skipping activation." -fi +# ── 3. Activate all workflows via CLI ──────────────────────────────── +echo "[n8n-init] Activating workflows..." +TMPFILE=$(mktemp) +n8n export:workflow --all --output="$TMPFILE" 2>/dev/null + +node -e " +const fs = require('fs'); +const wfs = JSON.parse(fs.readFileSync('$TMPFILE', 'utf8')); +wfs.forEach(w => console.log(w.id)); +" | while read -r WF_ID; do + n8n publish:workflow --id="$WF_ID" 2>/dev/null + echo "[n8n-init] Activated $WF_ID" +done + +rm -f "$TMPFILE" +echo "[n8n-init] Workflows activated." # ── 4. Seed parapharmacy DB ────────────────────────────────────────── -echo "[n8n-init] Waiting for parapharmacy-api to be ready..." +echo "[n8n-init] Waiting for parapharmacy-api..." until wget -qO /dev/null http://parapharmacy-api:3002/api/health 2>/dev/null; do sleep 2 done diff --git a/n8n/seed.json b/n8n/seed.json index f36a40d..15ee313 100644 --- a/n8n/seed.json +++ b/n8n/seed.json @@ -1,22 +1,22 @@ -[ - {"name":"Bioderma Atoderm Crema Hidratante 500ml","brand":"Bioderma","category":"Dermocosmética","price":18.95,"source":"seed","source_product_id":"seed_bioderma_atoderm","currency":"EUR","available":true}, - {"name":"La Roche-Posay Anthelios Airlicium FPS50+","brand":"La Roche-Posay","category":"Solar","price":19.95,"source":"seed","source_product_id":"seed_lrp_anthelios","currency":"EUR","available":true}, - {"name":"Mustela Gel de Ducha 500ml","brand":"Mustela","category":"Bebé","price":12.50,"source":"seed","source_product_id":"seed_mustela_gel","currency":"EUR","available":true}, - {"name":"Centrum Multivitaminicos 30 comprimidos","brand":"Centrum","category":"Vitaminas","price":15.80,"source":"seed","source_product_id":"seed_centrum_multi","currency":"EUR","available":true}, - {"name":"Dolocordalpan 1g Paracetamol 20 sobres","brand":"Dolocordalpan","category":"Analgésicos","price":4.95,"source":"seed","source_product_id":"seed_dolocordalpan","currency":"EUR","available":true}, - {"name":"Nurofen Flash 400mg 20 cápsulas","brand":"Nurofen","category":"Antiinflamatorios","price":6.75,"source":"seed","source_product_id":"seed_nurofen_flash","currency":"EUR","available":true}, - {"name":"Omeprazol Cinfa 20mg 28 cápsulas","brand":"Cinfa","category":"Gastrointestinal","price":8.50,"source":"seed","source_product_id":"seed_omeprazol_cinfa","currency":"EUR","available":true}, - {"name":"Vichy Mineral 89 Sérum Hidratante 30ml","brand":"Vichy","category":"Dermocosmética","price":25.90,"source":"seed","source_product_id":"seed_vichy_mineral89","currency":"EUR","available":true}, - {"name":"Avène Agua Termal 300ml","brand":"Avène","category":"Dermocosmética","price":9.95,"source":"seed","source_product_id":"seed_avene_agua","currency":"EUR","available":true}, - {"name":"CeraVe Crema Hidratante 340g","brand":"CeraVe","category":"Dermocosmética","price":14.95,"source":"seed","source_product_id":"seed_cerave_crema","currency":"EUR","available":true}, - {"name":"Ibuprofeno Alter 600mg 20 comprimidos","brand":"Alter","category":"Antiinflamatorios","price":5.20,"source":"seed","source_product_id":"seed_ibuprofeno_alter","currency":"EUR","available":true}, - {"name":"Salonpas Parches Analgésicos 5 unidades","brand":"Salonpas","category":"Analgésicos","price":7.80,"source":"seed","source_product_id":"seed_salonpas","currency":"EUR","available":true}, - {"name":"Fisiomer Spray Nasal 135ml","brand":"Fisiomer","category":"Respiratorio","price":11.50,"source":"seed","source_product_id":"seed_fisiomer","currency":"EUR","available":true}, - {"name":"Thealoz Duo Colirio 10ml","brand":"Thea","category":"Oftalmología","price":12.95,"source":"seed","source_product_id":"seed_thealoz","currency":"EUR","available":true}, - {"name":"Neutrogena Crema Manos Noruega 50ml","brand":"Neutrogena","category":"Dermocosmética","price":4.50,"source":"seed","source_product_id":"seed_neutrogena_manos","currency":"EUR","available":true}, - {"name":"Capricare 1 Leche en polvo 400g","brand":"Capricare","category":"Fórmulas lácteas","price":14.95,"source":"seed","source_product_id":"seed_capricare1","currency":"EUR","available":true}, - {"name":"Nutribén 2 Leche 800g","brand":"Nutribén","category":"Fórmulas lácteas","price":16.50,"source":"seed","source_product_id":"seed_nutriben2","currency":"EUR","available":true}, - {"name":"Bebelin Vitamina C 1g 20 comprimidos","brand":"Bebelín","category":"Vitaminas","price":6.95,"source":"seed","source_product_id":"seed_bebelin_vitc","currency":"EUR","available":true}, - {"name":"Lacer Pasta Dientes Sensibilidad 75ml","brand":"Lacer","category":"Oral","price":5.80,"source":"seed","source_product_id":"seed_lacer_pasta","currency":"EUR","available":true}, - {"name":"Fotosan Crema Solar FPS50 200ml","brand":"Fotosan","category":"Solar","price":22.50,"source":"seed","source_product_id":"seed_fotosan_solar","currency":"EUR","available":true} -] +{"products": [ + {"name":"Bioderma Atoderm Crema Hidratante 500ml","brand":"Bioderma","category":"Dermocosmética","price":18.95,"source":"seed","source_product_id":"seed_bioderma_atoderm","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"La Roche-Posay Anthelios Airlicium FPS50+","brand":"La Roche-Posay","category":"Solar","price":19.95,"source":"seed","source_product_id":"seed_lrp_anthelios","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Mustela Gel de Ducha 500ml","brand":"Mustela","category":"Bebé","price":12.50,"source":"seed","source_product_id":"seed_mustela_gel","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Centrum Multivitaminicos 30 comprimidos","brand":"Centrum","category":"Vitaminas","price":15.80,"source":"seed","source_product_id":"seed_centrum_multi","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Dolocordalpan 1g Paracetamol 20 sobres","brand":"Dolocordalpan","category":"Analgésicos","price":4.95,"source":"seed","source_product_id":"seed_dolocordalpan","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Nurofen Flash 400mg 20 cápsulas","brand":"Nurofen","category":"Antiinflamatorios","price":6.75,"source":"seed","source_product_id":"seed_nurofen_flash","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Omeprazol Cinfa 20mg 28 cápsulas","brand":"Cinfa","category":"Gastrointestinal","price":8.50,"source":"seed","source_product_id":"seed_omeprazol_cinfa","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Vichy Mineral 89 Sérum Hidratante 30ml","brand":"Vichy","category":"Dermocosmética","price":25.90,"source":"seed","source_product_id":"seed_vichy_mineral89","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Avène Agua Termal 300ml","brand":"Avène","category":"Dermocosmética","price":9.95,"source":"seed","source_product_id":"seed_avene_agua","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"CeraVe Crema Hidratante 340g","brand":"CeraVe","category":"Dermocosmética","price":14.95,"source":"seed","source_product_id":"seed_cerave_crema","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Ibuprofeno Alter 600mg 20 comprimidos","brand":"Alter","category":"Antiinflamatorios","price":5.20,"source":"seed","source_product_id":"seed_ibuprofeno_alter","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Salonpas Parches Analgésicos 5 unidades","brand":"Salonpas","category":"Analgésicos","price":7.80,"source":"seed","source_product_id":"seed_salonpas","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Fisiomer Spray Nasal 135ml","brand":"Fisiomer","category":"Respiratorio","price":11.50,"source":"seed","source_product_id":"seed_fisiomer","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Thealoz Duo Colirio 10ml","brand":"Thea","category":"Oftalmología","price":12.95,"source":"seed","source_product_id":"seed_thealoz","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Neutrogena Crema Manos Noruega 50ml","brand":"Neutrogena","category":"Dermocosmética","price":4.50,"source":"seed","source_product_id":"seed_neutrogena_manos","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Capricare 1 Leche en polvo 400g","brand":"Capricare","category":"Fórmulas lácteas","price":14.95,"source":"seed","source_product_id":"seed_capricare1","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Nutribén 2 Leche 800g","brand":"Nutribén","category":"Fórmulas lácteas","price":16.50,"source":"seed","source_product_id":"seed_nutriben2","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Bebelin Vitamina C 1g 20 comprimidos","brand":"Bebelín","category":"Vitaminas","price":6.95,"source":"seed","source_product_id":"seed_bebelin_vitc","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Lacer Pasta Dientes Sensibilidad 75ml","brand":"Lacer","category":"Oral","price":5.80,"source":"seed","source_product_id":"seed_lacer_pasta","source_url":"https://www.promofarma.com","currency":"EUR","available":true}, + {"name":"Fotosan Crema Solar FPS50 200ml","brand":"Fotosan","category":"Solar","price":22.50,"source":"seed","source_product_id":"seed_fotosan_solar","source_url":"https://www.promofarma.com","currency":"EUR","available":true} +]} \ No newline at end of file