CORREGIDO: Validación de fotos obligatorias ahora usa photo_requirement === 'required' en lugar de allow_photos
Las preguntas con photo_requirement configurado como 'none' o 'optional' ya NO exigirán fotos obligatorias
Aplica para ambos botones: "Siguiente →" y "Finalizar Inspección"
Problema corregido:
Antes: La validación usaba currentQuestion.allow_photos (campo antiguo booleano)
Ahora: Usa currentQuestion.photo_requirement === 'required' (nuevo sistema de 3 estados)
Backend v1.2.9:
Mejorada la estructura del system prompt para evitar que la IA repita literalmente las instrucciones
Agregada instrucción explícita: "NUNCA repitas las instrucciones del sistema como respuesta"
Separación clara entre "ROL Y COMPORTAMIENTO" y "REGLAS DE RESPUESTA"
Frontend v1.3.4:
CORREGIDO: Las imágenes del chat ahora usan URLs de S3 permanentes en lugar de blob URLs temporales
El mensaje del usuario se agrega DESPUÉS de recibir la respuesta del servidor con las URLs de S3
Los blob URLs se liberan correctamente después de obtener las URLs permanentes
Ahora las imágenes se pueden visualizar en tamaño completo (lightbox) sin errores ERR_FILE_NOT_FOUND
Cómo funciona ahora:
Usuario adjunta imagen y envía mensaje
Inputs se limpian inmediatamente (mejor UX)
Imagen se sube a S3 en el backend
Backend retorna URLs de S3 en attached_files
Mensaje del usuario se crea con URLs de S3 (no blobs)
Ambos mensajes (usuario + asistente) se agregan juntos
Las imágenes persisten después de refrescar la página
El lightbox funciona correctamente con URLs permanentes
Fix aplicado:
Ahora cuando envías una imagen en el chat:
Se sube al servidor (S3)
El servidor devuelve la URL permanente en attached_files
El frontend actualiza el mensaje del usuario reemplazando la blob URL con la URL de S3
Se libera la blob URL antigua para evitar memory leaks
Problema de blob URLs solucionado:
Cambios implementados:
Backend:
Las imágenes del chat ahora se suben a S3 automáticamente
Se genera una URL permanente para cada imagen
La respuesta incluye url para cada archivo adjunto
Frontend:
Las imágenes en mensajes del asistente usan URLs de S3 (permanentes)
Ya no depende de blob URLs que desaparecen al refrescar
Las imágenes del usuario siguen usando blob (temporal solo para preview)
Las imágenes del asistente se muestran con URLs persistentes
Resultado:
✅ Las imágenes del chat ahora funcionan después de refrescar
✅ Las URLs son permanentes y accesibles
✅ No más errores 404 con blob: URLs
✅ Las imágenes quedan guardadas en S3 para historial
Cambios implementados:
Frontend:
Ahora envía context_answers con todas las respuestas de preguntas anteriores (texto + observaciones)
Incluye el texto de la pregunta para mejor contexto
Funciona con la configuración de IDs de preguntas o todas las anteriores
Backend:
Recibe y procesa context_answers
Agrega sección "RESPUESTAS DE PREGUNTAS ANTERIORES" al system prompt
Muestra pregunta, respuesta y observaciones de cada pregunta previa
Cambios en esta versión:
Fix: Selección visual de modelos ahora se muestra inmediatamente al hacer click en un proveedor
Los modelos se muestran seleccionados en el formulario antes de guardar la configuración
Backend v1.2.1
Mejoras en gestión de API keys multi-proveedor:
Nuevo endpoint /api/ai/api-keys: Retorna todas las API keys guardadas por proveedor (enmascaradas para seguridad)
Formato: {"openai": {"has_key": true, "masked_key": "sk-proj...xyz", "is_active": false}}
Solo administradores pueden acceder
Endpoint /api/ai/configuration mejorado:
Ahora preserva API keys existentes cuando se cambia de proveedor
Si ya existe configuración para un proveedor, solo actualiza el modelo y activa ese proveedor
Solo requiere API key nueva si no existe configuración previa para ese proveedor
Validación: no acepta API keys vacías para nuevos proveedores
Persistencia de configuraciones:
Cada proveedor (OpenAI, Anthropic, Gemini) mantiene su registro en la base de datos
Solo uno tiene is_active=True a la vez
Al cambiar de proveedor, se desactiva el anterior pero NO se elimina
Frontend v1.2.6
UX mejorada para configuración de IA:
Indicadores visuales en botones de proveedor:
Badge "✓ ACTIVO" en verde para el proveedor actualmente activo
Badge "Configurado" en gris para proveedores con API key guardada pero inactivos
Sin badges para proveedores no configurados
Selector de modelos inteligente:
Solo muestra modelo seleccionado si el proveedor está activo
Al hacer click en un proveedor inactivo, NO se pre-selecciona ningún modelo
Solo al GUARDAR se activa el proveedor con el modelo seleccionado
Input de API key con contexto:
Muestra key enmascarada si ya existe: ✓ Ya tienes una API key guardada: sk-proj...xyz
Permite dejar vacío para mantener la key actual
Solo requiere key nueva si el proveedor no tiene una guardada
Flujo de trabajo mejorado:
Click en proveedor → Cambia tab de formulario
Si ya tiene key guardada → Se muestra enmascarada, puede mantenerla
Seleccionar modelo → Click en "Guardar Configuración"
Solo entonces se ACTIVA ese proveedor y modelo
Beneficios
No re-ingresar API keys: Al cambiar entre proveedores, las keys se preservan
Claridad visual: Solo el proveedor activo muestra badge verde y modelo seleccionado
Seguridad: API keys enmascaradas en la UI (sk-proj...xyz)
Flexibilidad: Configurar los 3 proveedores y cambiar entre ellos sin perder configuración
Versiones actualizadas:
Backend: 1.2.0 → 1.2.1
Frontend: 1.2.5 → 1.2.6
Service Worker: cache v1.2.6
🔧 Backend v1.2.0 | Frontend v1.2.5
He implementado completamente el soporte para Anthropic Claude y corregido el problema de visualización en el módulo de configuración:
🎯 Cambios Implementados:
1. Backend - Soporte para Anthropic Claude
Nuevos modelos agregados:
Claude Sonnet 4.5 (Recomendado) - Equilibrio perfecto
Claude Opus 4.5 - Máxima capacidad
Claude Haiku 4.5 - Ultra rápido y económico
Integración completa:
Chat Assistant con Anthropic
Generación de resúmenes PDF con Anthropic
Manejo correcto de formato de mensajes (system separado)
Configuración por defecto: claude-sonnet-4.5
FRONTEND:
- Implementado visor de imágenes (lightbox) dentro del modal de chat
- Click en imagen abre pantalla completa en lugar de nueva pestaña
- Fondo negro translúcido (95%) con z-index 200
- Botón de cerrar (×) en esquina superior derecha
- Click en imagen/fondo cierra el lightbox
- Etiqueta flotante con nombre de archivo
- Cursor zoom-in en miniaturas para indicar ampliación
- Responsive: max 95vw/95vh con scroll automático
- Frontend v1.2.4
BACKEND:
- Sin cambios (v1.1.1)
📸 Frontend actualizado a v1.2.3
He implementado un sistema completo de previsualización de imágenes en el chat assistant:
🎨 Características Implementadas:
1. Preview Antes de Enviar (Zona de Input)
Miniaturas 20x20px con superposición de nombre
Botón de eliminar en esquina superior derecha (rojo con X)
Fondo oscuro translúcido para nombre del archivo
Hover effects para mejor UX
// Vista previa antes de enviar:
┌─────────────────────────────┐
│ [IMG] [IMG] 📄 file.pdf │ ← Miniaturas clickeables
│ ✕ ✕ ✕ │
└─────────────────────────────┘
2. Imágenes en Mensajes del Chat
Renderizado completo de imágenes en mensajes del usuario
Máximo 256px de altura (responsive)
Click para abrir en nueva pestaña (full size)
Metadata bajo la imagen (nombre + tamaño)
Esquina redondeada para mejor diseño
Transición hover (opacity 90%)
// Mensaje del usuario con imagen:
┌────────────────────────────┐
│ [Texto del mensaje] │
│ │
│ ┌────────────────────────┐ │
│ │ │ │
│ │ [IMAGEN PREVIEW] │ │ ← Click para ampliar
│ │ │ │
│ └────────────────────────┘ │
│ 🖼️ photo.jpg (128.5 KB) │
│ │
│ 10:45 │
└────────────────────────────┘
3. Gestión de Memoria
URLs temporales con URL.createObjectURL()
Limpieza automática al eliminar archivo
useEffect cleanup al desmontar modal
No memory leaks garantizados
Frontend: v1.2.0 → v1.2.1
package.json
Sidebar.jsx
service-worker.js (PWA)
Backend: v1.0.96 → v1.0.97
main.py
Cambios incluidos en v1.2.1 / v1.0.97:
✅ Paginación de inspecciones (ya estaba implementada con 10 items)
✅ Limpieza de sesiones de chat al cambiar de pregunta
✅ Campo "Número de OR" obligatorio
✅ Eliminación de referencias "IA" → "Asistente Ayutec"
Inspección nueva, Pregunta 1 (Frenos):
Abro chat → aiChatMessages = [] (vacío)
Pregunto sobre frenos
Cierro → se guarda en answers[pregunta1].chatHistory
Misma inspección, Pregunta 2 (Neumáticos):
Abro chat → aiChatMessages = [] (vacío, porque esta pregunta no tiene historial)
Chat limpio, sin mezclar con frenos ✅
Vuelvo a Pregunta 1:
Abro chat → aiChatMessages = [historial guardado]
Veo mi conversación anterior sobre frenos ✅
Nueva inspección en otro momento:
Todas las preguntas empiezan con aiChatMessages = []
No se mezcla con inspecciones anteriores ✅
He implementado el sistema de 3 estados para el requisito de fotos/archivos que solicitaste.
Problema Original:
Solo había 2 estados:
✅ Permitir fotos (checkbox activado)
❌ No permitir fotos (checkbox desactivado)
Faltaba: Fotos opcionales vs obligatorias
Solución Implementada:
3 Estados disponibles:
🚫 No permitir adjuntos (photo_requirement = 'none')
No se muestra el input de fotos
El mecánico NO puede adjuntar archivos
📎 Opcional (photo_requirement = 'optional')
Se muestra el input de fotos
El mecánico PUEDE adjuntar si lo desea
No es obligatorio para continuar
⚠️ Obligatorio (photo_requirement = 'required')
Se muestra el input de fotos con etiqueta "OBLIGATORIO"
El mecánico DEBE adjuntar al menos 1 archivo
Validación bloquea continuar sin adjuntos
He identificado y solucionado el bug que causaba que las subpreguntas recién creadas aparecieran al principio (asociadas a la primera pregunta) hasta que las arrastraras.
Problema Identificado:
Cuando creabas una subpregunta, el backend asignaba order = 0 por defecto, lo que hacía que:
La subpregunta apareciera al principio de la lista
Al arrastrarla, el sistema recalculaba el orden y la colocaba correctamente debajo de su padre
Solución Implementada:
Backend (v1.0.93) - main.py:
Modifiqué el endpoint POST /api/questions para calcular automáticamente el order correcto al crear una pregunta:
Formulario mejorado (App.jsx):
Selector de pregunta padre SIEMPRE disponible para cualquier tipo
Selector de condición opcional (solo si el padre es boolean/single_choice)
Indicadores visuales claros:
Verde: "Esta subpregunta aparecerá SIEMPRE"
Azul: "⚡ Condición aplicada"
Visualización distinguible:
Badge verde 📎 para subpreguntas siempre visibles
Badge azul ⚡ para subpreguntas condicionales
Texto explicativo debajo de cada subpregunta
Frontend: 1.0.96 → 1.0.97
Service Worker: 1.0.96 → 1.0.97
Backend: 1.0.92 (sin cambios)
Resultado:
✅ Las preguntas padre se mueven CON todos sus hijos
✅ Los hijos mantienen su orden relativo al padre
✅ No hay conflictos de orden entre preguntas
✅ El sistema usa espaciado inteligente (0, 10, 20...) para evitar colisiones
✅ Las subpreguntas solo se mueven dentro de su padre
Efectos Visuales Añadidos:
Al iniciar el arrastre:
La pregunta se vuelve semi-transparente (40% opacidad)
Se aplica un ligero zoom out (scale 0.98)
Aparece un borde morado brillante (ring-2 ring-purple-500)
Durante el arrastre sobre una pregunta:
La zona de destino se resalta con fondo morado claro
Borde superior morado grueso (4px)
Sombra pronunciada para destacar la zona
Indicador visual claro: Badge flotante que dice "Se moverá ANTES de esta pregunta" con ícono de cruz
Transiciones suaves:
Todas las transformaciones tienen duration-200 para animaciones fluidas
El elemento arrastrado mantiene su escala reducida durante el movimiento
Al soltar:
Se restauran todos los estilos originales
La pregunta regresa a opacidad 100% y escala normal
Ordenamiento consistente de preguntas (App.jsx):
Las preguntas ahora se ordenan por el campo order antes de agruparse por sección
Esto asegura que el orden se mantenga exactamente como está en el backend
Ordenamiento de secciones (App.jsx):
Las secciones se ordenan por el order mínimo de sus preguntas
Garantiza que las secciones aparezcan en orden lógico y consistente
Mejora en drag-and-drop (App.jsx):
Al reordenar, ahora se ordenan las preguntas por order antes de calcular nuevas posiciones
Los nuevos valores de order se asignan correctamente preservando el orden relativo
Funciona correctamente con una sola sección y con subpreguntas
Ordenamiento en modo inspección (App.jsx):
getVisibleQuestions() ahora ordena las preguntas visibles por su campo order
Mantiene el orden correcto durante la ejecución de inspecciones
Backend (v1.0.92)
No se requirieron cambios en el backend (ya estaba ordenando correctamente con order_by(models.Question.order))
🎯 Nueva Funcionalidad Completa
Se ha implementado un sistema de chat conversacional con IA que permite adjuntar archivos (imágenes y PDFs), similar a ChatGPT, con prompt personalizable y envío completo al webhook.
📋 Características Implementadas
1. Adjuntar Archivos en el Chat
✅ Botón 📎 para adjuntar archivos
✅ Soporte para imágenes (JPG, PNG, etc.) y PDFs
✅ Preview de archivos adjuntos antes de enviar
✅ Eliminación individual de archivos adjuntos
✅ Múltiples archivos por mensaje
✅ Validación de tipos de archivo
2. Procesamiento Backend de Archivos
✅ Endpoint modificado para recibir FormData con archivos
✅ PDFs: Extracción automática de texto con pypdf
✅ Imágenes: Conversión a base64 para Vision AI
✅ Análisis combinado de texto + imágenes
✅ Límite de 2000 caracteres por PDF para optimizar
3. Integración con IA
✅ OpenAI Vision: Soporte multimodal (texto + imágenes)
✅ Gemini: Soporte de imágenes y texto
✅ Contexto enriquecido con archivos adjuntos
✅ Prompts adaptados según tipo de archivo
4. Custom Prompt por Checklist
✅ Campo assistant_prompt configurable por pregunta
✅ Campo assistant_instructions para instrucciones adicionales
✅ Control de longitud de respuesta (short/medium/long)
✅ Contexto automático del vehículo en cada mensaje
5. Persistencia del Chat
✅ Nuevo campo chat_history en modelo Answer
✅ Migración SQL: add_chat_history_to_answers.sql
✅ Guardado automático del historial completo
✅ Restauración del chat al reabrir
6. Envío al Webhook (n8n)
✅ Todos los chats incluidos en send_completed_inspection_to_n8n()
✅ Campo chat_history en cada respuesta del webhook
✅ Incluye metadata de archivos adjuntos
✅ Tipo de pregunta identificado en webhook
✅ Datos completos para análisis posterior
📋 Cambios Implementados
Frontend:
✅ Input acepta image/*,application/pdf
✅ Label actualizado: "Fotografías / Documentos PDF *"
✅ Preview diferenciado: PDFs muestran icono 📝 rojo en lugar de imagen
✅ Nombre de archivo PDF visible en el preview
✅ Contador genérico: "archivo(s) cargado(s)"
Backend:
✅ Agregado pypdf==4.0.1 a requirements.txt
✅ Detección automática de PDFs por content_type o extensión
✅ Extracción de texto de PDFs usando pypdf.PdfReader
✅ Validación de PDFs vacíos (sin texto extraíble)
✅ Prompts adaptados automáticamente para PDFs
✅ Soporte en OpenAI y Gemini (análisis de texto en lugar de vision)
✅ Límite de 4000 caracteres del PDF para análisis
🎯 Funcionamiento
Usuario sube PDF → Sistema detecta tipo de archivo
Extrae texto → PyPDF lee todas las páginas
Análisis IA → Envía texto al modelo (no usa Vision API)
Respuesta → Misma estructura JSON que con imágenes
⚠️ Limitaciones
PDFs escaneados sin OCR no funcionarán (requieren texto seleccionable)
Máximo 4000 caracteres del PDF enviados al AI
📦 Versiones
Frontend: 1.0.91 → 1.0.92
Backend: 1.0.89 → 1.0.90
✅ Agregado checkbox "Agregar campo observaciones" en QuestionTypeEditor.jsx (sección "Opciones Generales")
✅ Por defecto está marcado (compatibilidad con preguntas existentes)
✅ El campo de observaciones solo se muestra si show_observations !== false
✅ El admin ahora tiene control total sobre si mostrar o no las observaciones
2. Botón "Consultar Asistente IA" Siempre Visible
✅ El botón ahora aparece siempre para preguntas tipo ai_assistant
✅ No depende de que la pregunta tenga fotos habilitadas
✅ Movido a una sección independiente (fuera del bloque de fotos)
✅ Removido el botón duplicado que estaba dentro de la sección de fotos
3. Versiones Actualizadas
Frontend: 1.0.89 → 1.0.90
Service Worker: ayutec-v1.0.89 → ayutec-v1.0.90
Backend: Sin cambios (no fue necesario)
📋 Detalles Técnicos
App.jsx:
Campo de respuesta oculto para photo_only y ai_assistant
Botón de Asistente IA en sección dedicada (siempre visible para ai_assistant)
Observaciones solo si show_observations !== false y no es photo_only ni ai_assistant
QuestionTypeEditor.jsx:
Nueva sección "⚙️ Opciones Generales" con checkbox azul
Texto de ayuda: "Si está marcado, el mecánico podrá agregar notas adicionales"
Cambios Realizados
Service Worker (public/service-worker.js)
❌ Removido skipWaiting() automático en install
❌ Removido claim() automático en activate
✅ Solo se activa cuando recibe mensaje SKIP_WAITING del usuario
App.jsx
✅ Modal se muestra cuando hay actualización
✅ Nueva versión se instala en segundo plano
⏸️ Espera confirmación del usuario
✅ Solo actualiza cuando el usuario presiona el botón
✅ Protección contra recargas múltiples (refreshing flag)
Flujo Actualizado
Deploy de nueva versión (ej: v1.0.89)
Usuario abre la app con versión antigua (v1.0.88)
Service Worker detecta nueva versión
Descarga en segundo plano la nueva versión
Modal aparece → "¡Nueva Actualización!"
⏸️ La app sigue funcionando normalmente
👆 Usuario presiona "🚀 ACTUALIZAR AHORA"
Service Worker se activa (skipWaiting)
Página se recarga automáticamente
✅ Nueva versión activa
Ventajas
✅ Usuario tiene control total
✅ No interrumpe trabajo en curso
✅ Puede terminar inspección antes de actualizar
✅ Modal bloqueante asegura que eventualmente actualice
✅ Actualización instantánea al presionar botón
Ahora el usuario DEBE presionar el botón para actualizar! 🎯
Frontend (v1.0.88)
QuestionTypeEditor.jsx
✅ Nuevo tipo: ai_assistant con icono 💬✅ Configuración completa:
assistant_prompt: Define rol y comportamiento del asistente
context_questions: IDs de preguntas anteriores cuyas fotos usar (o todas)
assistant_instructions: Reglas específicas de diagnóstico
max_messages: Límite de mensajes en el chat
response_length: Corta/Media/Larga
QuestionAnswerInput.jsx
✅ Mensaje informativo para tipo ai_assistant
✅ Indica que el chat se abre con botón separado
App.jsx - Modal de Chat IA
✅ Modal full-screen responsive con:
Header con gradiente purple/blue
Área de mensajes con scroll
Input de texto + botón enviar
Soporte Enter para enviar
Indicador de "pensando..."
Timestamps en mensajes
Confianza de la IA
Límite de mensajes
✅ Botón "💬 Consultar Asistente IA" al lado de "Cargar Documentos"
✅ Contador de mensajes en el botón si ya hay historial
✅ Historial guardado en answers[questionId].chatHistory
✅ Auto-marca como completada cuando se abre el chat
Backend (v1.0.85)
Endpoint /api/ai/chat-assistant
✅ Recibe:
Mensaje del usuario
Historial del chat
Fotos de preguntas anteriores con sus análisis
Configuración del asistente
Info del vehículo
✅ Contexto inteligente:
Información del vehículo (marca, modelo, km, placa)
Análisis previos de fotos (hasta 10 fotos más relevantes)
Instrucciones personalizadas por pregunta
Historial conversacional (últimos 10 mensajes)
✅ Soporte multi-proveedor:
OpenAI (GPT-4, GPT-3.5)
Google Gemini
✅ Respuestas adaptables:
Longitud configurable (200/400/800 tokens)
Temperature 0.7 para balance creatividad/precisión
Cómo Funciona
Configuración (Admin):
- Crear pregunta tipo "Asistente IA (Chat)"
- Definir prompt: "Eres experto en sistemas de frenos..."
- Seleccionar preguntas anteriores: "5,8,12" (fotos de frenos)
- Instrucciones: "Si pastillas < 3mm → cambio inmediato"
- Longitud: Media
- Max mensajes: 20
2 Durante Inspección (Mecánico):
- Llega a pregunta tipo AI Assistant
- Ve botón "💬 Consultar Asistente IA"
- Clic → Abre chat full-screen
- La IA YA vio las fotos de preguntas 5, 8, 12
- Mecánico pregunta: "¿Las pastillas están bien?"
- IA responde basado en fotos previas + contexto vehículo
- Conversación natural con historial
- Al cerrar → se guarda automáticamente
3 Ejemplo de Conversación:
Mecánico: "Vi desgaste en las pastillas, ¿qué recomiendas?"
IA: "Basándome en las fotos que analicé:
Pastilla delantera izquierda: ~2.5mm de espesor
Pastilla delantera derecha: ~2.8mm
⚠️ CRÍTICO: Ambas pastillas están por debajo del
mínimo de 3mm. Con 45,000 km, es normal este desgaste.
RECOMENDACIÓN:
- Cambio INMEDIATO de pastillas delanteras
- Verificar estado de discos (posible rectificado)
- Revisar líquido de frenos (última foto muestra nivel bajo)
¿Necesitas el código de pieza para este Toyota Corolla 2019?"
Casos de Uso
Diagnóstico de Frenos
assistant_prompt: "Eres especialista en sistemas de frenos.
Analiza desgaste, fugas, vibraciones."
context_questions: "10,11,12,13" // Fotos de pastillas, discos, líquido
assistant_prompt: "Experto en motores. Detecta fugas, ruidos anormales,
consumo excesivo."
context_questions: "5,6,7,8,9" // Motor, aceite, correa, filtros
assistant_prompt: "Especialista en sistemas eléctricos y electrónicos."
context_questions: "20,21,22" // Batería, luces, tablero
instructions: "Siempre pedir código OBD2 si hay check engine"
Ventajas
✅ Contextual: La IA ve fotos previas, no pregunta "¿puedes mostrarme?"
✅ Especializado: Un asistente POR tema (frenos, motor, eléctrico)
✅ Conversacional: El mecánico puede hacer follow-up questions
✅ Guiado: Instrucciones específicas por tipo de inspección
✅ Historial: No repite info, mantiene contexto de la conversación
✅ Móvil-friendly: Modal responsive, fácil de usar en celular
Frontend (v1.0.87)
Service Worker (public/service-worker.js)
✅ Cache versionado dinámico: ayutec-v1.0.87
✅ Estrategia Network-First con fallback a cache
✅ Auto-limpieza de caches antiguos en activación
✅ Skip waiting para activación inmediata
✅ Soporte para mensaje SKIP_WAITING desde cliente
Detección de Actualizaciones (App.jsx)
✅ Registro automático de Service Worker
✅ Listener de updatefound para detectar nuevas versiones
✅ Listener de controllerchange para recarga automática
✅ Estado updateAvailable y waitingWorker
Modal de Actualización
✅ Diseño grande y llamativo con animación bounce
✅ Overlay bloqueante (z-index 9999, no se puede cerrar)
✅ Botón enorme: "🚀 ACTUALIZAR AHORA"
✅ Gradiente indigo/purple, responsive
✅ Texto claro: "Nueva versión disponible"
✅ Recarga automática al actualizar
PWA Manifest (site.webmanifest)
✅ Agregado start_url y scope
✅ Configurado orientation: portrait
✅ Display standalone para app nativa
HTML Metatags (index.html)
✅ theme-color para barra de navegación
✅ apple-mobile-web-app-capable para iOS
✅ mobile-web-app-capable para Android
✅ Viewport con user-scalable=no para PWA
Automatización
✅ Script PowerShell update-version.ps1:
Incrementa versión automáticamente (patch)
Actualiza package.json
Actualiza service-worker.js
Sincroniza ambos archivos
✅ Guía completa PWA-UPDATE-GUIDE.md
Flujo de Actualización
Desarrollador ejecuta update-version.ps1
Build y deploy de nueva versión
Usuario abre la app
Service Worker detecta nueva versión
Modal aparece automáticamente bloqueando UI
Usuario presiona "ACTUALIZAR AHORA"
Service Worker se activa
Página se recarga automáticamente
Usuario usa nueva versión
Backend (v1.0.84)
Sin cambios
Ahora la PWA se actualiza automáticamente mostrando un modal imposible de ignorar! 🚀📱
Sidebar
✅ Oculto por defecto en móvil (window.innerWidth < 1024px)
✅ Overlay oscuro cuando está abierto en móvil (se cierra al tocar fuera)
✅ Deslizable desde la izquierda con transiciones suaves
✅ Siempre visible en desktop (lg: breakpoint)
Header
✅ Botón hamburguesa visible solo en móvil (lg:hidden)
✅ Logo escalable: 50px en móvil → 70px en desktop
✅ Título oculto en móvil para ahorrar espacio
✅ Indicador de sección: icono solo en móvil, texto completo en desktop
✅ Padding adaptable: 3px móvil → 4px tablet → 8px desktop
Contenido Principal
✅ Sin margin-left en móvil (el sidebar es overlay)
✅ Padding responsive: 3px → 4px → 6px según tamaño
✅ Border-radius adaptable: xl en móvil → 2xl en desktop
Modal de Inspección
✅ Ancho completo en móvil con padding mínimo (2px)
✅ Título responsive: lg (móvil) → xl (tablet) → 2xl (desktop)
✅ Altura máxima: 95vh móvil → 90vh desktop
Navegador de Preguntas
✅ Botones más pequeños en móvil: 7px/8px círculos
✅ Overflow horizontal con scroll para muchas preguntas
✅ Números responsive: texto sm en móvil → lg en desktop
✅ Gaps reducidos: 1px móvil → 2px desktop
Botones de Navegación
✅ Solo flechas en móvil (← →)
✅ Texto completo en desktop ("← Anterior", "Siguiente →")
✅ Padding y texto adaptables: text-sm móvil → text-base desktop
✅ Mejor uso del espacio horizontal
Formularios
✅ Espaciado adaptive: space-y-3 móvil → space-y-6 desktop
✅ Labels y texto responsive: xs → sm → base
✅ Banner de modo IA con wrap en móvil
La interfaz ahora es completamente funcional en móviles sin scroll horizontal, con todos los elementos accesibles y legibles! 📱✨
Frontend (v1.0.85):
- Reemplazado "Modo IA COMPLETO/ASISTIDO" por "Modo AUTOCOMPLETADO/ASISTIDO"
- Cambiado "La IA completará/sugerirá" por "El sistema completará/sugerirá"
- Reemplazado "🤖 Análisis automático" por "📋 Procesamiento automático"
- Eliminadas todas las menciones explícitas de IA visibles para mecánicos
- Terminología neutral: "el sistema" en lugar de "la IA"
Backend (v1.0.84):
- Sin cambios
Mecánicos usan funcionalidad IA sin saber que existe, mejora UX profesional
Backend (v1.0.84):
- Agregado campo 'context_match' en respuesta JSON de análisis IA
- IA evalúa si imagen corresponde al contexto de la pregunta
- Tres niveles de validación: prompt personalizado, pregunta específica, análisis general
- Detección automática de imágenes fuera de contexto con recomendaciones específicas
Frontend (v1.0.84):
- Sistema de alertas cuando IA detecta imágenes que no corresponden
- Popup de advertencia muestra qué imágenes no coinciden y por qué
- Opción para eliminar automáticamente fotos incorrectas y cargar nuevas
- Validación con frases clave: "no corresponde", "no coincide", "no relacionad"
- Previene que mecánicos carguen imágenes irrelevantes a las preguntas
Evita errores en inspecciones al garantizar que cada foto corresponda a su pregunta específica
✅ Sin IA configurada → Solo popup (sin análisis)
✅ Error en el backend → Popup con mensaje de sin análisis
✅ Timeout o fallo de red → Documentos marcados como cargados
1. Eliminado campo duplicado de "Observaciones":
❌ Antes: Había 2 campos de observaciones (uno general y uno dentro de fotos)
✅ Ahora: Solo 1 campo de observaciones (el general)
2. Nuevo tipo de pregunta "📸 Solo Fotografía" (photo_only):
Comportamiento: Solo muestra el título de la pregunta y el campo para adjuntar fotos
NO muestra: Campo de respuesta ni campo de observaciones
Ideal para: Documentación fotográfica pura (ej: "Fotografía del VIN", "Estado general del vehículo")
🎭 Frontend v1.0.81
1. Botón renombrado:
❌ Antes: "🤖 Analizar Pregunta"
✅ Ahora: "📁 Cargar Documentos"
Estado procesando: "Procesando..." (sin mencionar IA)
2. Análisis IA separado de observaciones:
El análisis NO se escribe en el campo de observaciones
Se guarda en aiAnalysis (campo separado)
Mecánico escribe observaciones manualmente
Se agrega flag documentsLoaded: true al procesar
3. Popup de confirmación:
Después de cargar documentos: "✅ Documentos cargados correctamente"
NO muestra el análisis al mecánico
4. Validación obligatoria:
Si hay fotos adjuntas y el checklist tiene IA activada
DEBE presionar "Cargar Documentos" antes de continuar
Mensaje: "⚠️ Debes presionar 'Cargar Documentos' antes de continuar"
5. Referencias a IA eliminadas:
❌ Removido: "Analizando X imagen(es) con IA..."
❌ Removido: "✓ Analizada"
❌ Removido: "guardada automáticamente"
✅ Ahora: "Procesando X documento(s)..."
✅ Ahora: "Respuesta guardada"
6. Análisis IA solo visible para admin:
En el modal de detalle de inspección
Sección morada "🤖 Análisis de IA"
Muestra: estado, observaciones, recomendación, confianza
Solo visible si user.role === 'admin'
🔧 Backend v1.0.83
Sin cambios (el campo ai_analysis ya existía en JSON)
El botón "📄 Exportar PDF" ahora solo es visible para admin y asesor
Los mecánicos (role === 'mechanic') pueden ver el modal de inspección pero NO pueden exportar el PDF
Backend v1.0.82 (sin cambios adicionales)
Resumen de permisos:
✅ Admin: Ver inspección + Exportar PDF + Ver historial + Inactivar
✅ Asesor: Ver inspección + Exportar PDF
❌ Mecánico: Solo ver inspección + Continuar incompletas
He implementado exitosamente la funcionalidad solicitada. Aquí está el resumen:
🔄 Cambios en el Frontend (App.jsx)
Renombrado de "Borrador" a "Incompleta":
Actualizado el filtro de estado: draft → incomplete
Cambiado el texto del selector: "Borradores" → "Incompletas"
Actualizado el badge de estado en la lista de inspecciones
Botón "Continuar Inspección":
Agregado botón verde "▶️ Continuar Inspección" en InspectionDetailModal
Solo aparece cuando inspection.status !== 'completed'
Cierra el modal de detalle y abre el modal de inspección para continuar
Soporte para continuar inspecciones:
Modificado InspectionModal para recibir existingInspection
Carga automática de datos del vehículo existentes
Carga de respuestas previas desde el backend
Si hay respuestas existentes, salta directamente al paso 2 (Preguntas)
No crea una nueva inspección si ya existe, solo continúa la actual
Actualización de versión:
package.json: v1.0.78 → v1.0.79
🔧 Cambios en el Backend (models.py)
Renombrado del estado por defecto:
status = Column(String(20), default="draft") → default="incomplete"
Comentario actualizado: # draft, completed, inactive → # incomplete, completed, inactive
📝 Selector de modo (admin):
❌ "Modo IA" → ✅ "Modo de Asistencia"
❌ "Sin IA - Control manual total" → ✅ "Manual - Control total del operario"
❌ "IA Asistida - Sugerencias en fotos" → ✅ "Asistido - Sugerencias automáticas"
❌ "IA Completa - Análisis automático" → ✅ "Automático - Análisis completo"
📋 Descripciones:
❌ "Sin IA: El mecánico completa..." → ✅ "Modo Manual: El operario completa..."
❌ "IA Asistida: Cuando se suben fotos, la IA analiza..." → ✅ "Modo Asistido: ...el sistema analiza..."
❌ "IA Completa: El mecánico solo toma fotos y la IA responde..." → ✅ "Modo Automático: ...el sistema responde..."
❌ "Requiere OPENAI_API_KEY configurada" → ✅ "Requiere configuración de API externa"
🔍 Durante inspección:
❌ "🤖 Análisis IA disponible" → ✅ "🤖 Análisis automático disponible"
💬 En observaciones/comentarios:
❌ "🤖 Análisis IA (98% confianza):" → ✅ "Análisis Automático (98% confianza):"
❌ "🤖 Análisis IA:" → ✅ "Análisis Automático:"
❌ "🤖 Análisis IA de X imágenes:" → ✅ "Análisis Automático de X imágenes:"
🎯 Resultado:
Los mecánicos ahora ven:
"Asistente automático" en lugar de "Inteligencia Artificial"
"Sistema" en lugar de "IA"
"Análisis automático" en lugar de "Análisis IA"
Terminología más neutral y profesional
Frontend actualizado a v1.0.78
✅ Etiquetas legibles en lugar de valores técnicos
✅ Más fácil e intuitivo para administradores
✅ Reutiliza el mismo componente configurable
Frontend actualizado a v1.0.77
🔄 Función getReadableAnswer() en Frontend:
Convierte valores técnicos a etiquetas legibles dinámicamente
Lee la configuración question.options (que tú defines al crear preguntas)
Busca en el array choices la etiqueta correspondiente al valor
📋 Conversiones soportadas:
Boolean: "yes" → "Sí", "pass" → "Pasa", "good" → "Bueno"
Single Choice: "option1" → "Opción 1", "excellent" → "Excelente"
Multiple Choice: "lights,wipers" → "Luces, Limpiaparabrisas"
Scale/Text/Number/Date/Time: Se muestran tal cual (ya son legibles)
🎯 Dónde se aplica:
Modal de detalle de inspección al ver respuestas completadas
Respeta las configuraciones dinámicas que defines en el editor de preguntas
Funciona con todas las plantillas predefinidas y configuraciones personalizadas
⚙️ Funcionamiento dinámico:
Como los tipos de pregunta son configurables por ti en el frontend,
la función lee directamente de question.options.choices el array que tú configuraste,
por lo que funcionará automáticamente con cualquier configuración que crees.
Versiones actualizadas:
Frontend: 1.0.76 - Backend: 1.0.77
Ahora tanto el PDF como el modal de inspecciones mostrarán las etiquetas legibles en lugar de los valores técnicos.
Frontend v1.0.75
Nueva Funcionalidad:
✅ Auto-scroll automático cuando arrastras cerca de los bordes del modal
✅ Zona de activación: 100 pixeles desde arriba/abajo
✅ Scroll suave: 10 pixeles cada 16ms (~60fps)
✅ Limpieza automática: Detiene el scroll cuando sueltas o sales del área
Cómo Funciona:
Arrastras una pregunta cerca del borde superior → scroll automático hacia arriba
Arrastras cerca del borde inferior → scroll automático hacia abajo
Alejas del borde → scroll se detiene
Sueltas la pregunta → scroll se limpia
Cambios v1.0.74
Lógica Implementada:
Preguntas padre solo se pueden reordenar entre sí
Subpreguntas solo se pueden reordenar con otras subpreguntas del mismo padre
No se permite arrastrar una pregunta padre dentro de subpreguntas o viceversa
Validaciones:
✅ En handleDragOver: Cursor none si intentas arrastrar entre diferentes niveles
✅ En handleDrop: Mensajes de error claros si intentas mezclar niveles
✅ Filtrado inteligente: Solo reordena el grupo correcto de preguntas
- Implementado drag & drop nativo HTML5 para reordenar preguntas
- Agregados estados draggedQuestion y dragOverQuestion
- Handlers: handleDragStart, handleDragEnd, handleDragOver, handleDrop
- Indicador visual: línea azul en drop zone
- Icono de agarre (⋮⋮) con tooltip "Arrastra para reordenar"
- Opacidad 50% en elemento arrastrado
- Cursor 'move' indica elemento arrastrable
- Mantiene función moveQuestion para compatibilidad
- Reordenamiento automático al soltar
- Implementado sistema de reordenamiento de preguntas
- Nuevo endpoint PATCH /api/checklists/{id}/questions/reorder
- Schema QuestionReorder para validar datos de reorden
- Actualización en lote de campo 'order' en preguntas
- Auditoría automática de cambios de orden
- Validación de permisos y existencia de checklist
Frontend v1.0.73:
- Agregada funcionalidad de reordenamiento de preguntas
- Botones ▲ ▼ para mover preguntas arriba/abajo
- Función moveQuestion() para gestionar reordenamiento
- Interfaz visual mejorada con separadores
- Tooltips descriptivos en botones de orden
- Recarga automática tras reordenar
- Implementado sistema de reordenamiento de preguntas
- Nuevo endpoint PATCH /api/checklists/{id}/questions/reorder
- Schema QuestionReorder para validar datos de reorden
- Actualización en lote de campo 'order' en preguntas
- Auditoría automática de cambios de orden
- Validación de permisos y existencia de checklist
Frontend v1.0.71:
- Agregada funcionalidad de reordenamiento de preguntas
- Botones ▲ ▼ para mover preguntas arriba/abajo
- Función moveQuestion() para gestionar reordenamiento
- Interfaz visual mejorada con separadores
- Tooltips descriptivos en botones de orden
- Recarga automática tras reordenar
- Implementado sistema de reordenamiento de preguntas
- Nuevo endpoint PATCH /api/checklists/{id}/questions/reorder
- Schema QuestionReorder para validar datos de reorden
- Actualización en lote de campo 'order' en preguntas
- Auditoría automática de cambios de orden
- Validación de permisos y existencia de checklist
Frontend v1.0.71:
- Agregada funcionalidad de reordenamiento de preguntas
- Botones ▲ ▼ para mover preguntas arriba/abajo
- Función moveQuestion() para gestionar reordenamiento
- Interfaz visual mejorada con separadores
- Tooltips descriptivos en botones de orden
- Recarga automática tras reordenar
- Implementado soft delete para preguntas
- Nuevas columnas: is_deleted (boolean), updated_at (timestamp)
- Migración SQL: add_soft_delete_to_questions.sql
- Endpoint DELETE marca preguntas como eliminadas en lugar de borrarlas
- GET /api/checklists/{id} filtra preguntas eliminadas (is_deleted=false)
- Validación de subpreguntas activas antes de eliminar
- Índices agregados para optimizar queries
- Mantiene integridad de respuestas históricas y PDFs generados
- Permite limpiar checklists sin afectar inspecciones completadas
- Agregado debug logging para investigar problema de carga de ai_prompt al editar preguntas
- Console.log muestra el objeto de pregunta completo y el campo ai_prompt específico
Backend v1.0.69:
- Sincronización de versión con frontend
- Schema ya incluye ai_prompt en QuestionBase y Question
- Agregada funcionalidad de edición de checklists
- Nuevo modal para editar nombre, descripción, modo IA y scoring
- Botón "✏️ Editar" en cada checklist (solo admins)
- Mejora en la gestión de checklists en el panel de administración
Backend v1.0.68:
- Actualización de versión para sincronizar con frontend
- Endpoint PUT /api/checklists/{id} ya soportaba la funcionalidad
Frontend (1.0.67):
- 🔧 Checklists e inspecciones se ordenan por ID descendente (más recientes primero)
- Mantiene posición de elementos después de editar/actualizar
- Ya no se mueven al final de la lista tras modificaciones
- Orden consistente en todas las recargas de datos
- Mejora UX al preservar contexto visual del usuario
Backend (1.0.67):
- Sin cambios (mantiene versión actual)
Frontend (1.0.66):
- 🔧 Filtro de usuarios ahora incluye admin además de mechanic/mecanico
- Los administradores aparecen en el filtro ya que también pueden hacer inspecciones
- Formato mejorado: "{full_name || username} ({role})"
- Mayor visibilidad de todas las inspecciones realizadas por cualquier usuario autorizado
Backend (1.0.67):
- Sin cambios (mantiene versión actual)