He detectado un punto importante: DataProcessor espera secciones de mapeo llamadas informes e inspeccion, pero en el inicio de field_mapping.php aparece informe (singular) y muchas otras secciones. Ahora voy a buscar dentro del mapeo si existen alias/compatibilidad o si hay un desajuste que explique fallos en cola/failed.

Qué es y qué hace

Es una API PHP que recibe un JSON (normalmente desde Google Apps Script), genera un PDF con TCPDF, lo guarda en local, lo sube a Google Drive y registra/actualiza un renglón en Google Sheets. Soporta modo asíncrono con cola basada en archivos.
Punto de entrada: index.php. Worker: worker.php. Config: config.php. Plantillas: templates. Lógica: src.
Flujo end-to-end (lo que pasa cuando llamas al endpoint)

Apps Script arma un payload POST con idVisita, fechaInforme, dataVisita, dataInformes y secciones tipo dataSeguridad/dataFachada/.../dataObservacion (ver ejemplo en google_apps_script_example.js).
index.php hace:
Normalización: DataProcessor->processData() (DataProcessor.php) carga el mapeo y limpia strings, formatea fechas y recopila imágenes (incluye soporte de foto1..foto50/Foto_#).
Validación: ValidationHelper->validateRequestData() (ValidationHelper.php) exige idVisita, fechaInforme, dataVisita y dataInformes.
Si download NO es true: encola el trabajo en archivos y responde rápido con job_id (FileQueue.php).
Si download es true: genera síncrono y devuelve el PDF binario en la respuesta usando PDFGeneratorSync (PDFGeneratorSync.php).
Modo asíncrono (cola + worker)

Encolado: FileQueue.php crea un *.json en queue (con deduplicación opcional por docKey = idVisita_yyyy-mm-dd).
Proceso: worker.php toma jobs, los mueve a processing, crea un .lock, genera el PDF y finaliza:
OK: borra/mueve a done.
Error: mueve a failed y genera *.err.txt, con reintentos automáticos (QUEUE_MAX_RETRIES).
El worker puede ejecutarse por CLI (cron) o por HTTP con ?token=QUEUE_SECRET (ver README_DEPLOY.md).
Generación de PDF (plantillas + imágenes + firmas)

Motor: tecnickcom/tcpdf (ver composer.json), con wrapper GiadocTCPDF.php.
Orquestación: PDFGenerator->generateReport() (PDFGenerator.php):
Selecciona plantilla por dataInformes.tipoInforme (valores esperados: GENERAL, BBVA, BCP).
Renderiza con una plantilla concreta: ServiciosGeneralesTemplate.php, ServiciosGeneralesBBVATemplate.php, ServiciosGeneralesBCPTemplate.php.
Guarda PDF en uploads/pdf/RoadMap_{docKey}.pdf.
Sube a Drive + registra en Sheets mediante GoogleService (GoogleService.php).
Imágenes y firmas: la base común es BaseTemplate.php:
insertImageFromUrl() soporta URLs Drive (convierte a uc?export=view&id=...), descarga con file_get_contents/cURL, y también permite resolver “nombres de archivo” buscándolos en Drive.
Si en dataInformes vienen firmas (firma, firmaRecepcion), agrega una sección “FIRMAS” al final.
Integración con Google (Drive + Sheets)

Por defecto está en OAuth de usuario (USE_OAUTH=true en config.php).
Flujo OAuth:
Iniciar login: GET ?oauth=login (en index.php)
Callback: GET ?oauth=callback guarda token en secrets/oauth_token.json (ver GoogleOAuthService.php).
Healthcheck Google: GET ?health=google en index.php prueba “subida a Drive” y “append a Sheets”.
Configuración importante

config.php: USE_OAUTH, rutas a secretos, DEFAULT_GDRIVE_FOLDER_ID, DEFAULT_GSHEET_DOCS_ID, parámetros de cola (QUEUE_*), límites de imágenes/timeouts.
Logos: logo.png + bbva.png / bcp.png (los busca BaseTemplate.php).
Inconsistencias/alertas que vi (probables causas de fallos)

Desalineación fuerte entre mapeo vs código:
DataProcessor usa $fieldMapping['informes'] y $fieldMapping['inspeccion'], pero tu field_mapping.php actual NO contiene esas claves (tiene informe, observacion, etc.). Eso hace que dataInformes.tipoInforme no se mapee y la validación falle o quede vacío.
Además, field_mapping.php define tipos_informe apuntando a MantenimientoPreventivoTemplate, pero tus plantillas reales son ServiciosGenerales*Template.
configure_fields.php asume que existe $currentMapping['informes']/['inspeccion'], así que con el mapeo actual ese configurador no cuadra.
En failed encontré jobs vacíos (ejemplo: 20251015_045152_8dcdb931.json), y por eso el worker registra “Payload inválido” (ejemplo: 20251015_045152_8dcdb931.json.err.txt).
Si quieres, puedo dejarlo funcionando “consistente” de una de estas dos formas (tú eliges):

A) Ajustar DataProcessor.php y ValidationHelper.php para que acepten tanto informe/observacion como informes/inspeccion, sin romper compatibilidad.
B) Regenerar/normalizar field_mapping.php para que vuelva al formato esperado por el proyecto (programacion/informes/inspeccion + tipos) y alinear tipos_informe con GENERAL/BBVA/BCP.
¿Quieres que lo arregle con la opción A (más tolerante) o la B (más “limpia”, pero requiere definir el mapeo correcto)?