Vitrina de ofertas de trabajo tech en Chile. Las pegas se obtienen parseando newsletters de LinkedIn Jobs (y otras fuentes), se almacenan en PostgreSQL y se publican como sitio estático.
Gmail (newsletters LinkedIn) ─┐
GetOnBoard (API pública v0) ├─→ n8n (parser + dedup) → PostgreSQL → Static Site (nginx)
WorkingNomads (API pública) ─┘ │
pegas.devschile.cl
| Componente | Descripción | Stack |
|---|---|---|
| Frontend | Sitio estático con buscador y filtros | HTML/CSS/JS vanilla, nginx:alpine |
| Backend | API de datos | PostgreSQL 16 (Coolify) |
| Ingestión | Lee emails y APIs de portales, parsea, guarda en BD | n8n workflow |
| Build | Genera data.json desde la BD |
Node.js (Dockerfile multi-stage) |
| Fuente | Método | Frecuencia | Filtro |
|---|---|---|---|
| Parseo de newsletter por email (2 casillas Gmail) | Cada 6h (Gmail Trigger) | Todas las categorías tech detectadas por keyword | |
| GetOnBoard | API pública v0 (sin auth), n8n/test-getonbrd.js valida el filtro |
Cada 6h (Schedule Trigger) | Categorías dev/tech (programming, mobile-developer, sysadmin-devops-qa, data-science-analytics, machine-learning-ai, cybersecurity) + solo countries incluye Chile o Remote |
| WorkingNomads | API pública /api/exposed_jobs/ (sin auth) |
Cada 6h (junto a GetOnBoard) | location=latin-america,chile; todas remotas (tags: remote) |
Fuentes evaluadas y descartadas por ahora (ver plan.md/resumen.md para detalle y razones): RemoteOK (global/US-centric, exige backlink por ToS), We Work Remotely y Remotive (sin foco LatAm), Laborum/Computrabajo/BuscoJobs Chile/beBee/JobLeads (sin API ni RSS públicos — beBee y JobLeads bloquean /api/ por robots.txt), FinderHR (es un headhunter manual, no un job board), Himalayas (API pública real pero volumen masivo y global, requiere filtro geográfico más fino antes de sumarla). Otras evaluadas en julio 2026: it-hunter.cl (bloqueado por Cloudflare, challenge JS), AcidLabs y OPTION/careers-page.com (portales de una sola empresa, sin API pública descubierta — AcidLabs es HTML plano de Odoo, OPTION es un SPA Vue/Manatal), INACAP/emplea.inacap.cl (SPA de Reqlut con token de sesión en la URL, sin resultados sin JS). Google no es una fuente: no tiene API pública de empleos, solo agrega schema.org/JobPosting de otros sitios — ver roadmap para la idea de agregar ese schema a nuestras propias pegas.
- Trigger → Gmail Trigger (LinkedIn) o Schedule Trigger (GetOnBoard + WorkingNomads), los tres cada 6h
- Parser/Fetch → Extrae o normaliza título, empleador, link, descripción, categoría, sueldo, tags
- Deduplicación → Verifica contra PostgreSQL (UNIQUE en
url,ON CONFLICT DO NOTHING) - INSERT → Guarda nueva pega en la BD (nodo único compartido por las tres fuentes)
- Redeploy en tiempo real → Si hubo pegas nuevas en esa corrida, n8n dispara restart en Coolify de inmediato, regenerando
data.json - Digest de Slack (2x/día) → A las 9:00 y 18:00, un trigger aparte junta en la BD todas las pegas nuevas desde el último aviso (de cualquier fuente, tracking vía static data del workflow) y manda un solo mensaje a
#trabajoscon hasta 5 listadas - Frontend →
index.htmlcargadata/data.jsony renderiza con filtros
├── index.html # Frontend estático
├── css/style.css # Estilos
├── js/app.js # Lógica: fetch, filtros, render
├── scripts/
│ ├── generate-json.js # Lee PostgreSQL → data.json
│ └── init-db.js # CREATE TABLE IF NOT EXISTS
├── schema.sql # Esquema de la BD
├── n8n/
│ ├── workflow.json # Workflow de n8n (exportado)
│ ├── parser-code.js # Parser LinkedIn standalone (para tests)
│ └── test-getonbrd.js # Valida en vivo el filtro Chile/Remoto de GetOnBoard
├── Dockerfile # Multi-stage: build + nginx:alpine
├── nginx.conf # Config nginx
└── README.md
Tabla pegas:
| Columna | Tipo | Descripción |
|---|---|---|
id |
SERIAL PK | |
url |
TEXT UNIQUE | Link original a la oferta — clave de deduplicación |
titulo |
TEXT | Título de la oferta |
empleador |
TEXT | Empresa |
descripcion |
TEXT | Descripción extraída |
categoria |
TEXT | Categoría (para filtros) |
ubicacion |
TEXT | Ubicación geográfica |
sueldo |
TEXT | Sueldo/rango salarial detectado, si existe |
tags |
TEXT | Tags separados por coma (ej. remote) |
fecha_publicacion |
TIMESTAMP | Fecha de la oferta (real si la fuente la entrega, si no la de ingesta) |
fuente |
TEXT | Origen: linkedin, getonbrd, etc. |
email_origen |
TEXT | Casilla de email de donde se parseó (null si no aplica) |
activo |
BOOLEAN | Soft delete (default TRUE) |
fecha_creacion |
TIMESTAMP | Fecha de ingreso al sistema |
# Instalar dependencias
npm install
# Generar data.json (requiere DATABASE_URL)
DATABASE_URL=postgres://... node scripts/generate-json.js
# Inicializar BD (crea tabla)
DATABASE_URL=postgres://... node scripts/init-db.jsHosteado en Coolify como aplicación GitHub (devschile/pegas).
Build: Dockerfile multi-stage — la etapa de build ejecuta init-db.js + generate-json.js y copia data.json a la imagen nginx final.
Variables de entorno requeridas en Coolify:
DATABASE_URL: connection string de PostgreSQL
Redeploy trigger: n8n llama a la API de Coolify para redeployar cuando hay pegas nuevas.
MIT
- Parser de LinkedIn Jobs (emails)
- PostgreSQL + deduplicación por URL
- Frontend con buscador y filtros
- Detección de sueldo/rango salarial
- GetOnBoard — API pública v0, sin auth, filtrada a Chile/Remoto (nodos
getonbrd-*enn8n/workflow.json, validado conn8n/test-getonbrd.js) - WorkingNomads — API pública
/api/exposed_jobs/, sin auth, filtrada a LatAm/Chile - Digest de Slack 2x/día (9:00 y 18:00) en vez de notificar en cada corrida — evita saturar el canal
- Fuentes adicionales — evaluadas y descartadas por ahora: ver tabla "Fuentes de pegas" más arriba. Candidata más viable a futuro: Himalayas (API pública real, pero requiere filtro geográfico más fino por su volumen global)
- Auto-expiración de pegas antiguas
- Dashboard de métricas