Verificado contra la base y el código de hoy, 2026-08-12 · evidencia por punto, no resumen · A4 fuera de alcance por decisión tuya
Parte 3 · Respuestas
3.1 · Contrato del endpoint src/routes/api/admin/eventos/ingest/+server.ts
- Token: header
Authorization: Bearer <INGEST_SECRET>.
- Body: JSON, objeto
{ "fuente": "luma", "eventos": [ ... ] } (no array plano). fuente a nivel raíz.
- Por evento — obligatorios:
id_fuente, nombre, fecha_inicio (YYYY-MM-DD), y pais_code salvo modalidad online. Opcionales: modalidad (default presencial), fecha_finalizacion (default = inicio), zona_horaria (default America/Bogota), ciudad, estado_provincia, ubicacion_texto, ubicacion_lat, ubicacion_lng, costo_inscripcion, link_registro/link_evento/link_sesion, mas_informacion, super_evento_id, url_fuente.
- Los JSONB (
horarios, tematicas, actividades, organizadores_raw, hosts_speakers) van como array/objeto, no string.
- Respuesta:
{ ok, fuente, summary:{total,created,updated,errors}, results:[{id_fuente, status: created|updated|error, evento_id, evento_codigo, error?}] }. Distingue por evento con motivo e id_fuente, y devuelve el evento_codigo.
- Fallo de un evento: se registra su error y sigue con el resto del lote.
- Cuenta de sistema:
contact_email = ingesta@lpdi.co, registered_by = null (no hay UUID de usuario; en el panel el evento aparece con ese correo). No se crea ningún usuario.
- Tope por lote: 500. No hay rate limit ni modo dry-run.
Ejemplo mínimo de request:
POST /api/admin/eventos/ingest Authorization: Bearer <secret>
{ "fuente":"luma", "eventos":[ { "id_fuente":"evt-123", "nombre":"Demo Day", "fecha_inicio":"2026-09-10", "modalidad":"presencial", "pais_code":"Colombia", "ciudad":"Bogotá", "url_fuente":"https://lu.ma/xxx", "tematicas":[], "organizadores_raw":[{"rol":"Organizador","nombre":"Pygma"}] } ] }
3.2 · Publicación programada sin riesgo
Corrección (2026-08-12): mi reporte anterior estaba mal. El catálogo público (eventosPublicos.ts línea 172) filtra solo por status APPROVED y sin papelera, NO por publish_at. El propio código cita la regla de Frank (#6): la visibilidad depende exclusivamente de la aprobación, no de la fecha ni de publish_at. Un evento aprobado aparece de inmediato aunque su fecha sea futura. La aprobación en lote escribe publish_at, pero el catálogo lo ignora, así que los eventos NO quedan ocultos. No hay riesgo aquí.
3.3 · Eventos finalizados
Por el panel, un evento finalizado (fecha fin < hoy) es de solo lectura salvo super_admin. Pero el endpoint de ingesta usa service-role y sí puede actualizar un evento finalizado (no chequea la fecha): si el scraper reenvía uno ya terminado, lo actualiza sin fallar. No lo cambié, solo te confirmo el comportamiento.
3.4 · Geocodificación
El endpoint no geocodifica. Toma ubicacion_lat/lng si vienen; si mandás dirección sin coordenadas, el evento queda sin lat/lng. La geocodificación la tenés que resolver vos antes de enviar (o aceptar que esos queden sin punto en el mapa).
Parte 4 · Lo que falta para ingerir con seguridad
Bloquea o conviene resolver antes de la primera carga grande
- Volumen de correos (B3): 150 aprobaciones de eventos ingeridos disparan ~150 correos a
ingesta@lpdi.co. Si no querés ese ruido, conviene silenciar el correo para la cuenta de sistema antes de la primera curación masiva.
- Geocodificación del scraper (3.4): el endpoint no geocodifica texto suelto (el formulario sí, vía Google Places). Definí si mandás coords resueltas o aceptás eventos ingeridos sin punto en el mapa.
Nota: el riesgo de "publish_at oculta eventos futuros" que reporté antes NO aplica; era un error mío de verificación, corregido en 3.2. La visibilidad depende solo de la aprobación.
Puede esperar (no bloquea la ingesta)
- A6 · 485 placeholders: son de eventos históricos ya cargados; el endpoint ya limpia el placeholder de los NUEVOS ingeridos, así que la carga no los reintroduce. Puedo vaciar los 485 cuando digas (la geo se conserva).
- A5 · ~28 compuestos residuales + 2 basuras: no afectan la ingesta; los puedo separar/limpiar en una pasada corta, con tu visto bueno de la lista.
Riesgo que no preguntaste
El endpoint puede actualizar eventos ya finalizados (3.3). Si el scraper reprocesa ediciones viejas de Luma, podría tocar eventos que ya ocurrieron. Si no querés eso, se puede agregar un guard de "no actualizar si fecha fin < hoy". Hoy no está.