gasuarez-backend

Scraper + sincronización. Documentación local.

Base: http://localhost:4000

Autenticación

Si API_KEY está en .env, enviá el header en cada request (salvo esta página):

x-api-key: TU_API_KEY
# o
Authorization: Bearer TU_API_KEY

Sincronización principal (chequear data)

GET /status admin · scrape + Firestore + compare

Galerías en paralelo (workers por URL) + getCollection("propiedades") + diff por webId. Requiere credenciales Firebase en .env.

import axios from 'axios';

const API_KEY = 'TU_API_KEY';
const BASE = 'http://localhost:4000';

const { data } = await axios.get(`${BASE}/status`, {
  headers: { 'x-api-key': API_KEY },
  timeout: 600000,
});

console.log(data.summary, data.propiedadesCount);

Solo array vidriera: GET /api/scrape/listing · Sin galerías: ?galleries=false

Respuesta /status (ejemplo ítem)

[{
  "webId": "5894945",
  "Href": "https://www.gasuarez.com.ar/p/5894945-...",
  "Titulo": "...",
  "VENTA": 80000,
  "ALQUILER": false,
  "Images": ["https://...", "https://..."]
}]

Una propiedad (ficha completa)

GET /propiedades?url=...
const url = 'https://www.gasuarez.com.ar/p/4340627-casa-en-venta-...';

const { data } = await axios.get(`${BASE}/propiedades`, {
  params: { url },
  headers: { 'x-api-key': API_KEY },
  timeout: 60000,
});

console.log(data);

Equivalente: GET /api/scrape/property?url=...

Firestore — getCollection

GET /api/firebase/collection/:name

Misma función que usa el sync internamente. Ejemplo: propiedades (excluye doc metadata).

import axios from 'axios';

const { data } = await axios.get(`${BASE}/api/firebase/collection/propiedades`, {
  headers: { 'x-api-key': API_KEY },
});
console.log(data.count, data.data[0]);

Salud del servidor

GET /health sin Puppeteer · rápido
const { data } = await fetch(`${BASE}/health`).then((r) => r.json());

Validar catálogo (web vs mapas)

GET /api/sync/catalog/preview

Scrape + diff por webId con Firestore. No escribe.

const { data } = await axios.get(`${BASE}/api/sync/catalog/preview`, {
  headers: { 'x-api-key': API_KEY },
});

Aplicar sync (bulk — cron)

POST /api/sync/catalog/apply

Borra caducadas, agrega nuevas, merge en modificadas (setSingleDoc — no pisa coords ni serviciosPublicos) y metadata. dryRun: true por defecto.

// Preview (no escribe)
const { data } = await axios.post(`${BASE}/api/sync/catalog/apply`, {
  dryRun: true,
}, { headers: { 'x-api-key': API_KEY }, timeout: 600000 });

console.log(data.deletesPlanned, data.deletesPreview, data.metadataPreview);

// Ejecutar (requiere FIREBASE_WRITES_ENABLED=true en .env)
const applied = await axios.post(`${BASE}/api/sync/catalog/apply`, {
  dryRun: false,
  deleteRemoved: true,
}, { headers: { 'x-api-key': API_KEY }, timeout: 600000 });

Resumen de rutas

RutaUso
GET /health¿Servidor vivo?
GET /statusArray vidriera + Images[] (admin)
GET /api/sync/catalog/previewScrape + compare Firestore
GET /propiedades?url=Ficha de una URL
GET /api/firebase/collection/propiedadesgetCollection("propiedades")
POST /api/sync/catalog/applyEscribir en DB (flag apagado)

Probar /health · Reemplazá TU_API_KEY por el valor de API_KEY en tu .env.