Novedades

Historial de cambios y mejoras de la plataforma Yeguada. Ver guía de uso →

  1. v97.16Jun 2026

    Los gastos programados ya no se multiplican por el número de socios

    • Fix🚨 Fallo grave detectado antes de que ocurriera: al programar un gasto (alquiler, seguro…) desde el formulario, se asignaba a TODOS los socios activos, generando un movimiento por cabeza. Programar el alquiler de 550 €/mes habría creado 29 gastos de 550 € cada mes — 191.400 € de previsiones falsas en un año. La programación de alquiler que ya existía no está afectada, porque se creó por otra vía que sí imputaba un único movimiento.
    • NuevoEl formulario de programación ahora pregunta, solo para gastos, a quién se imputa: «A la caja — un único movimiento al mes» (opción por defecto, la correcta para alquiler, seguros o suministros) o «Uno por cada socio», que indica cuántos movimientos generará. La lista de excepciones solo aparece cuando tiene sentido.
    • FixAplicado tanto a gastos recurrentes como puntuales. Los ingresos no cambian: una cuota sí es, por definición, un movimiento por socio.
  2. v97.15Jun 2026

    Los gastos recurrentes arrastraban el mismo fallo que las cuotas

    • Fix🩹 v97.13 arregló que una programación de CUOTAS con fecha de inicio futura no generase nada, pero solo tocó el lado de los ingresos. Los GASTOS recurrentes (alquiler, seguros…) usan otra función interna, `ensureAlquilerRecurrenteProvisions`, que tenía exactamente el mismo corte en el mes actual — así que seguían quedándose a cero.
    • FixNueva función `pregenerarGastosRecurrentesRangoCompleto(configId)`, gemela de la de cuotas: genera todo el rango [mesInicio, mesFin] ignorando la fecha de hoy, y se llama al guardar la programación de gasto.
    • MejoraA diferencia de la función original, esta solo INSERTA: no borra previsiones cuando ya existe un movimiento real del mismo mes, respetando la regla de que el sistema nunca elimina movimientos por su cuenta.
    • MejoraEl script de reparación `fix-provisiones-rango.js` ahora cubre también los gastos recurrentes, para arreglar las programaciones creadas antes de esta versión.
  3. v97.14Jun 2026

    La pestaña Previsión se corta a hoy (antes mostraba todo el año)

    • Mejora📅 Con la programación anual de cuotas creada (28 socios × 12 meses = 336 previsiones futuras), la pestaña «Previsión» quedaba inservible: cientos de movimientos y un saldo de miles de euros que no reflejaba nada operativo. Ahora, por defecto, solo se muestran y suman las previsiones con fecha hasta HOY.
    • MejoraNuevo botón «📅 Ver futuras (N)» que aparece solo en la pestaña Previsión cuando hay movimientos posteriores a hoy. Al pulsarlo se incluyen en la lista y en el saldo; el botón cambia a «Solo hasta hoy» para volver. Útil para planificar el año sin ensuciar el día a día.
    • FixEl corte se aplica únicamente tras montar en el navegador: el servidor corre en UTC y el móvil en hora local, así que cerca de medianoche «hoy» no coincide entre ambos y se produciría un error de hidratación de React.
  4. v97.13Jun 2026

    Pre-generar todas las provisiones del rango al crear programación

    • Fix🩹 Al crear una programación de cuota con mesInicio en el futuro (ej. julio 2026 → junio 2027 configurada en junio 2026), NO se generaba ninguna previsión. Causa: la función que se llamaba, `ensureMonthlyCuotasProvisions`, solo materializa hasta el mes actual (es la red de seguridad diaria), no hasta `mesFin`. Como `mesInicio > hoy`, el rango efectivo era vacío y se saltaba.
    • FixNueva función `pregenerarProvisionesConfigRangoCompleto(configId)` que ignora la fecha de hoy y genera todas las PROVISIONs del rango [mesInicio, mesFin] AMBOS INCLUIDOS. Se llama desde `saveProgramacionUnificada` justo tras crear/upsertar la config.
    • MejoraIdempotente: no duplica si ya hay PROVISION o REAL para (config, user, periodoInicio). Función también reutilizable desde un botón manual «Sincronizar previsiones» si se añadiera en el futuro.
  5. v97.12Jun 2026

    Fix saldo Previsión N26 disparado (bug de nombre de campo)

    • Fix🩹 En /tesoreria la pastilla «Previsión (X €)» de la cuenta N26 mostraba -2448,81 € aunque la cuenta no tenía ninguna previsión pendiente. Ese importe coincidía con el total histórico de tickets ya reembolsados.
    • FixCausa: en el filtro de ledger Previsión, la condición para excluir tickets ya liquidados comparaba `m.liquidadoPorGastoId` pero el mapping del frontend (tesoreria/page.tsx) renombra ese campo a `liquidadoPorPagoId`. Así que el check siempre daba undefined→null y TODOS los tickets pasaban como previsión virtual, incluso los ya pagados.
    • FixCambio de una letra: `liquidadoPorGastoId` → `liquidadoPorPagoId`. Ahora tickets liquidados no cuentan en el saldo Previsión y N26 marca 0€ (o el real que quede) en lugar de la suma histórica de reembolsos.
  6. v97.11Jun 2026

    Badge «X tickets pendientes de reembolso» alineado con el panel real

    • Fix🩹 En la home aparecía «1 ticket pendiente de reembolso» sobre el icono de Tesorería pero al entrar el panel no mostraba nada. El zombie era una cancelación PROVISION del gasto recurrente de alquiler (importe -550€, esAjusteProvision=true) que la query del badge contaba erróneamente porque tiene `afectaCajaReal=false` y `esPagoReembolso=false` como cualquier ticket.
    • FixQuery del badge alineada con la del panel /tesoreria/reembolsos: ahora exige `esAjusteProvision=false` y `estadoAprobacion ∈ {PENDIENTE_APROBACION, APROBADO}`. Excluye cancelaciones, tickets legacy sin flujo de aprobación y rechazados.
  7. v97.10Jun 2026

    Movimientos vencidos ya no incluyen las cancelaciones (fantasmas +-30€)

    • Fix🩹 En la lista «Movimientos previstos vencidos» aparecían filas con importe raro (+-30,00 € o --550,00 €) que al pulsar «Cobrado» daban el error «Esta previsión ya no existe o no es convertible». Eran los propios movimientos de Cancelación de v97 (importe negativo, esAjusteProvision=true), que también tienen tipo=PROVISION pero NO son cobrables — son solo la compensación contable del original.
    • FixMovimientosVencidosSection ahora excluye los movimientos con `esAjusteProvision=true`. Solo se listan las PROVISIONS originales (importe positivo para ingresos, negativo para gastos, pero ninguna cancelación).
    • FixEl total de «💰 Por cobrar / 💸 Por pagar» ya no incluye estos importes fantasma, así que ahora refleja la deuda real pendiente.
  8. v97.9Jun 2026

    Mensajes de error reales del servidor + paginación numérica abajo

    • Fix🚨 Hasta ahora, cuando una action de servidor fallaba en producción (`throw new Error(...)`), Next.js reemplazaba el mensaje real por «Error desconocido del servidor» (es una protección de seguridad de Next 16). El tesorero veía un mensaje genérico inútil. Solución: las 4 actions de convertir/cancelar previsión ahora retornan `{ ok: false, error: string }` en vez de lanzar excepción. Los mensajes llegan tal cual al toast: «Esta previsión ya fue convertida o cancelada anteriormente», «Los tickets personales solo pasan a Real al registrar el reembolso desde Tesorería», etc.
    • Mejora🔢 Paginación numérica abajo de cada lista de movimientos por cuenta. Por defecto se ve la última página (los 20 más recientes); con los botones ‹ 1 2 … N › se navega al resto. Reemplaza el botón global «Ver todos» de v97.8 que el tesorero no quería.
    • FixAplicado a las 6 listas de cuenta (3 vistas × 2 layouts desktop/móvil). El componente Pagination es uno solo y reutilizable.
  9. v97.8Jun 2026

    Errores explícitos en convertir/cancelar previsión + paginación a 20 movimientos por defecto

    • Fix🚨 Al pulsar «Convertir» o «Cancelar previsión» en una PROVISION que ya tenía cancelación creada (por un click anterior o por duplicado pre-v97.7), la action retornaba EN SILENCIO y el tesorero veía el toast de éxito aunque internamente no se hacía nada (los saldos no cambiaban). Ahora se lanza un error explícito con mensaje claro: «Esta previsión ya fue convertida o cancelada anteriormente».
    • FixMismo arreglo aplicado a las 4 funciones (`applyConvertIngresoProvisionToRealTx`, `applyConvertGastoProvisionToRealTx`, `cancelarPrevisionIngreso`, `cancelarPrevisionGasto`). Si la previsión no existe o ya fue procesada, el toast rojo lo dice.
    • Mejora📃 Paginación en las listas de movimientos por cuenta: por defecto se muestran solo los últimos 20 movimientos. Nuevo botón en la barra de acciones (junto al toggle Real/Previsión y al export CSV): «Ver todos» / «Solo últimos 20». Cuentas con cientos de movimientos ya no tardan tanto en renderizar y el scroll es fluido en móvil.
    • MejoraPaginación del tab Real/Previsión (que ya existía) reducida de 50 a 20 movimientos por página, en línea con el resto.
  10. v97.7Jun 2026

    Botones Convertir / Cancelar previsión protegidos contra dobles clicks y errores silenciosos

    • Fix🔒 Los botones «Convertir» y «Cancelar previsión» de /tesoreria se quedan deshabilitados y muestran «…» mientras se procesa la petición. Antes era posible pulsar rápido varias veces el mismo botón (aunque la idempotencia del servidor cubría el caso normal, era una garantía teórica frente a race conditions raras).
    • Fix🚨 Si la conversión falla en el servidor (por ejemplo «Los tickets personales solo pasan a Real al registrar el reembolso desde Tesorería»), ahora se muestra un toast ROJO con el mensaje. Antes el error se tragaba en silencio y el tesorero veía «no pasa nada» sin entender por qué.
    • MejoraToast verde de éxito al convertir o cancelar: «Cobro convertido a Real», «Pago convertido a Real», «Previsión cancelada». Feedback claro de que la acción se completó.
    • MejoraRefactor interno: nuevo wrapper `<ProvisionActionButton>` que centraliza confirm + useTransition + try/catch + toast + disabled. Aplicado a los 8 lugares donde aparecían estos botones en /tesoreria (escritorio + móvil, ingresos + gastos).
  11. v97.6Jun 2026

    Movimientos vencidos ya excluyen las previsiones canceladas

    • Fix🩹 Tras pulsar «Convertir» o «Cancelar previsión» en /tesoreria, el movimiento PROVISION original quedaba intacto (correcto por diseño v97), pero la sección «Movimientos previstos vencidos» SEGUÍA mostrándolo — porque no detectaba que ya tenía su Cancelación asociada. El tesorero veía «no pasa nada» aunque internamente sí pasaba.
    • FixAhora el server identifica todas las PROVISIONS canceladas (las que tienen otro movimiento `esAjusteProvision=true` apuntando a ellas vía `ingresoAjustePadreId`/`gastoAjustePadreId`) y marca cada movimiento con un flag `tieneCancelacion`. La lista de vencidos las omite. La PROVISION original sigue visible en el historial normal — solo desaparece de la lista de pendientes.
    • MejoraEl saldo de la cuenta ya era correcto desde v97 (la cancelación suma −X y compensa el +X de la PROVISION). Este fix solo arregla la UI de pendientes para que coincida con la lógica del saldo.
  12. v97.5Jun 2026

    Programaciones recurrentes: inmutables (solo crear / eliminar)

    • Fix🗑️ Quitado el botón «Sincronizar previsiones» del Programador (`/admin/cuentas-bancarias/[cuentaId]/programacion`). Ya no tiene sentido tras v97.3 — las provisiones se generan automáticamente al guardar el programador y al activar un usuario nuevo.
    • Fix🔒 Las programaciones recurrentes (cuotas de ingreso y gastos recurrentes) ya NO se pueden editar. Esto evita líos: si editas el importe, ¿qué hacemos con las provisiones ya generadas? Mejor decisión: si quieres cambiar algo, elimina la programación (lo que crea cancelaciones automáticas para sus provisiones pendientes) y crea una nueva con los valores correctos. Histórico íntegro, sin sorpresas.
    • MejoraLas tarjetas de cada programación ahora son solo lectura: muestran tipo, importe, día de creación y rango mesInicio→mesFin. Si hay excepciones de usuarios, se ven en un dropdown. Único botón de acción: «Eliminar programación».
    • MejoraBanner informativo actualizado: explica que las programaciones son inmutables y describe el flujo de eliminación con cancelación automática de provisiones pendientes.
  13. v97.4Jun 2026

    Hotfix: hydration mismatch en el badge de filtros activos

    • Fix🩹 Hydration mismatch en /tesoreria: el badge rojo con el número de filtros activos aparecía en el cliente pero no en el servidor porque los estados de filtros se inicializan desde `sessionStorage` (que solo existe en el cliente). React lanzaba warning al hidratar.
    • FixFix con flag `mounted`: useEffect lo pone a true tras el primer render del cliente. El badge solo se renderiza si `mounted && activeFiltersCount > 0`. En SSR no aparece nunca; en CSR aparece cuando corresponde. Sin mismatch.
  14. v97.3Jun 2026

    Adiós al cron de cuotas + filtros createdAt/updatedAt + hook usuario nuevo

    • Fix🔌 Quitadas las llamadas automáticas a `ensureMonthlyCuotasProvisions` en /, /tesoreria y /tesoreria/reembolsos. El cron ya no se dispara en cada visita — las provisiones se generan solo al guardar la config recurrente (saveProgramacionUnificada) y al activar un usuario nuevo.
    • Nuevo✨ Hook en `updateUser`: cuando un usuario inactivo pasa a activo, se generan automáticamente sus provisiones pendientes de todas las CuotaProvisionConfig y GastoRecurrenteConfig activas. Fire-and-forget — si falla no bloquea el guardado del usuario.
    • Nuevo📅 Dos filtros de fecha NUEVOS en /tesoreria: «Fecha de creación» (createdAt — entrada en BD) y «Fecha de modificación» (updatedAt — último cambio). Sumados a los ya existentes («Fecha del movimiento» y «Fecha de confirmación»), son 4 rangos de fecha independientes.
    • FixEl filtro «Fecha del movimiento» (antes etiquetado «Fecha de registro») ya no coalescía con createdAt — ahora filtra estrictamente por `m.fecha` (la fecha contable). Si quieres filtrar por cuándo entró en BD, usa el nuevo filtro «Fecha de creación».
    • MejoraMejor coherencia entre el saldo del tab Real y el saldo Real del resumen de cuenta. Tickets pendientes de reembolso (gastos REAL con afectaCajaReal=false) pasan al tab Previsión como deuda virtual, como ya lo trata `cajaSaldos.ts`.
  15. v97.2Jun 2026

    Saldos coherentes + sistema deja de eliminar movimientos automáticamente

    • Fix🩹 El saldo del tab «Real» mostraba un total distinto al saldo Real del resumen de la cuenta. Causa: mi ledger no aplicaba los mismos filtros que `cajaSaldos.ts` (incluía gastos REAL con `afectaCajaReal=false`, que son tickets pendientes de reembolso). Ahora aplica el mismo criterio: Real = REAL con efecto contable; los tickets pendientes pasan al tab «Previsión» como deuda virtual.
    • Fix📅 El saldo del radio Real/Previsión refleja la fecha «Hasta» del filtro de fecha de registro. Si no hay filtro, muestra el saldo actual. Tooltip mejorado con la fecha exacta consultada.
    • Nuevo🔒 **PRINCIPIO NUEVO: el sistema NO elimina movimientos automáticamente, NUNCA.** El usuario lo pidió expresamente. Históricos preservados, saldos coherentes con cancelaciones (movimientos compensatorios negativos) en vez de borrados.
    • FixCron `ensureMonthlyCuotasProvisions`: eliminadas las 3 ramas que borraban PROVISIONS: (1) al cambiar tipoGeneracion a REAL, (2) cuando había REAL del mismo mes, (3) limpieza fuera del rango del config. Si quedan PROVISIONS huérfanas o sobrantes, el tesorero las cancela manualmente con el botón nuevo.
    • Fix**Eliminar programación recurrente** (CuotaProvisionConfig / GastoRecurrenteConfig) ya no borra las provisiones generadas. Ahora desactiva la config (`enabled=false`) y crea la cancelación de cada provisión pendiente. El histórico queda íntegro y el saldo previsión vuelve a 0.
    • Fix**Eliminar movimientos manualmente** (botón ✕) ahora requiere ADMIN obligatoriamente. Tesorero y usuario YA NO pueden borrar nada — solo cancelar previsiones (que crea movimiento compensatorio sin destruir historial). Mensaje claro: «Solo un administrador puede eliminar movimientos. Para anular una previsión, usa el botón Cancelar previsión.»
    • MejoraNuevas funciones `canDeleteIngresoTesoreria` y `canDeleteGastoTesoreria` en lib/tesoreriaMovimientosPermissions.ts — único punto de verdad para «¿puede borrar?».
  16. v97.1Jun 2026

    Mejoras visuales: signo natural en importes + saldo final en radio Real/Previsión

    • Fix🔢 Las cancelaciones y devoluciones (importeCents negativos) ya no muestran «−−55,00 €» o «+−55,00 €». Ahora se calcula el signo EFECTIVO al saldo: gasto × signo del importe. Una cancelación de previsión (ingreso negativo) se muestra como «−55,00 €» en color rojo (porque resta del saldo); un gasto negativo (devolución) como «+55,00 €» verde (porque suma).
    • Mejora📊 Los botones del radio Real/Previsión en la cabecera de la tabla muestran ahora el SALDO FINAL de cada tipo a la fecha de consulta (hoy incluido) en lugar del número de movimientos: «Real (4.567,89 €)» y «Previsión (1.234,00 €)». Tooltip explicativo al pasar el ratón.
    • MejoraEl saldo se calcula sobre TODOS los movimientos de la cuenta (sin filtros activos) — es el saldo total de la cuenta a hoy, no del rango filtrado.
  17. v97Jun 2026

    PROVISION → REAL con cancelación compensatoria + botón cancelar previsión

    • Nuevo🔄 Nuevo modelo de conversión: al pulsar «Convertir» en una previsión, el sistema YA NO modifica el movimiento original. En su lugar crea dos movimientos nuevos en la fecha de hoy: (1) un REAL con el importe correspondiente para el saldo Real, y (2) una «Cancelación Previsión» (importe negativo) que anula la previsión original en el saldo de previsiones. Resultado: saldo Real correcto, saldo Previsión a 0, historia completa preservada.
    • Nuevo↩️ Nuevo botón violeta «Cancelar previsión» junto al de «Convertir». Crea SOLO la entrada de compensación negativa sin generar movimiento real asociado. Útil para anular PROVISIONS fantasma duplicadas o cuotas que el tesorero decide no cobrar (socios exentos, errores, etc.).
    • Fix🩹 Si el importe real fue distinto al previsto (ej. previsión 30 €, cobro 35 €), el tesorero hace el ajuste a MANO con un movimiento extra. Eliminada la lógica antigua del delta automático que era confusa y generaba ajustes invisibles.
    • MejoraIdempotencia: si pulsas «Convertir» dos veces sobre la misma previsión, solo se crea una vez la pareja REAL + Cancelación (la segunda llamada detecta la cancelación ya existente y no duplica).
    • MejoraAudit log: nuevas acciones CANCEL_INGRESO_PROVISION y CANCEL_GASTO_PROVISION quedan registradas en /admin/sistema/logs con el ID del movimiento cancelado y el actor.
    • MejoraAplica a ingresos Y gastos. El gasto REAL nuevo clona TODAS las líneas (categoría, subcategoría, artículo, cantidad, paquetes, contenidoPorUnidad, proveedor, tag, nota) del gasto previsto. La cancelación lleva solo 1 línea genérica con importe negativo.
  18. v96.1Jun 2026

    Fix v96: el saldo acumulado debe ser global, no del rango filtrado

    • Fix🩹 En v96 el saldo acumulado de cada movimiento se calculaba sobre los movimientos del rango filtrado, lo cual no tiene sentido financieramente — el saldo de la cuenta a una fecha concreta no cambia porque filtres tu vista. Ahora el saldo se calcula sobre TODOS los movimientos de la cuenta (sin filtros) y la vista solo decide qué filas se enseñan; cada fila conserva su saldo global.
    • MejoraEsto significa que si filtras «últimos 7 días», la primera fila muestra el saldo actual de la cuenta y, según vas viendo cómo era hace 7 días, el saldo va decreciendo/creciendo según los movimientos que SUCEDIERON antes (aunque no estén visibles por el filtro).
  19. v96Jun 2026

    Tesorería: vista separada Real / Previsión con saldo acumulado por movimiento

    • Nuevo📊 En /tesoreria, la tabla de movimientos ahora tiene un toggle inline «Real / Previsión» en la cabecera. Cada vista muestra solo los movimientos del tipo seleccionado y su propio saldo acumulado, calculado independientemente.
    • Nuevo💶 Nueva columna «Saldo Real» / «Saldo Previsión» (cambia el título según el tipo activo) al final de la tabla con el saldo acumulado tras cada movimiento. El cálculo se hace dentro del rango filtrado (fechas, persona, etc.) — el saldo total absoluto de la cuenta sigue visible en el resumen superior con el nombre de la cuenta.
    • MejoraOrden descendente (más reciente arriba): la primera fila muestra el saldo actual; al bajar ves cómo era antes de cada movimiento. El contador junto a cada botón del radio indica cuántos movimientos hay de cada tipo en el rango filtrado.
    • MejoraEn móvil: las cards de movimiento muestran el saldo del tipo activo en el pie, igual que en desktop. Las cards de los formularios inline de edición también — antes mostraban «Real: X → Y / Virtual: X → Y», ahora muestran solo el saldo correspondiente al tipo activo.
    • MejoraEl radio se persiste con `useState` en el cliente — al refrescar la página vuelve a «Real» (vista por defecto). La paginación se resetea al alternar.
  20. v95Jun 2026

    Hotfix v93: backfill resistente a ingresos REAL duplicados del mismo mes

    • Fix🩹 Tras desplegar v93, el backfill falló con `Unique constraint violado en (cuotaProvisionConfigId, periodoInicio, userId, tipo)` para ciertos usuarios. Significa que en la BD ya había DOS ingresos REAL del mismo (user, mes, config) — uno ya vinculado y otro huérfano (duplicado registrado por error).
    • FixEl backfill ahora detecta este caso ANTES de hacer UPDATE: si ya existe otro REAL vinculado al mismo (user, mes, config), no toca el huérfano (se queda como huérfano para revisión manual) pero igual añade su key a `realKeys` para que el cron NO genere PROVISION fantasma. Saldo correcto sin tocar duplicados existentes.
    • MejoraEl warning loguea ambos IDs (huérfano + ya-vinculado) para que el admin pueda revisar y eliminar duplicados manualmente desde /tesoreria si lo desea: «ingreso REAL duplicado del mismo mes/usuario detectado. Huérfano X conservado sin vincular (ya hay otro REAL Y vinculado)».
    • FixDefensa adicional: si por cualquier otro motivo (carrera, etc.) el UPDATE falla, igual se añade la key a `realKeys`. Garantiza que el cron no crea PROVISIONS fantasma incluso en casos extraños.
  21. v94Jun 2026

    Refactor: editor de líneas de gasto compartido entre tesorería y reembolsos

    • Mejora🧩 Nuevo componente compartido `<LineaGastoEditor>` que se usa en los dos sitios donde se editan líneas de gasto: el editor inline de `/tesoreria` (al pulsar «Editar» en una fila de movimiento) Y el modal de «Pago de reembolso» (al pulsar «Ver / editar ticket»). Antes había dos formularios duplicados que evolucionaban por separado.
    • Nuevo💜 El editor de líneas del modal de reembolso ahora tiene los mismos campos que el de tesorería: multi-tags como chips (TagsMultiSelect), campo Nota ancho completo, subtítulos aclaratorios «(uds. compradas)» y «(por unidad de venta)», preview en vivo del total con detección automática de devoluciones (badge violeta «↩️ DEVOLUCIÓN»), tolerancia a importes y Nº de unidades negativos.
    • MejoraVentaja del refactor: cualquier mejora futura al editor de líneas se aplica a ambos sitios automáticamente. No más drift entre vistas.
    • Fix🐛 El modal de reembolso bloqueaba importes negativos y Nº ≤ 0 con `min="0"`/`min="1"` en los inputs (escapados del fix v91/v92). Al usar el componente compartido, ahora también acepta devoluciones.
    • Mejora`LineaGastoEditor` expone helpers públicos: `serializeLineasGasto(lineas)` para construir el `lineas` JSON del FormData, y `buildEmptyLineaGasto(catalogo)` para crear una línea por defecto. Ambos exportan tipos `LineaGastoDraft` y `CatalogoGasto`.
    • MejoraQuery del server en /tesoreria ya devolvía `tagIds[]` y `nota` (añadido en v90). El modal de reembolso ahora también los lee con fallback al tagId legacy si están vacíos. Los datos pre-existentes en BD se conservan al editar.
  22. v93Jun 2026

    FIX CRÍTICO: ingresos manuales de cuota duplicaban el saldo de cuenta

    • Fix🚨 Causa raíz del «el saldo Real se mueve de más con ciertos ingresos»: cuando el tesorero registraba pagos manuales de cuota mensual desde el formulario «Registrar ingreso» (por ejemplo al desglosar el pago anual de un socio en 12 cuotas), `createIngresoMovimiento` no seteaba `cuotaProvisionConfigId`. El cron horario `ensureMonthlyCuotasProvisions` filtra REALs por ese campo: como esos ingresos tenían NULL, el cron NO los detectaba como pagos válidos y CREABA PROVISIONS fantasma para los mismos meses. Al marcar la PROVISION fantasma como cobrada, quedaban DOS REALs del mismo mes → saldo duplicado.
    • Fix🔧 Backfill automático en `ensureMonthlyCuotasProvisions`: antes del bucle de creación, busca Ingresos REAL del mismo `ingresoTipoId`+`cuentaBancoId` con `cuotaProvisionConfigId=NULL` en el rango del config. Para cada uno: UPDATE asociándolo al config y rellenando `periodoInicio`. Añade su key a `realKeys` para que el bucle posterior elimine cualquier PROVISION fantasma del mismo (user, mes). Idempotente — en visitas siguientes no hay huérfanos.
    • Fix🛡️ Prevención en `createIngresoMovimiento`: al crear un ingreso manual, si su `ingresoTipoId`+`cuentaBancoId` coincide con un `CuotaProvisionConfig` activo y la fecha cae en el rango (`mesInicio` ≤ fecha ≤ `mesFin`), auto-rellenar `cuotaProvisionConfigId` y `periodoInicio` (primer día del mes de la fecha). Así los pagos manuales futuros NO generan el problema.
    • Mejora📊 Tras desplegar v93, la próxima visita a /tesoreria ejecuta el backfill silenciosamente: las PROVISIONS fantasma de meses ya pagados manualmente se eliminan; los REALs antiguos quedan correctamente vinculados al config; los dashboards de saldo dejan de sumar de más.
    • MejoraLog warning en caso de que un ingreso huérfano no pueda asociarse (unique constraint conflict, etc.) — no propaga el error, simplemente queda registrado para diagnóstico.
  23. v92May 2026

    Fix: dos validaciones de Nº de unidades aún bloqueaban negativos

    • Fix🩹 A v91 se le escaparon dos puntos donde aún se bloqueaban valores negativos en el campo «Nº (uds. compradas)»: (1) validación cliente del submit en `GastoMiembroMobileForm` («Cada línea debe tener Nº de unidades > 0»), (2) atributo HTML5 `min="1"` en el input del formulario `EditarTicketForm`. Backend y resto del frontend ya estaban relajados desde v91.
    • FixAmbos relajados a la lógica correcta: solo se rechazan 0 y NaN. Negativos permitidos para devoluciones. El label del input en EditarTicketForm ahora indica «Nº (negativo = devolución)».
  24. v91May 2026

    Tickets negativos: soporte completo de devoluciones (importe + cantidad)

    • Nuevo↩️ Ahora puedes registrar devoluciones como ticket completo: importes negativos por línea y total negativo. Caso típico: te devuelven 3 botellas de whisky que costaban 25€ cada una → Nº=-3, Cantidad/uds.=0,7L, Importe=-75€. El gasto agregado queda con importeCents negativo, reduce correctamente la columna de gasto total y aparece como salida invertida en los dashboards.
    • FixBackend `resolvePaqueteFields` y `validateGastoLineasDetalle`: `paquetes` (Nº) acepta cualquier número finito ≠ 0 (positivo = compra, negativo = devolución). `cantidad` total puede ser negativa. `contenidoPorUnidad` sigue requiriendo > 0 (el contenido físico de UNA unidad de venta — ej. una botella sigue siendo 0,7 L aunque la devuelvas).
    • Fix`createGastoConLineas` y `updateGastoConLineas`: importe acepta cualquier valor finito (negativo, 0 o positivo); cantidad acepta cualquier número ≠ 0. Solo rechazamos NaN y cantidades 0.
    • FixFrontend EditarTicketForm y GastoLineasEditor (tesorería): quitado `min="0"` del input de importe. Inputs ya eran tipo texto/decimal, así que aceptan el signo `-` directamente. Etiqueta del campo importe ahora indica «(negativo = devolución)».
    • Nuevo💜 Indicador visual de devolución: el preview de línea cambia a fondo violeta con badge «↩️ DEVOLUCIÓN» cuando el Nº o el importe son negativos. Aparece tanto en el creador como en el editor de tesorería. El precio €/uds. se muestra siempre en absoluto (un whisky cuesta lo mismo lo compres o lo devuelvas).
    • FixEscalado anti-fraude (v84) se DESACTIVA cuando el total es negativo o hay líneas mixtas con signo. El signo es intencional del usuario, no error de la IA — no hay que «cuadrarlo» automáticamente.
  25. v90May 2026

    Editor de gasto en /tesoreria: multi-tags + nota + ayudas visuales

    • Nuevo🏷️ Multi-tags por línea en el editor de gasto inline (/tesoreria al pulsar «Editar» en una fila). Componente `TagsMultiSelect` (chips + dropdown buscable) idéntico al del formulario de creación. Antes solo permitía 1 etiqueta por línea; ahora puedes asignar varias (ej. «Cena oficial» + «Bebida» + «Pólvora»).
    • Nuevo📝 Campo «Nota» por línea (opcional, ancho completo). Útil para registrar descuentos aplicados, IVA especial, aclaraciones o por qué una línea está cortesía. Ya estaba soportado en BD (campo `GastoLinea.nota`) pero el formulario no lo exponía.
    • Fix📊 Subtítulos aclaratorios en los campos numéricos del editor: «Nº (uds. compradas)» y «Cantidad/uds. (por unidad de venta)». Antes era ambiguo y parecía que estuvieran invertidos.
    • Nuevo💡 Preview en vivo bajo cada línea: «= 3 × bandeja · 0,5 kg/uds. · 1,5 kg en total · 💰 4,67 €/kg». Mismo formato que en el creador. Solo aparece si Nº y Cantidad/uds. están rellenos.
    • MejoraServer: query de movimientos en /tesoreria ahora trae `paquetes`, `contenidoPorUnidad`, `unidadVentaLabel`, `nota` y la tabla pivote `tags` (multi). Antes solo traía `tagId` singular y se perdían los datos nuevos al cargar el editor inline.
    • MejoraReconciliación tagId ↔ tagIds[]: al guardar, el formulario envía ambos por compat. El backend ya hacía la conciliación desde v76 (tagIds es fuente de verdad; tagId es el primero del array para queries legacy).
    • FixEl editor mantiene los tags multi existentes al cargar (si ya había tags asignados a la línea, vienen precargados como chips). Si el dato venía con `tagIds[]` vacío pero con `tagId` legacy, se usa este como único tag (fallback de compatibilidad).
  26. v89May 2026

    IA multi-página: hasta 5 fotos por factura en un único análisis

    • Nuevo📚 Las facturas largas (Dialsur, Makro…) suelen ocupar 2-3 páginas. Ahora puedes subir hasta 5 fotos en el paso «Foto del ticket» antes de pulsar «Analizar con IA». Gemini Vision recibe todas las imágenes a la vez y las trata como UNA factura unificada, agregando líneas de todas las páginas en un solo array de salida.
    • Nuevo🖼️ UI nueva del paso foto: grid 2×N de previews con badge numerado (1, 2, 3…) en cada página, botón ✕ rojo para quitar una página individual, botón «+ Añadir página» que abre selector para añadir más sin perder las anteriores. Contador «N/5» en cabecera.
    • MejoraNota explícita al prompt cuando hay >1 imagen: «MULTI-PÁGINA: son páginas de la MISMA factura, no facturas distintas. Léelas en orden y agrega las líneas de todas. El total_eur es el TOTAL FINAL que aparece típicamente en la última página.»
    • MejoraBackend: `/api/gastos/precategorizar` ahora acepta múltiples files vía `formData.getAll('ticket')`. Cap: 5 archivos, 5 MB cada uno. Cada archivo se valida por magic bytes. `callGeminiVision` refactorizada para aceptar array de imágenes (mantiene firma antigua por compat).
    • FixEl `ticketFotoUrl` que se guarda en el modelo Gasto sigue siendo 1 sola (la primera). Limitación conocida del schema actual; las páginas adicionales se usan para el análisis pero solo la primera queda asociada al gasto. Futuro: tabla `GastoTicketFoto` 1:N para guardar todas.
  27. v88May 2026

    Tesorería: nueva columna «Descripción» en las listas de movimientos

    • Nuevo📋 Tabla de movimientos del panel `/tesoreria` (la del bloque «Movimientos»): nueva columna «Descripción» entre Importe y Persona. Para gastos muestra `descripcion` del ticket (concatenación de líneas), para ingresos muestra `nota`. Truncado a 2 líneas con `line-clamp-2`, max-width 260px. Tooltip al pasar el ratón muestra el texto completo.
    • Nuevo📋 Tabla del historial completo (`/tesoreria/historial`, `/tesoreria/reembolsos?tab=historial`, `/gastos/reembolsos?tab=historial`): columna «Concepto» renombrada a «Detalle» (sigue mostrando id, categoría y estado de liquidación). Nueva columna «Descripción» dedicada al texto del ticket (o nota del ingreso), también con `line-clamp-2` y tooltip.
    • MejoraEl truncado usa `line-clamp-2` (CSS estándar v77) en vez de `truncate` simple: respeta saltos de línea por palabras y muestra hasta 2 líneas antes de cortar con elipsis. Mucho más legible para tickets con concatenación tipo «Whisky 70cl · Coca-Cola 2L · Frutos secos · ...».
  28. v87May 2026

    Permitir líneas de gasto con importe 0 € (muestras, regalos, promos)

    • Fix💚 Las líneas con importe 0,00 € ya se pueden guardar. Antes el server rechazaba con «Cada línea debe tener un importe mayor que 0» — pero los regalos por compra alta, muestras promocionales (marcador 'M' en facturas Dialsur) o productos cortesía SÍ son línea legítima con producto físico real y precio 0.
    • FixCambio en `createGastoConLineas` (admin.ts): se validan importes negativos o NaN (rechazados) pero importe = 0 se acepta. La cantidad sigue requiriendo > 0 (sin producto no hay línea).
    • FixMisma relajación en el formulario de edición de gasto (EditarTicketForm.tsx). Antes daba toast «debe ser mayor que 0»; ahora solo bloquea negativos.
    • MejoraEl cambio respeta el caso real Dialsur: cuando hay líneas tipo «Cerveza Mahou 0,0 — M — 3 unidades — 0,00 €» (muestra promocional), ya no necesitas trampear el importe a 0,01 € para poder guardar.
  29. v86May 2026

    IA: bloque condicional para facturas mayoristas + cap memoria 100

    • Mejora🔍 Nuevo bloque en el prompt: «DETECCIÓN CONDICIONAL — FORMATO TABULAR MAYORISTA». Solo activa cuando Gemini reconoce literalmente las cabeceras Código/Descripción/Cajas/Unidades/Tipo/PvP-CIva/PvP-SIva/Total (típico Dialsur/Makro/Persagas). Si NO ve esas cabeceras (Mercadona, Lidl, etc.) ignora el bloque entero — no contamina tickets normales como en el v79-v80. Compacto (~15 líneas vs las 80 del intento anterior).
    • MejoraReglas explícitas dentro del bloque: «Tipo es %IVA, no cantidad», «Total es SIN IVA → importe_eur = Total × (1+Tipo/100)», marcadores P/M, offset vertical descripción↔números, mapeo Cajas+Unidades a paquetes+contenido, no agrupar filas.
    • Mejora📚 Cap reglas memoria 50 → 100. Las 43 seed Dialsur quedaban diluidas con genéricas + destiladas. Ahora caben todas + más espacio para reglas futuras.
    • MejoraReordenado del SQL: reglas marcadas con [Proveedor] vienen ANTES de las genéricas en el bloque memoria. Antes ordenaba solo por usageCount, lo que privilegiaba genéricas usadas muchas veces. Ahora las específicas de proveedor pesan más cuando aplican.
    • MejoraTexto del bloque memoria reforzado: de «pistas opcionales · ignóralas si contradicen» a «CONOCIMIENTO ACUMULADO · SI el ticket es de ese proveedor DEBES respetar sus reglas». Más decisión para las reglas específicas, manteniendo la salvaguarda «si contradice lo evidente en la imagen, manda el ticket».
  30. v85May 2026

    Tesorero/admin: registrar gastos sin foto del ticket

    • Nuevo💼 En el formulario de tesorería (`esFormularioTesoreria=true`), el botón «Rellenar a mano (sin IA)» ya no requiere imagen del ticket. Para tesoreros/admins el flujo es: abre el modal de registrar gasto → pulsa directamente el botón → introduce datos a mano. Útil para transferencias bancarias, facturas digitales ya archivadas, gastos recurrentes sin ticket físico.
    • MejoraEl botón cambia de texto según contexto: «Rellenar a mano (sin IA)» si hay foto subida, «Crear gasto sin foto (sin IA)» si no la hay y se está en modo tesorería. Hint visual azul: «Como tesorero/admin puedes registrar gastos sin foto (ej. transferencias bancarias, facturas digitales ya archivadas, gastos recurrentes).»
    • FixPara usuarios normales (USUARIO/USER) la foto sigue siendo obligatoria — el cambio aplica solo cuando `esFormularioTesoreria=true`, que es el caso de los modales de /tesoreria. El backend ya aceptaba gastos sin foto (campo `ticketFotoUrl` nullable en el modelo Gasto) — solo el frontend bloqueaba.
  31. v84May 2026

    FIX CRÍTICO: el sistema inflaba importes 10× para forzar cuadre del total

    • Fix🚨 Causa raíz del problema «whisky a 293 € en vez de 30 €»: cuando Gemini omitía líneas y la suma daba 81 € pero el total ticket era 790 €, el sistema escalaba cada línea por factor 9,68× para que cuadrara. Resultado: cifras absurdas que parecían inventadas (whisky inflado a 293, ron a 400, larios a 96). El usuario veía números falsos sin manera de saber qué pasaba.
    • Fix🔒 Escalado limitado al rango factor [0.7×, 1.3×]. Si la diferencia entre suma de líneas y total es más del ±30%, NO escala. Mejor mostrar la suma real (81 €) con aviso visible que falsificar 10× para «cuadrar». Aplica tanto al primer escalado IA (escalarLineasIAAlTotal) como al post-mapeo (escalarLineasAlTotal).
    • Nuevo🚨 Nuevo banner ROJO grande en la UI cuando la IA probablemente omitió líneas: «Faltan X € por repartir. La IA probablemente ha omitido productos del ticket (devuelve solo N líneas pero el total es Y €). Añade las líneas que faltan con «+ Línea» o vuelve a sacar la foto. NO confirmes así porque los importes mostrados pueden ser inexactos.»
    • MejoraEl aviso ámbar anterior («la suma no coincide») se mantiene para descuadres pequeños (<25% o <5€) que sí son ajustes normales. Para descuadres grandes salta el banner rojo con instrucciones explícitas.
    • MejoraLog en servidor cuando se detecta el caso: warning con factor, suma y total para diagnóstico futuro.
  32. v83May 2026

    Fix anti-agregación: la IA volvía 2 líneas cuando había 16

    • Fix🩹 Tras quitar el bloque mayoristas en v82, Gemini volvió a agregar productos en 2-3 líneas genéricas («Bebidas: 500€», «Snacks: 200€») en facturas tabulares con muchos productos. Era el comportamiento que el bloque mayoristas evitaba (pero a costa de saturar el prompt para todo lo demás).
    • FixNueva regla ANTI-AGREGACIÓN al inicio del bloque «LÍNEAS DEL TICKET» como instrucción más importante del prompt: «Cuenta cuántas filas de producto hay en el ticket — eso es N. Tu array lineas DEBE tener exactamente N entradas. NUNCA agrupes bajo nombres genéricos.» + verificación final: «antes de cerrar el JSON, releé el ticket y cuenta visualmente: si tienes 2 entradas y el ticket tiene 16 filas, es ERROR — vuelve a leer.»
    • FixAclaración corta sobre facturas tabulares (sin reintroducir el bloque mayoristas masivo): «en estos documentos suele haber columna de descripciones a la izquierda y números a la derecha posiblemente con offset vertical — empareja por orden vertical, pero cada fila de producto sigue siendo línea separada».
    • FixReforzado el `systemInstruction` de Gemini (visible siempre, no se trunca): «extractor EXHAUSTIVO · una entrada por CADA fila física · NUNCA agrupes en "Bebidas" o "Varios"».
    • FixSubido `maxOutputTokens` de 8.192 a 16.384. Sospecha: con tickets de 16+ líneas el JSON podía truncarse y Gemini «compensaba» agregando para que cupiera.
  33. v82May 2026

    Fix: rollback del prompt mayoristas que empeoraba la lectura general

    • Fix🩹 El bloque «📄 FACTURAS DE MAYORISTAS» que añadí en v79 + los 6 ejemplos Dialsur recalculados con IVA de v80 saturaban el prompt y contaminaban la lectura de tickets normales (Mercadona, Lidl). Gemini Flash perdía foco con tanto texto e intentaba aplicar reglas de mayoristas (offset vertical, multiplicar por IVA) a tickets lineales donde NO aplica.
    • FixQuitado el bloque mayoristas entero del prompt principal (~80 líneas). Quitados los 6 ejemplos Dialsur con multiplicación de IVA. Quitada la cross-reference desde 'LÍNEAS DEL TICKET'. El prompt vuelve esencialmente a v78 + memoria IA + regla anti-cliente simplificada.
    • FixEl conocimiento sobre Dialsur (formato tabular, IVA × multiplicador, P/M) NO se pierde: ya vive en la tabla TicketIAMemoria como reglas seed marcadas [Dialsur]. Sólo se aplican cuando Gemini detecta que el ticket es de ese proveedor — no contaminan los tickets de Mercadona/Lidl/etc.
    • MejoraCap de reglas inyectadas reducido de 200 a 50 (saturaba con 43 reglas seed + las destiladas). Texto del bloque de memoria suavizado: 'PISTAS APRENDIDAS · úsalas SOLO si aplican a este ticket · si contradicen lo evidente, ignóralas — los datos del ticket mandan'. Las reglas con [Proveedor] se ignoran si el ticket no es de ese proveedor.
    • MejoraRegla anti-cliente del prompt simplificada (era específica para 'MAFEL SL · CIF B53041091') a versión genérica. El detalle de MAFEL queda en la memoria como regla [Dialsur] donde sí pertenece.
  34. v81May 2026

    Memoria IA: 43 reglas iniciales precargadas — Gemini no parte de cero

    • Nuevo🌱 Script `npm run db:seed-ia-memoria` con 43 reglas curadas a mano que se cargan en la tabla TicketIAMemoria como origen 'seed'. La IA arranca PRE-ENTRENADA con conocimiento sobre los proveedores típicos de la comparsa sin esperar a las primeras correcciones del usuario.
    • Nuevo22 reglas genéricas (sin proveedor): conversión de unidades (70cl→0.7L, 33cl→0.33L, 25cl→0.25L), categorización por tipo de producto (whisky→Licores, fruta→Comida/Frutas, vasos→Plásticos/Desechables), reglas de IVA España (21/10/4%), proveedor vs cliente, líneas con 0,00€ son promos.
    • Nuevo21 reglas específicas por proveedor: Dialsur (4 reglas — formato tabular, P/M, Cajas+Unidades, eslogan), Makro (2 — similar mayorista), Mercadona (3 — ticket lineal IVA incluido, Hacendado), Lidl/Carrefour/Consum/Hiperber/Family Cash/Bricomart (formato típico de cada hiper), Amazon, Persagas, Sercat, JoverFruits, Brotons, La Bodegueta.
    • MejoraScript idempotente: comprobación por (cuentaBancoId + texto + proveedorId) antes de insertar. Re-ejecutar el seed no duplica reglas. Si un proveedor no existe aún en la BD, salta su regla específica (se puede re-ejecutar tras crear el proveedor en /admin/proveedores).
    • MejoraEn el panel /admin/sistema/ia-memoria las reglas seed aparecen con badge 🌱 'Seed' (distinguibles de las destiladas 🧠 IA y las manuales ✍️). Se pueden desactivar/editar como cualquier otra.
  35. v80May 2026

    Memoria IA acumulativa: la IA aprende de cada corrección, sin techo

    • Nuevo📚 Nueva tabla `TicketIAMemoria` y panel /admin/sistema/ia-memoria. Cada vez que corriges un ticket precategorizado por IA y lo guardas, se dispara una llamada extra a Gemini (fire-and-forget, no bloquea la UI) que DESTILA tu corrección a 1-3 reglas concisas en lenguaje natural (≤300 chars). Estas reglas se guardan permanentemente. Ejemplo destilable: «En facturas Dialsur la columna Total es SIN IVA — multiplica por (1+Tipo/100)».
    • NuevoEn cada precategorización futura, TODAS las reglas habilitadas de la cuenta se inyectan al prompt como bloque «📚 MEMORIA APRENDIDA» (cap 200 reglas, ordenadas por uso desc). Como cada regla son ~150 chars, caben 200 reglas en el espacio de 8 ejemplos JSON crudos. La memoria crece sin techo con el uso real, no se pierde al subir tickets de otros proveedores.
    • NuevoPanel admin completo en /admin/sistema/ia-memoria: lista todas las reglas con texto, proveedor asociado, cuenta, contador de uso, origen (🧠 IA destilada / ✍️ manual / 🌱 seed inicial). Permite activar/desactivar reglas con toggle, editar texto, eliminar, crear regla manual desde formulario. Filtros por texto/origen/solo-activas.
    • MejoraSeed inicial: regla para Dialsur «La columna Total es sin IVA, multiplicar por (1+Tipo/100)» ya cargada en la BD para la cuenta MOROS_N26. Las próximas facturas Dialsur usarán esta regla desde el primer ticket sin esperar a entrenamiento.
    • FixCorrección al prompt v79: los ejemplos Dialsur indicaban importe_eur = columna Total, lo cual era incorrecto (Total es sin IVA). Recalculados: 13,56 sin IVA × 1.21 = 16,41 €. Mismo cálculo aplicado a Whisky, Coca-Cola, Agua mineral (IVA 10%), Frutos secos.
    • MejoraServidor: nuevas server actions en src/app/actions/iaMemoria.ts (toggle/eliminar/crear/editar). Función `destilarYGuardarReglas` en src/lib/iaMemoria.ts con system instruction específico para Gemini. Audit log para todas las operaciones (CREATE_IA_MEMORIA, UPDATE_IA_MEMORIA, DELETE_IA_MEMORIA, ENABLE/DISABLE_IA_MEMORIA).
  36. v79May 2026

    Fix masivo doble-padding móvil · Prompt IA para facturas mayoristas (Dialsur)

    • Fix📱 Causa raíz del «todo se corta a la derecha» en móvil: 19 páginas (cuenta, gastos/reembolsos, mis-notificaciones, tareas, tablón, moros-comida, calendario, ayuda, gastos/editar, admin y sus 8 subrutas, tesoreria/historial) duplicaban el `px-4` que ya pone el `<main>` global de `layout.tsx`. Resultado: 32px robados a cada lado en vez de 16, encogiendo el viewport útil en ~64px. En móviles de 360-412px eso convertía cualquier tarjeta con cifras grandes, tabs largos o steppers en contenido cortado por el borde derecho. Quitado el px-4 redundante en las 19 páginas. Ahora todo el contenido respira los 16px estándar y nada se corta.
    • Fix🔧 Botones del configurador «Barra inferior (móvil)» en /cuenta más compactos: w-8→w-7 en móvil, gaps y padding interno ajustados (sm: mantiene tamaño grande). El botón ✕ ya no se pega contra el borde derecho del card en viewports estrechos.
    • Mejora🧠 Prompt IA de tickets muy reforzado para facturas mayoristas (Dialsur, Makro, Persagas, Sercat, …). Estas facturas tabulares (columnas Código/Descripción/Cajas/Unidades/Tipo/PvP/Total) tenían 4 fuentes de error sistémico: (1) descripciones y números en columnas con offset vertical, la IA emparejaba mal; (2) columna `Tipo` (10/21) tomada como cantidad cuando es % IVA; (3) `Cajas` + `Unidades` no se mapeaban bien al modelo `paquetes × contenido_por_paquete`; (4) la IA cogía al CLIENTE («MAFEL SL · CIF B53041091») como proveedor en vez del emisor real (logo Dialsur top-right).
    • MejoraNuevo bloque «📄 FACTURAS DE MAYORISTAS / CASH & CARRY» en el prompt con: emparejamiento por orden vertical, explicación de cada columna, regla «el Total siempre es la última columna», marcadores `P`/`M`, líneas con Total=0,00€ son promociones (incluirlas con nota_linea), códigos repetidos no se consolidan, y 6 ejemplos reales extraídos de facturas Dialsur (Fanta, Coca-Cola, Whisky JW, Mahou 0,0 promo, San Miguel pack, Frutos secos).
    • MejoraRegla anti-cliente reforzada en `proveedor_comercio`: ahora la IA busca el emisor por logo top-right + esloganes («Cash & Carry», «Distribuidor», dominio @cash.musgrave.es) y descarta los bloques con CIF + dirección postal que son el receptor. En duda, mejor proveedor_comercio="" que poner al cliente.
    • MejoraCombinado con el aprendizaje IA de v76: las 2-3 primeras facturas Dialsur que corrijas a mano se inyectan como few-shot en las siguientes precategorizaciones de la misma cuenta. A partir de la 3ª-4ª factura del mismo proveedor la precisión sube notablemente.
  37. v78May 2026

    Auditoría: limpieza de antipatrones que escapaban a v77

    • FixTras la política responsive global de v77, audité elementos que la anulaban. Encontré 5 `w-56` y 1 `w-48` rígidos sin variante `sm:` que comían espacio en móvil (Tesorería: panel persona; Proveedores: input nombre). Convertidos a `w-full sm:w-56` / `w-full sm:w-48` para que en móvil ocupen toda la fila.
    • MejoraAuditoría completa de antipatrones responsive: 25 `min-w-[Npx]`, 61 `whitespace-nowrap`, 37 `break-words/break-all`, ningún `!important` problemático ni anchos inline en píxeles. Resto resultó ser legítimo: `flex-1 min-w-[Npx]` (correcto), badges cortos con `whitespace-nowrap`, tablas con scroll wrapper. Los 37 utilities `break-*` son redundantes con v77 pero no estorban (no-op).
  38. v77May 2026

    Responsive «sane defaults»: nada se rompe por defecto

    • Mejora🛡️ Reglas CSS globales en globals.css que cubren el 99% de los problemas de «se corta a la derecha» sin tener que añadir `min-w-0`, `break-words` ni `overflow-hidden` a cada componente nuevo. A partir de ahora cualquier feature nueva hereda buen comportamiento responsive de base.
    • FixCausa raíz del problema #1: los hijos de `.flex` y `.grid` ahora reciben `min-width: 0` automáticamente. Por defecto los items flex tienen `min-width: auto` («no encogeré por debajo de mi contenido»), y un identificador largo (`notificarAdmins`, `RecordatorioCobroLog`) o un email empujaba toda la fila más allá del viewport.
    • Fix`body` con `overflow-wrap: anywhere` → cualquier texto largo sin espacios (URLs, paths, IDs hex) se rompe en cualquier punto si no cabe, en lugar de empujar el contenedor.
    • Fix`<table>` con `max-width: 100%` y `word-break: break-word`. `<img>`/`<video>`/`<svg>` con `max-width: 100%` y `height: auto`. Cabeceras (`h1`-`h6`), `code`, `.font-mono` con `overflow-wrap: anywhere` explícito.
    • MejoraNueva sección «⚠️ REGLAS DE ORO» al inicio de `CLAUDE.md` con la checklist responsive que cualquier IA / sesión nueva debe leer antes de tocar UI. Indica qué cubren los sane defaults y dónde sí hace falta intervención puntual (charts con tooltips, tablas con muchas columnas).
  39. v76May 2026

    Tags múltiples · Proveedor único en ticket · Precio unitario · IA que aprende

    • Nuevo🏷️ Múltiples etiquetas por línea de gasto. Antes una línea solo podía tener una tag; ahora puedes asignar varias (ej. «Cena oficial» + «Bebida» + «Pólvora»). Nuevo componente TagsMultiSelect con chips + dropdown buscable + creación inline. Schema: tablas pivote GastoLineaTag e IngresoTag (N:M). El campo legacy `tagId` se mantiene poblado con el primer tag para no romper queries antiguas.
    • Nuevo🏪 Proveedor único por ticket. Al subir un ticket con IA o crear gasto manual, ahora hay un campo «Proveedor del ticket» a nivel cabecera. Al elegirlo se propaga a todas las líneas. Si el ticket tiene varias compras de proveedores distintos (caso raro), el campo per-línea sigue accesible para override puntual. La IA preselecciona el proveedor mayoritario detectado.
    • Nuevo💶 Precio por unidad base en el formulario de gasto. Donde antes solo se veía «3 ud × 1 ud/paquete = 3 ud total», ahora también aparece el precio resultante: «💶 12,30 €/uds.» y si hay paquetes «· 36,90 €/pack 6×25cl». Útil para detectar errores de tipeo (precio absurdo) o comparar formatos.
    • Nuevo🧠 La IA aprende de tus correcciones. Cada vez que se analiza un ticket y se guarda el gasto, se persiste el JSON original que devolvió la IA junto con el JSON final que tú decidiste guardar (en una nueva tabla TicketIAExample con cuentaBancoId + proveedorId + diff resumido). En la siguiente precategorización de la misma cuenta, los últimos 5 ejemplos se incluyen en el prompt como pares «original → corregido» para que el modelo aprenda los patrones del comercio: nombres de artículos, categorías que prefiere el usuario, etc.
  40. v75May 2026

    Admin: IBAN + notificaciones por usuario · Presupuesto subtotales · Dashboard expandible móvil

    • Nuevo💳 En /admin/usuarios, al expandir un miembro hay nuevo campo IBAN editable inline (validación mod-97). Admin puede establecer/cambiar/borrar el IBAN de cualquier miembro sin que el propio usuario lo edite. Auditoría queda con `byAdmin: true`.
    • Nuevo🔔 Nuevo botón «Gestionar notificaciones» en cada usuario expandido. Abre modal con toggle global de email + matriz tipo×canal (📧 / 🔔) idéntica a la de Mi cuenta, pero apuntando al usuario seleccionado. Las prefs viven en SystemConfig.userNotifPref:{userId} sin tocar schema.
    • Nuevo💰 En /presupuesto-compras cada subcategoría muestra ahora subtotal € en el header (siempre, abierta o colapsada). Ejemplo: «Aperitivos y snacks · 4 art · 312,40 €». La categoría ya lo tenía, ahora también la subcategoría.
    • Fix📱 La tabla dinámica de gastos en /admin/gastos-dashboard ahora se puede expandir en móvil. Antes solo mostraba el nivel raíz con totales. Ahora cada nodo (categoría → subcategoría → artículo) es una card colapsable recursiva con indentación visual y triángulo ▶/▼, idéntica navegación que en desktop.
  41. v74May 2026

    Fix: digest diario llegaba como push cada hora

    • Fix🔔 El resumen diario de provisiones vencidas que se introdujo en v73 llegaba como push cada hora al cron tick (en Android se notaba especialmente al descartar la notif: volvía a sonar a la siguiente hora). Causa: `notificarAdmins` llamaba a `sendPushToAdmins(...)` fire-and-forget DESPUÉS del bucle de `crearNotificacion`, sin pasar por su dedup. La fila in-app sí estaba deduplicada por (admin, tipo, entityId) con cooldown 24h, pero la push externa se enviaba cada vez igualmente.
    • FixEliminada la llamada extra a `sendPushToAdmins`. Ahora `notificarAdmins` confía 100% en `crearNotificacion`, que ya envía push deduplicado uno-a-uno a cada admin. Mismo patrón que `notificarTodosActivos`. Resultado: una sola push al día por admin, como debe ser.
  42. v73May 2026

    Digest diario de provisiones vencidas (en vez de N push/día)

    • Fix🔕 Antes admin/tesorero recibía 1 push por cada provisión vencida — si había 11 ingresos sin cobrar = 11 push/día. Ahora `checkProvisiones()` envía UNA sola notificación al día con conteo y totales agregados: «🔔 Resumen diario · 11 ingresos por cobrar (240 €) · 2 gastos por pagar (50 €)».
    • Mejora`entityId` basado en la fecha del día (`provisiones-YYYY-MM-DD`) → el cooldown de 24h del sistema de notificaciones garantiza una sola por día, aunque el cron pegue 24 veces.
    • MejoraFiltro corregido: tickets personales pendientes de reembolso (`afectaCajaReal=false`) y gastos ya liquidados (`liquidadoPorGastoId`) se excluyen del conteo. Solo cuentan deudas reales.
    • MejoraEl flujo de recordatorios escalonados al usuario destinatario (PRE_3 / POST_1 / POST_3 / POST_7 vía `enviarRecordatoriosCobros`) no cambia — sigue siendo individual y limitado a 4 push máximo por movimiento gracias al UNIQUE de `RecordatorioCobroLog`.
  43. v72May 2026

    Landscape global + logs con nombres en lugar de IDs

    • Fix📱 Pasada landscape: el menú de usuario, la campana de notificaciones, CommandPalette y todos los modales (IBAN, registrar gasto/ingreso, reembolso, ticket lobby, eliminar usuario, welcome tour) ahora usan `max-h-[Ndvh]` con scroll interno. Antes en orientación horizontal con teclado abierto algunos quedaban cortados arriba/abajo o el botón de cerrar caía fuera del viewport.
    • Fix🧭 Menú de cuenta (avatar) reemplaza altura libre por `max-h-[calc(100dvh-5rem)]` con `overflow-y-auto overscroll-contain`. En móvil landscape (~360px alto) la lista de 9 items con divisores ya no se sale por abajo.
    • Mejora📝 Logs (/admin/sistema/logs): los `entityId` de tipo User, Gasto e Ingreso se resuelven a nombres legibles ("Pepito Pérez", "Carnes (24,50 €)", "Cuota mensual (10,00 €)"). Para detalles JSON, los campos `userId`, `ownerId`, `miembroId`, `asignadoAId` también se hidratan con el nombre. Bulk fetch (3 queries totales) → sin N+1.
    • Mejora🏷️ Logs: 14 acciones nuevas etiquetadas (`USER_UPDATE_IBAN`, `DELETE_USER`, `UPSERT_PRESUPUESTO_*`, `SYNC_PRESUPUESTO_FROM_FORECAST`, etc.). Las que aún no estén mapeadas pasan por un humanizer (`auto_fill_presupuesto` → `Auto fill presupuesto`) en lugar de mostrar el código crudo.
  44. v71May 2026

    Salud del sistema unificada en una sola pestaña

    • Nuevo🚦 /admin/sistema/salud rehecho como panel único de salud con semáforo. Cabecera resumen («Todo en orden» / «N alertas» / «N errores críticos») y 7 tarjetas con estado verde/ámbar/rojo: 🩺 Cron heartbeat, 💾 Backup automático, 📡 Push, 📧 Email, 🔔 Recordatorios, 💰 Cuotas atrasadas, 📊 Presupuesto. Cada tarjeta enlaza a la pestaña con detalle.
    • MejoraCada tarjeta muestra una métrica clave en grande (ej. «hace 14 min», «2 categorías >90%», «3 miembros sin push») y un subtítulo explicativo. El color del semáforo se calcula con lógica específica por subsistema (cron OK <90 min, presupuesto rojo si alguna categoría >100%, etc.).
    • MejoraBloque expandible «🔍 Detalle de alertas» abajo con las listas concretas de miembros sin push, miembros con cuotas atrasadas y categorías cerca/sobre presupuesto. Solo aparece si hay alertas activas.
  45. v70May 2026

    Barra inferior (móvil) personalizable por usuario

    • Nuevo🧭 Cada miembro decide qué accesos directos aparecen en la barra inferior cuando usa la app en móvil. Catálogo de 14 destinos: Inicio, Subir ticket, Reembolsos, Análisis, Tesorería, Comidas, Calendario, Tablón, Votaciones, Tareas, Inventario, Admin, Mi cuenta, Notificaciones.
    • NuevoMínimo 2, máximo 5 accesos. Reordenables con flechas ↑/↓. La configuración se guarda en `SystemConfig.userBottomNav:{userId}` (sin tocar schema).
    • MejoraFiltrado automático: si un acceso requiere rol (ej. Tesorería) o un feature flag desactivado a nivel global (ej. Tablón apagado), se oculta sin necesidad de reconfigurar. Cuando vuelva a ser válido aparecerá automáticamente.
    • MejoraDefaults respetan el comportamiento previo: usuarios normales tienen Subir ticket / Análisis / Comidas / Calendario, y admin/tesorero añaden Tesorería entremedias. Botón «Restaurar por defecto» para volver al estado de fábrica con un click.
    • MejoraConfigurable desde Mi cuenta → «Barra inferior (móvil)». La barra se actualiza al instante para todas las pestañas tras guardar (revalidatePath del layout).
  46. v69May 2026

    Heartbeat del cron + admin/sistema 100% responsive

    • Nuevo🩺 Nuevo bloque «Estado del cron» en la pestaña Backup con 3 indicadores: 💚 pulso (último hit al endpoint, fresh <90 min, stale >24 h), ✓ último backup real, 🔔 recordatorios enviados hoy. Resuelve la duda «¿está vivo el cron?» de un vistazo.
    • MejoraNuevo campo `BackupConfig.lastCronPingAt` que se actualiza en CADA hit a `/api/admin/backup/cron`, no solo cuando el backup real toca ejecutarse. Antes `lastCronRunAt` solo cambiaba a la hora UTC configurada (1×día), por eso parecía estancado.
    • Fix📱 Tabs de /admin/sistema: en móvil se muestran como nav scrollable horizontal con `whitespace-nowrap` y bordes a sangre. Antes con `flex-wrap` se rompían en 2-3 filas y quedaba feo.
    • Fix📱 Pestaña Logs: en móvil <768px la tabla se sustituye por cards apiladas con todo el detalle (acción, fecha, usuario, cambios). Filtros usan `grid` 1/2/3 columnas según ancho y los inputs de fecha pasan a fila completa con label arriba en móvil.
    • Fix📱 Layout sistema: quitado el doble `max-w-6xl px-4` que ya provee el layout global. Ganamos ancho útil en móvil y todas las subpáginas (config, backup, salud, push, logs) heredan el mismo wrapping.
  47. v68May 2026

    Dashboard analítica: pasada responsive integral

    • Fix📱 `/admin/gastos-dashboard` corregido a fondo: doble padding (la página tenía su propio `max-w-6xl px-4` dentro del layout que ya tiene `max-w-5xl px-4`). Ahora usa solo el wrapper del layout, ganando ~32px de ancho útil en móvil.
    • Fix📱 Form de filtros (Desde / Hasta / Cuenta / Aplicar): inputs con `flex-1 min-w-[140px]` para repartir bien el espacio en móvil; el select de cuenta ya no tiene `min-w-48` rígido y el botón ocupa fila completa cuando hace falta.
    • Fix📱 Tartas de gastos e ingresos por categoría: `outerRadius` pasa de fijo `110px` a relativo `75%`. Los labels de cada porción ahora son solo el porcentaje (sin el nombre) y se ocultan automáticamente en porciones <6%. Leyenda añadida abajo del chart con el nombre completo de cada categoría/tipo.
    • Fix📱 Comparativa año anterior: ancho del eje Y se reduce de 120px → 80px, fuente 11→10 y los nombres se truncan a 12 caracteres en lugar de 16. El chart cabe entero sin scroll lateral en móviles ≥320px.
    • Fix📱 Todos los gráficos: tooltips con `wrapperStyle={fontSize:11, zIndex:50}` y `allowEscapeViewBox={x:false, y:false}` explícito. Cards de gráficos con `overflow-hidden` y `min-w-0` para que tooltips y barras nunca escapen el contenedor visualmente.
  48. v67May 2026

    Pasada responsive móvil: Cuenta y Dashboard tesorero

    • Fix📱 Mi cuenta → Notificaciones: el botón «Desactivar» del toggle de push y el contenedor de «Emails de notificación» se cortaban a la derecha en pantallas <400px. Causa: los `<div>` de texto no tenían `min-w-0 flex-1`, por lo que rechazaban encogerse y empujaban el botón fuera del viewport.
    • Fix📱 Matriz de preferencias por tipo de aviso: la columna «Push» se cortaba parcialmente porque las cabeceras `📧 Email` y `🔔 Push` ocupaban demasiado en móvil. Ahora en <640px se muestran solo los iconos (📧 / 🔔) y `table-fixed` reparte el espacio. El icono completo aparece a partir de tablet.
    • Fix📱 Dashboard tesorero (Comparativa mensual + Evolución del saldo + Top proveedores + Heatmap): cards con `overflow-hidden` para que tooltips de Recharts y barras horizontales nunca escapen la tarjeta. Tooltip explícito con `allowEscapeViewBox={x:false,y:false}` y fontSize reducida.
    • Fix📱 Top proveedores: el bloque del lado derecho (líneas + total + %) escondía la columna «X lin.» en móvil para dar más espacio al nombre del proveedor; reaparece en sm:+. El nombre tiene `flex-1 min-w-0` y trunca con elipsis correctamente.
  49. v66May 2026

    Limpieza: las 5 carpetas legacy de admin desaparecen

    • MejoraLas 5 redirects de v65 (`/admin/config-sistema`, `/admin/backup`, `/admin/health`, `/admin/push-debug`, `/admin/logs`) que vivían como `page.tsx` cada una se mueven a la sección `redirects()` de `next.config.ts`. Las 5 carpetas legacy se eliminan por completo del App Router. El árbol queda más limpio.
    • MejoraBeneficio práctico: redirects 308 (permanente) gestionados por el edge en lugar de renderizar una page React solo para hacer `redirect()`. Más rápido y propiamente cacheable. Cero archivos huérfanos.
  50. v65May 2026

    Sistema unificado: las 5 cards de admin se fusionan en una sola con pestañas

    • Nuevo🛠️ Nueva ruta `/admin/sistema` con 5 pestañas en un único panel: ⚙️ Configuración · 💾 Backup · 🩺 Salud · 📡 Push · 📋 Logs. Antes eran 5 pages separadas (`/admin/config-sistema`, `/admin/backup`, `/admin/health`, `/admin/push-debug`, `/admin/logs`) con chrome duplicado. Ahora hay un layout server compartido que centraliza auth + ← Admin + h1 + tab nav, y cada subpágina solo aporta su contenido.
    • MejoraEl hub `/admin` muestra ahora una única card «Sistema e infraestructura» en el grupo «Sistema», en vez de las 5 anteriores. Mucho menos ruido visual.
    • MejoraLas 5 rutas antiguas (`/admin/config-sistema`, `/admin/backup`, `/admin/health`, `/admin/push-debug`, `/admin/logs`) se mantienen como redirects 301 → la nueva ruta correspondiente, así que cualquier bookmark sigue funcionando. Los query params del registro de actividad (filtros, paginación) se preservan.
    • MejoraTab nav en cliente con `usePathname` resalta automáticamente la pestaña activa. Server Actions (`saveBackupConfig`, `setSystemConfig`, etc.) actualizadas para revalidar las nuevas rutas.
  51. v64May 2026

    Admin reorganizado en 3 grupos + toggle de recordatorios

    • Nuevo🔔 Toggle «Recordatorios automáticos de cobros y pagos» en /admin/config-sistema. Apaga el envío de PRE_3 / POST_1 / POST_3 / POST_7 sin tocar la configuración personal de cada miembro. Default ON. Persiste en SystemConfig.key=recordatorios_cobros_enabled con audit log.
    • Mejora🗂️ /admin reorganizado: las 11 cards estaban dispersas. Ahora se agrupan en 3 secciones con cabecera: «🎯 Operaciones del año» (Usuarios destacado + Comidas Moros + Calendario + Sobrantes), «🗂️ Datos maestros» (Cuentas bancarias + Defaults de paquete) y «🛠️ Sistema e infraestructura» (Configuración + Backup + Salud + Push debug + Logs). Más fácil encontrar cada cosa.
  52. v63May 2026

    Recordatorios push automáticos sin configurar nada externo

    • MejoraLos recordatorios de v62 ahora se ejecutan dentro del cron horario que ya corre el contenedor `backup-cron` (docker-compose.nas.yml). No hay que tocar Synology Task Scheduler ni añadir nada en .env.nas — sale de fábrica con el deploy.
    • MejoraLógica refactorizada a `src/lib/recordatoriosCobros.ts`. La idempotencia (`RecordatorioCobroLog` UNIQUE) garantiza que aunque el cron pegue cada hora, cada miembro recibe la push una sola vez por cada (movimiento, día) — la primera ejecución del día envía y las siguientes son no-op.
    • NuevoSwitch global vía SystemConfig.key=`recordatorios_cobros_enabled` (default true). Helpers `isRecordatoriosCobrosEnabled()` / `setRecordatoriosCobrosEnabled(bool)` listos para añadir un toggle en /admin si en algún momento quieres desactivarlo sin redeploy.
    • MejoraEl endpoint `POST /api/cron/recordatorios-cobros` se mantiene como gatillo manual (curl con BACKUP_CRON_SECRET) por si quieres forzar un envío de prueba sin esperar al cron.
  53. v62May 2026

    Cobros/pagos a un click + recordatorios push automáticos

    • Nuevo✓ Botón inline «Cobrado» / «Pagado» en cada item de «Movimientos previstos vencidos» (tesorería): un click pasa la provisión a REAL con fecha = hoy. Tickets de reembolso pendientes muestran un chip informativo «Ticket reembolso» (siguen su propio flujo desde tesorería).
    • Nuevo🔔 Recordatorios push automáticos vía cron diario `/api/cron/recordatorios-cobros`: para cada ingreso/gasto PROVISION asignado a un miembro, envía push 3 días ANTES del vencimiento (aviso preventivo) y luego a los D+1, D+3 y D+7 si sigue sin cobrarse/pagarse. Cuatro escalones con tono creciente.
    • MejoraIdempotencia: nueva tabla `RecordatorioCobroLog` con UNIQUE(entity, entityId, userId, kind) garantiza que cada combinación se envía como mucho una vez en toda la vida del movimiento. Si el cron dispara dos veces el mismo día → no duplica.
    • MejoraReusa los tipos `PROVISION_VENCE_INGRESO` / `PROVISION_VENCE_GASTO` ya configurables en Mi Cuenta → Notificaciones (push activo por defecto, email no), así que cualquier miembro puede silenciar este canal a su gusto.
  54. v61May 2026

    Tesorería: eliminado el resumen agregado por cuenta

    • MejoraEliminado el bloque «Cuenta General (Tesorero) / N26 (Moros): pendientes de pago» que mostraba el agregado por usuario. La información que daba (provisiones vencidas) está cubierta por «Movimientos previstos vencidos» de v60 con detalle por movimiento individual y mejor cobertura (cuotas, comidas Moros, recurrentes y manuales).
    • MejoraLimpieza de imports y `useMemo` muertos asociados (`labelUserWithCode`, `resumenPorUsuarioFiltrado`).
  55. v60May 2026

    Movimientos previstos vencidos: vista plana en tesorería

    • Nuevo🕐 Nueva sección «Movimientos previstos vencidos» en /tesoreria: lista cualquier provisión (ingreso o gasto) cuya fecha ya pasó y que aún no se ha cobrado/pagado. Cubre cuotas mensuales, comidas Moros, gastos recurrentes y movimientos manuales — da igual el origen.
    • FixAntes la tabla agregada por usuario podía decir «todos al día» aunque hubiera ingresos previstos vencidos no relacionados con la cuotaProvisionConfig (ej. cenas Moros del 7 sin cobrar). Ahora la sección plana muestra cada uno individualmente con días de retraso, persona, cuenta e importe.
    • MejoraCada item resaltado en rojo (ingresos por cobrar) o ámbar (gastos por pagar). Total agregado arriba. Los más antiguos primero. Si hay >8, botón para ver el resto.
  56. v59May 2026

    Pasada responsive: textos largos no cortan el móvil

    • FixReglas CSS globales: en móvil cualquier texto monoespaciado (IBANs, IDs hex de gastos, endpoints) se rompe automáticamente para no desbordar el contenedor. Headings (h1-h4) se parten en cualquier punto si son demasiado largos para la pantalla.
    • FixEditor de presupuesto (zona Forecast): la grid de 6 columnas fijas (Nº · Cantidad/uds · Unidad · Formato · €/uds · Total) ahora se reorganiza en 3 columnas en móvil con el Formato y el Total ocupando líneas completas. Antes desbordaba en pantallas <400px.
    • MejoraUtility class `.scroll-x` para envolver tablas anchas con scroll horizontal limpio (incluye scrollbar fina y touch-smooth).
  57. v58May 2026

    Lint limpio: 976 errores → 0 errores

    • FixLint pasa ahora con exit code 0 (antes rompía con 976 errores). Configuración relajada para warnings de deuda histórica conocida (Prisma any types con prefijo legacy, args no usados con `_`, @ts-ignore con descripción).
    • MejoraAuto-fix aplicado: comillas, prefer-const, eslint-disable redundantes. Override para tests (any libre) y .claude/worktrees (ignorado).
    • MejoraQuedan 415 warnings (todos no críticos), reducción del 65% sobre los 1185 problemas iniciales. Ningún cambio funcional, solo configuración + autofix puramente sintáctico.
  58. v57May 2026

    IBAN visible en el flujo de reembolsos

    • Nuevo💳 En el modal de pago de reembolsos (Tesorería), al elegir una persona aparece su IBAN con un botón «📋 Copiar» para llevarlo a la app del banco con un click. Si la persona aún no lo configuró, se muestra un aviso ámbar con instrucciones.
    • NuevoLista de usuarios (Admin → Gestión de usuarios): cada miembro tiene ahora un chip de estado «💳 IBAN» (azul) o «⚠️ Sin IBAN» (ámbar) para que admin y tesorero vean de un vistazo a quién falta por pedirle.
  59. v56May 2026

    IBAN personal + banner push persistente

    • Nuevo💳 IBAN personal: en Mi cuenta puedes guardar tu IBAN para que tesorería te haga los reembolsos. Validación con dígitos de control mod-97 (ES, FR, DE, GB y 75 países más). Si no lo tienes configurado, al loguearte aparece un modal recordándotelo. El modal se puede cerrar pulsando «Más tarde» y reaparece cada 24 h hasta que lo rellenes.
    • Nuevo🔔 Banner push persistente: a usuarios autenticados sin notificaciones activas les aparece un cartel ámbar en cada visita. Si lo cierran, vuelve a aparecer a la semana. Mucho más alcance que el AutoPushPrompt original que solo intentaba una vez.
    • FixCambiar VAPID en producción ya no requiere intervención manual: las suscripciones viejas se invalidan solas y se generan nuevas (v55). Combinado con el banner persistente y el modal de IBAN, los miembros que entren tras el deploy quedan operativos sin necesidad de explicarles nada.
  60. v55May 2026

    Push: re-suscripción automática tras cambiar VAPID

    • FixTras regenerar las claves VAPID, las suscripciones viejas firmadas con la clave anterior daban [403] «VAPID credentials do not correspond». Ahora AutoPushPrompt y PushNotificationToggle comparan la clave usada por la suscripción del navegador con la VAPID actual del .env. Si no coinciden, desuscriben y re-suscriben automáticamente al abrir la app.
    • NuevoBotón «🧹 Purgar todas (post-VAPID)» en /admin/push-debug: borra todas las suscripciones de la BD de un golpe. Útil tras regenerar VAPID en producción para forzar a que los miembros reciban una invitación limpia al volver a abrir la app.
  61. v54May 2026

    Diagnóstico push + banner instalación iOS

    • NuevoAdmin → Diagnóstico push: ve estado VAPID en producción, suscripciones por usuario y envía push de prueba a cualquiera. Si VAPID no está configurado, instrucciones para arreglarlo.
    • FixwebPush.ts: antes se tragaba silenciosamente cualquier error que no fuera 404/410. Ahora loggea en consola del servidor (visible en `docker logs`) y devuelve resumen detallado con statusCode y body de cada fallo. Esto explica por qué algunas push no llegaban: ahora puedes ver exactamente qué falla.
    • NuevoBanner de instalación iOS: si abres la app desde Safari en iPhone sin tenerla instalada, aparece un cartelito con instrucciones (Compartir → Añadir a inicio). Apple no permite Web Push en Safari sin PWA instalada.
  62. v53May 2026

    Dashboard tesorero más rico: 4 secciones nuevas

    • Nuevo📅 Comparativa mensual: barras agrupadas mostrando gastos {anio} vs {anio-1} mes a mes, con delta anual. Visible solo para ADMIN/TESORERO en /admin/gastos-dashboard.
    • Nuevo📈 Evolución del saldo: línea temporal del saldo acumulado (ingresos REAL − gastos REAL − pagos reembolso) durante el periodo seleccionado, con saldo final y delta.
    • Nuevo🏪 Top proveedores: lista ordenada de los 10 proveedores con más gasto en el periodo, con barras de progreso, % del total y nº de líneas.
    • Nuevo🗓️ Heatmap de cuotas: matriz miembros × 12 meses del año mostrando ✓ pagado (verde), · parcial (ámbar), ✗ pendiente (rojo), futuro (gris claro), excluido (gris). Ordenado por pendiente descendente y total pendiente por miembro.
    • MejoraLas 4 secciones se calculan en server con queries optimizadas (cuotas usa cuotaProvisionConfigId, saldo usa aggregates por rango). Solo se cargan si el usuario es admin o tesorero — los miembros normales no ven nada nuevo.
  63. v52May 2026

    Suite de tests críticos: 13 → 80

    • MejoraSubido el coverage de funciones puras de lib/ de 13 a 80 tests (4 archivos nuevos): unidadMedidaGasto (parse, label, infer), gastoPrecategorizar (findBestByNombre, parseEuroStringToNumber, escalar, prepararLineas, parseFecha, parseJsonFromModelContent), formatFecha (5 funciones), catalogoGastoFilter, articulosCatalogo.
    • MejoraCubre regresiones críticas: cálculo de cantidad/contenido en líneas, scaling al total del ticket, fuzzy matching de catálogo, parsing flexible de fechas DD/MM/YYYY y DD-MM-YYYY, JSON envuelto en markdown del modelo IA.
  64. v51May 2026

    Filtros avanzados + export CSV en historial de gastos

    • NuevoHistorial de movimientos en /gastos/reembolsos?tab=historial: panel de filtros con búsqueda libre, tipo (pendiente/liquidado/pago), categoría, proveedor, tag, rango de fecha y rango de importe. Botón «Limpiar todos» y resumen en vivo (X de Y filas, saldo neto).
    • NuevoBotón «📥 CSV» que descarga la vista filtrada con punto y coma (Excel ES) y BOM UTF-8. Una fila por línea de gasto con categoría/subcat/artículo/cantidad/unidad/proveedor/tag/IDs.
  65. v50May 2026

    Wizard Sobrantes + Re-procesar IA + backlog organizado

    • NuevoWizard guiado «🪄 Cerrar año Moros» en /admin/sobrantes-moros: 3 pasos (intro → marcar sobrantes → confirmar) y al guardar muestra forecast del próximo año listo. Al primer cierre se abre por defecto; el panel avanzado sigue disponible con un toggle.
    • NuevoBotón «🤖 Re-procesar con IA» al editar un ticket existente: descarga la foto guardada, la pasa por Gemini con el catálogo actual y reemplaza las líneas. Útil tras añadir defaults de paquete o ajustar el prompt.
    • FixCLAUDE.md: documentado que el volumen Docker para uploads ya estaba bien configurado (yeguada_uploads + chown en Dockerfile). Era una nota obsoleta.
  66. v49May 2026

    Modelo unificado en TODA la plataforma (no solo subir ticket)

    • FixTesoreriaPageClient.GastoLineasEditor (editar líneas de gasto desde tesorería) usaba el modelo viejo cantidad+unidad. Ahora también muestra Nº · Cantidad/uds. · Unidad · Formato y persiste en BD con paquetes/contenidoPorUnidad/unidadVentaLabel.
    • FixTesoreriaReembolsoModal (modal de pago de reembolsos editando líneas de tickets) idem: cuatro inputs en lugar de dos.
    • MejoraMovimientoDetalleModal: cuando una línea de gasto está en modo paquete muestra «3 × bandeja 250 g» con el total en unidad base debajo. Antes solo «3 kg».
    • MejoraServer actions (getGastosPageData, getTicketsPendientesReembolsoForUser, gastosTotales de tesorería) devuelven ahora siempre paquetes, contenidoPorUnidad y unidadVentaLabel para que todos los formularios puedan reconstruir las líneas viejas como Nº=1 sin perder datos.
  67. v48May 2026

    Editor de presupuesto rediseñado: Forecast vs Presupuesto vs Diferencias

    • MejoraEditor del presupuesto separado en tres zonas claras: 📊 Forecast {anio-1} (gris, no editable, muestra Nº · Cantidad/uds · Unidad · Formato · €/uds · Total del año anterior); ✏️ Presupuesto {anio} (azul, editable, mismos campos como input); 📈 Diferencias (deltas en unidad base, Nº y €).
    • MejoraEl forecast ya no se puede modificar — es lo que se gastó/calculó del año pasado. Solo se edita lo presupuestado, y a la derecha aparece si el presupuesto sube o baja respecto al año anterior.
    • MejoraTotal preview en el bloque editable junto a los campos para ver el efecto de cada cambio sin bajar a los deltas.
  68. v47May 2026

    IA: «no inventes pesos» cuando no hay datos claros

    • MejoraAntes el prompt animaba a la IA a estimar pesos típicos (canónigos = 100 g, champiñón bandeja = 250 g…). Eso fabricaba números que después salían en los totales. Nueva regla: si el ticket no muestra el peso/volumen, la IA debe poner Nº=1, contenido=1, unidad=UNIDADES — mejor «no lo sé» que un dato falso.
    • MejoraProductos como «1 CANÓNIGOS 1,19€» o «1 CHAMPIÑON BANDEJA P» quedan ahora como 1 uds. con formato descriptivo («bolsa», «bandeja») en lugar de inventarse 100 g/250 g.
  69. v46May 2026

    Bug raíz: el flujo de IA no pasaba por el extractor

    • FixLas versiones 41-45 modificaron mapLineaIA pero el endpoint /api/gastos/precategorizar usaba un mapeo PARALELO en catalogResolve.ts que ignoraba paquetes/contenido/extractor. Por eso «1 ICEBERG 250 GR» seguía saliendo como Cantidad/uds=1. Ahora catalogResolve aplica el mismo modelo unificado y el extractor determinista de peso del nombre. Por fin el flujo está completo: IA → catalogResolve (con extractor) → form.
    • MejoraLog [catalogResolve] en dev muestra para cada línea qué dijo la IA y cómo quedó tras el post-procesado.
  70. v45May 2026

    Footer mobile + ticket por API + log IA

    • MejoraFooter ahora también visible en móvil con dos enlaces separados: «📜 Estatutos y FAQ» y la píldora de versión «🚀 v45» que lleva al changelog completo
    • FixImagen del ticket en el historial: nueva ruta API segura (/api/gastos/ticket/[filename]) que sirve el archivo con autenticación y comprobación de permisos. Funciona también si Docker no monta el volumen estático de uploads. Las URLs nuevas usan esta ruta automáticamente.
    • MejoraSi la imagen del ticket no carga (archivo perdido), aparece un aviso ámbar en lugar de un cuadro roto.
    • MejoraLog de diagnóstico en mapLineaIA (solo en dev): muestra qué devolvió la IA y cómo lo mapeamos, para depurar casos donde el peso no se extrae bien.
  71. v44May 2026

    Extracción determinista del peso (no depende de la IA)

    • FixEl IA seguía dejando «1 ICEBERG 250 GR» como Cantidad/uds=1 + kg, ignorando el peso. Ahora añadido un post-procesado determinista por regex: si el nombre del producto contiene un peso/volumen explícito (250 g, 1 kg, 70 cl, 500 ml, 1,5 L), se sobreescribe lo que diga la IA. Ya no depende de que Gemini haga caso.
    • MejoraEl formato se enriquece con la medida cuando ya tenía texto sin número (ej. IA da «bandeja» → queda «bandeja 250 g»).
    • MejoraTests: 8 casos cubriendo gr, kg, L, cl, ml y falsos positivos del tipo «1 KG no es 1 g».
  72. v43May 2026

    IA con peso del nombre + pendientes manuales por cuenta

    • MejoraIA del ticket: ahora extrae el peso/volumen del nombre del producto. «1 ICEBERG 250 GR» pasa a Cantidad/uds=0,25 kg + Formato=«bandeja 250 g». Reglas de conversión explícitas (g→kg, cl→L, ml→L) y muchos más ejemplos en el prompt.
    • MejoraTesorería: en cuentas sin cuota mensual programada también aparecen los miembros con provisiones de ingreso manuales (creadas a mano por tesorería). Antes la pestaña de la cuenta salía vacía.
    • FixTest obsoleto que esperaba expectedEur calculado por meses × cuota actualizado al modelo actual (real + provisión existente en BD). Vitest ya no lee tests del worktree.
  73. v42May 2026

    Modelo unificado también en editar ticket

    • MejoraEl editor de tickets existentes (/gastos/editar/[id]) ahora usa el mismo modelo unificado: Nº × cantidad/uds. + unidad + formato opcional. Al abrir un ticket viejo, se reconstruye con Nº=1 y se puede pasar a paquetes editando.
    • MejoraPreview en vivo del total bajo cada línea al editar (igual que en el form de subida).
  74. v41May 2026

    Modelo unificado: Nº × cantidad/uds. + unidad

    • MejoraEliminado el toggle Suelto/Paquete del form de gastos y del editor de presupuesto. Ahora cada línea es siempre Nº (uds. compradas) × cantidad por uds. + unidad. Más simple y consistente.
    • MejoraEjemplos: 3 bandejas pollo 500g → Nº=3, cantidad=0,5, kg, formato=«bandeja». Aceite 5L → Nº=1, cantidad=5, L, formato=«garrafa 5 L». Pack 24 cervezas 33cl → Nº=1, cantidad=7,92, L, formato=«pack 24×33cl».
    • MejoraFormato (texto descriptivo) es opcional — se rellena solo si el artículo tiene paquete default configurado.
    • MejoraIA del ticket: el prompt pide ahora siempre los tres campos (paquetes, contenido_por_paquete, unidad_medida) con ejemplos de carne a granel, latas, garrafas y unidades sueltas.
    • MejoraAdmin → Defaults de paquete: copy actualizado, columnas renombradas a «Formato» y «Cantidad/uds.» para alinear con el form.
  75. v40May 2026

    Admin de paquetes con labels claros + más presets

    • MejoraAdmin → Defaults de paquete: cada campo tiene ahora su propio label encima («Cómo se vende» / «Contiene» / «Unidad») y un bloque de ayuda explica el modelo arriba
    • MejoraPreview en vivo bajo cada artículo: «1 × garrafa 5 L contiene 5 L». Se actualiza mientras tecleas y deja claro qué significa cada campo
    • NuevoPreset «🍺 Aplicar formatos típicos» ampliado: además de bebidas y desechables ahora cubre aceites (garrafa 5 L), vinagre, hielo, olivas, vermouth, tinto verano y más
  76. v39May 2026

    Cantidad, paquetes y precio visibles en cada fila del presupuesto

    • MejoraColumna Presupuesto: si una fila está en Suelto pero el artículo tiene formato de venta típico configurado, ahora se muestra la equivalencia en paquetes debajo (ej. 21 uds. ≈ 3,5 × pack 6)
    • MejoraColumna Precio/ud: además del precio por unidad base, ahora se muestra debajo el precio por paquete equivalente cuando el artículo tiene paquete default (y al revés en modo Paquete, donde ya se mostraba)
    • MejoraResultado: en cada fila ves siempre las tres caras del dato — cantidad en unidad base, equivalente en paquetes y los dos precios
  77. v38May 2026

    Vs forecast siempre visible en cada fila del presupuesto

    • MejoraLa línea «Vs forecast» de cada fila del presupuesto muestra ahora siempre los tres deltas (unidad base, paquetes y €), no solo cuando estás editando
    • MejoraDelta en paquetes visible también en filas en modo Suelto si el artículo tiene formato de venta típico configurado (default de paquete)
    • FixDelta en € de cada fila ahora se calcula como total presupuesto - total forecast (antes era cantidad delta × precio actual, infraestimaba el efecto del cambio de precio)
  78. v37May 2026

    Delta en paquetes y fix precio/ud base en preview

    • FixEditor del presupuesto en modo Paquete: el precio por unidad base se mostraba 100x menor ("0,01 €/uds." cuando debía ser "1,00 €/uds."). Era un /100 de más en la línea de preview.
    • NuevoVs forecast en el editor: además del delta en unidad base (L/kg/uds) y en €, ahora aparece el delta en nº de paquetes cuando estás en modo Paquete (forecast convertido a packs usando el contenido actual)
  79. v36May 2026

    Forecast con paquetes y separación changelog/FAQ

    • MejoraForecast del presupuesto muestra ahora la equivalencia en paquetes cuando el artículo tiene formato típico configurado (ej. cerveza Alhambra: forecast en L + en packs 24×33cl)
    • MejoraEditor del presupuesto: al cambiar a modo Paquete con campos vacíos, se prerrellenan label y contenido a partir del default del artículo. Sigues pudiendo cambiar todo manualmente.
    • MejoraSeparadas las novedades de la guía de uso: /ayuda contiene solo estatutos y tutoriales, /novedades contiene todo el changelog histórico
  80. v35May 2026

    Sesión que sobrevive a horas/días sin uso

    • FixVuelves a la app y sigues logueado: el service worker ya no cachea HTML (causaba CSRF caducado y 401 al interactuar) y la sesión NextAuth pasa de 24 h fijas a 30 días con renovación automática diaria
  81. v34May 2026

    Defaults de paquete por artículo + auto-fill presupuesto

    • NuevoAdmin → «Defaults de paquete»: fija el formato típico de cada artículo (ej. cerveza Alhambra → pack 24×33cl, 7,92 L)
    • NuevoAuto-fill del presupuesto en modo Paquete: artículos con default se crean ya en pack, cantidad = nº de packs estimados, precio/pack derivado del histórico
    • NuevoBotón «Aplicar paquetes típicos bebidas» que siembra de golpe formatos habituales (cerveza pack 24×33cl, agua pack 6×1,5 L, vasos paquete 50 u…) sin tocar artículos ya configurados
    • MejoraForm de gastos: al elegir un artículo con default de paquete, la línea pasa a modo Paquete con label y contenido prerellenados
  82. v33Abr 2026

    Paquete vs cantidad también en gastos

    • NuevoForm de gasto: toggle Suelto/Paquete igual que el presupuesto. En modo Paquete indicas nº de paquetes + contenido por paquete y la app calcula la cantidad total en L/kg/uds.
    • NuevoLa IA detecta paquetes en el ticket y rellena nº de packs + contenido por paquete. Ej. «20 packs Alhambra 6×25cl» → paquetes=20, contenido=1,5 L, cantidad total=30 L
    • FixRetrocompatible con histórico: gastos antiguos del 2025 quedan intactos como compra suelta. Los campos de paquete son opcionales
  83. v32Abr 2026

    Forecast con precio y total visibles

    • NuevoCada fila del presupuesto muestra en la columna Forecast la cantidad estimada, el precio por unidad del año anterior y el total € aproximado
    • NuevoPreview en vivo al editar: cantidad final en unidad base, €/unidad, total y delta (cantidad y €) frente al forecast mientras tecleas
    • MejoraModo Paquete con cuadre automático: nº paquetes + contenido + precio/paquete → la app calcula la cantidad final y la contrasta con el forecast
  84. v31Abr 2026

    Edición admin de cenas + auto-archivo anuncios

    • NuevoAdmin puede seguir editando asistencia a cenas Moros aunque haya pasado la fecha límite. Selector «Editar como admin» para cambiar a quién se está editando. Cambios auditados.
    • NuevoAnuncios nuevos se auto-archivan a los 30 días. Archivado manual desde 📦 y restauración desde Histórico con ↩️
  85. v30Abr 2026

    Mis tareas pendientes primero + histórico

    • MejoraPantalla de tareas: tus tareas pendientes aparecen primero, luego «Otras tareas del cuartelillo»
    • NuevoHistórico de tareas: pestaña separada para tareas archivadas. Cualquier admin, creador o asignado puede archivar/reactivar
    • NuevoAuto-archivo de tareas completadas hace más de 14 días
  86. v29Abr 2026

    Votaciones: histórico, secretas y quién votó qué

    • NuevoPestañas Activas / Histórico para votaciones. Cualquier admin puede archivar (cierra y mueve a histórico) o reactivar
    • NuevoVotación secreta: «Ocultar resultados hasta cierre» — nadie ve recuentos hasta que la votación termina (admin y autor sí)
    • NuevoBotón «Ver quién votó qué»: lista por opción los votantes y los miembros pendientes de votar
  87. v28Abr 2026

    Píldoras enlazadas + FAQ ampliada

    • NuevoPíldora morada en home con encuestas pendientes en las que aún no has votado
    • MejoraTodas las píldoras de inicio (pagos, próxima cena, próxima reserva, tickets, tareas) son ahora enlaces directos a su pantalla
    • MejoraFAQ ampliada con sección de Encuestas y aclaraciones de archivado en Tareas y Tablón
  88. v27Abr 2026

    Presupuesto en modo paquete + packaging protegido

    • NuevoPresupuesto: editar en modo Suelto (kg/L/uds a precio por unidad base) o Paquete (nº paquetes × medida por paquete a precio por paquete). Ej. 1 × «garrafa 10 L» a 20 € → 10 L a 2 €/L
    • Fix«Sincronizar con forecast» respeta filas en modo paquete: no sobreescribe cantidad ni precio configurados a mano
    • MejoraDetalle de cada artículo muestra cantidad total en unidad base aunque compres en paquetes, y precio por unidad base bajo el precio por paquete
  89. v26Abr 2026

    Notificaciones por tipo + email configurable + reservas para todos

    • NuevoMi cuenta → Notificaciones: matriz por tipo (ticket aprobado, reserva, anuncio, movimiento a tu favor…) decides si recibirlo por email, push, ambos o ninguno. El historial in-app se conserva siempre en 🔔
    • NuevoEmail configurable desde admin: elige Gmail (con app password) o Resend, edita usuario/clave/API desde Configuración del sistema sin tocar .env. Botón de email de prueba
    • MejoraReservas de cuartelillo notifican ahora a todos los miembros activos (antes solo admins). Próxima reserva visible como píldora en home y en el calendario del lobby
    • MejoraTesorería más ordenada: filtro «Por fecha» colapsado, dashboard solo con tareas pendientes, bloques pendientes con estilo unificado
  90. v25Abr 2026

    Mejoras menores y fixes

    • MejoraPulido de la sesión v24 (versión histórica intermedia)
  91. v24Abr 2026

    Feature flags, tesorería mejorada y correcciones

    • NuevoFeature flags: activa o desactiva secciones de la app desde Administración → Configuración del sistema (tablón, votaciones, inventario, calendario, comidas, análisis, presupuesto)
    • NuevoEl menú de usuario, barra inferior y búsqueda global ocultan automáticamente las secciones desactivadas
    • MejoraTesorería: los pendientes de pago ahora se basan en registros reales de la BD (provisiones creadas manual o por programación) en vez de cálculo por calendario
    • MejoraSubir gasto sin IA: el ticket (foto o PDF) es ahora obligatorio antes de pasar al formulario
    • FixEliminado botón «Enviar recordatorio push» de Comidas Moros (ya disponible solo en administración)
    • FixLogo de la navbar restaurado a «Yeguada» (M&C solo para el icono de instalación PWA)
    • FixCorregido error de Prisma bundled en browser al cargar página de configuración del sistema
    • FixEliminado warning de React por <Script strategy=beforeInteractive> en App Router
  92. v23Abr 2026

    Votaciones, inventario, tablón de anuncios y mejoras de seguridad

    • NuevoTablón de anuncios: comunicados oficiales con push notification a toda la comparsa, con opción de fijar anuncios importantes
    • NuevoVotaciones / encuestas rápidas: crea encuestas con opciones, voto único o múltiple, fecha límite, barras de progreso en tiempo real
    • NuevoInventario del cuartelillo: gestión completa del material (CRUD, filtros por categoría/estado/búsqueda, agrupación visual)
    • NuevoDashboard personal mejorado: saludo con nombre, badge de pagos pendientes, próxima cena y tickets por revisar
    • NuevoCron resumen financiero mensual: endpoint /api/cron/resumen-mensual envía push con gastos/ingresos/saldo a admin y tesorero
    • MejoraSeguridad: Docker ejecuta como usuario no-root (USER nextjs), eliminados todos los $executeRawUnsafe con input de usuario
    • MejoraBúsqueda global (Ctrl+K): añadidas rutas de tablón, votaciones e inventario
    • MejoraPush notifications: activación automática al primer login (sin necesidad de ir a configuración)
  93. v22Abr 2026

    Cenas Moros: resumen por servicio, recordatorio push y mejora offline

    • NuevoResumen de asistencias por servicio en /moros-comida: muestra miembros e invitados por cada comida/cena de la semana
    • NuevoBotón «Enviar recordatorio push» para admins: notifica a miembros sin asistencia confirmada cuando el cierre está a ≤3 días
    • NuevoNotificaciones push web (PWA): soporte completo con service worker, VAPID y suscripción por usuario
    • NuevoComparativa año anterior en el dashboard de gastos: gráfico horizontal mostrando categoría por categoría el gasto actual vs el año pasado
    • NuevoAlertas de presupuesto: aviso cuando el gasto real de una categoría supera lo presupuestado
    • MejoraService worker mejorado con caché offline: cache-first para iconos y assets estáticos, stale-while-revalidate para páginas
    • FixUsuarios exentos de cuota (CuotaProvisionExclusion) ya no aparecen como deudores en tesorería
  94. v21Abr 2026

    Presupuesto Moros: fill/sync mejorado, diff de precio y actualización en tiempo real

    • Mejora«Añadir faltantes» salta artículos sin precio histórico y muestra cuántos se añadieron y cuántos se saltaron
    • NuevoBotón «Sincronizar con forecast»: sobreescribe cantidad y precio de los artículos ya presupuestados con los valores actuales del forecast
    • NuevoColumna «Vs forecast» muestra ahora el ahorro o coste extra en euros (verde = ahorro, ámbar = gasto extra)
    • MejoraEditar una línea actualiza la fila en tiempo real sin recargar toda la página
    • FixEliminar un artículo ya no lo vuelve a crear automáticamente al recargar la página
    • FixUsuarios sin rol admin/tesorero ya no reciben error «No autorizado» al acceder al presupuesto (vista de solo lectura)
  95. v20Abr 2026

    Forecast corregido: cuenta N26, precio real y ratio de raciones ajustado

    • FixEl forecast ahora solo considera gastos de la cuenta N26 (Moros), excluyendo gastos generales del tesorero
    • FixPrecio unitario calculado como coste real (importeCents / cantidad de GastoLinea del año anterior), no del presupuesto anterior
    • FixEliminado Math.ceil() al rellenar presupuesto — se usaba redondeo al alza que inflaba el total ~40% con 162 artículos
    • MejoraRatio de raciones incluye invitadosEstimacion en comidas y almuerzos, no solo invitados de cena
    • NuevoKPI «Gasto real año anterior» en el dashboard de presupuesto para comparar directamente con el total presupuestado
    • MejoraFiltro de categorías por defecto: Comida, Bebida y Plásticos y Limpieza (eliminados Mantenimiento, Seguridad, etc.)
    • MejoraFAQ y guía actualizados con sección Presupuesto Moros y Sobrantes & Forecast
  96. v19Abr 2026

    Presupuesto Moros mejorado: filtro de categorías, valores por defecto y forecast de invitados

    • MejoraPresupuesto Moros: filtro de categorías en la vista — por defecto muestra Comida, Bebida y Desechables. Se puede activar o desactivar cada categoría con un clic
    • MejoraAl abrir el formulario de edición de un artículo, la cantidad se pre-rellena con el forecast calculado y el precio con el del año anterior — solo hay que ajustar lo necesario
    • MejoraEl forecast ahora tiene en cuenta los invitados a comidas y almuerzos (invitadosEstimacion) además de los invitados a cenas, para calcular el ratio de raciones
    • NuevoWelcomeTour actualizado con paso sobre Presupuesto Moros
    • MejoraBackup: eliminada sección «Mantenimiento de datos» (ya no es necesaria)
    • MejoraSobrantes & Forecast admin: pestañas unificadas en una sola vista con selector de año para poder trabajar con históricos y futuros
  97. v18Abr 2026

    Orden de cuentas en lobby, filtro en gastos y correcciones de producción

    • MejoraEn el lobby, la cuenta N26 (predeterminada) aparece siempre la primera en la sección de saldos bancarios
    • NuevoFiltro de búsqueda en «Mis últimos gastos»: filtra por descripción, artículos o cuenta
    • MejoraPágina de cuenta (/cuenta): cabecera con avatar, nombre, badge de rol y email; sección de versión con enlace a novedades
    • FixError de build en producción: acción de mantenimiento limpiarCuotaConfigsDuplicadas envuelta correctamente para ser compatible con form action
    • MejoraWelcomeTour actualizado al nuevo menú de navegación con barra inferior
  98. v17Abr 2026

    Eliminar usuarios, bottom nav móvil y menú reorganizado

    Sprint de UX e integración: navegación nativa en móvil, menú de usuario por grupos, lobby limpiado, análisis de gastos renombrado y herramienta de eliminación de usuarios con reasignación de movimientos.

    • NuevoEl administrador puede eliminar usuarios desde la gestión de usuarios. Si el usuario tiene gastos o ingresos registrados, aparece un modal para elegir a quién reasignarlos antes de borrar. Las provisiones automáticas de cuota se eliminan directamente (el destino ya tiene las suyas)
    • NuevoBarra de navegación inferior en móvil (bottom nav): acceso directo a Subir ticket, Análisis de gastos, Comidas y Calendario. Admin y tesorero ven también Tesorería como quinto ítem
    • MejoraMenú de usuario reorganizado en grupos con emojis: Personal (tickets, comidas, calendario), Gestión (tesorería, análisis, compras), Admin y Cuenta
    • MejoraLobby: sección de saldos bancarios solo visible para admin y tesorero
    • Mejora«Dashboard gastos» renombrado a «Análisis de gastos» en toda la interfaz: lobby, menú, paleta de comandos y panel admin
    • MejoraPanel de administración: «Gestión de usuarios» pasa a ser la tarjeta destacada
    • FixFix push notifications: instancia Prisma cacheada no incluía el modelo PushSubscription — añadido al check de completeness del singleton para forzar recreación cuando el cliente está desfasado
    • MejoraNotificaciones push se reactivan automáticamente si el permiso ya estaba concedido (sin diálogo), útil al limpiar la BD o cambiar de dispositivo
  99. v14Abr 2026

    Previsiones corregidas, programador mejorado y filtros de tesorería rediseñados

    Sprint de tesorería: se corrige el bug raíz de la generación de previsiones mensuales, se mejora el programador de gastos/ingresos y los filtros de movimientos reciben un rediseño completo.

    • FixBug crítico: las previsiones mensuales solo se creaban para el primer mes en lugar de todos. Causa: skipDuplicates no existe en Prisma 6 con SQLite — reemplazado por pre-filtrado correcto con createMany
    • FixError HTTP 431 al cambiar fechas de una programación recurrente — los mensajes de error largos de Turbopack ya no se meten enteros en la URL
    • FixLas previsiones de meses pasados son ahora inmutables al cambiar el importe del config. Los cobros confirmados (REAL) tampoco se modifican nunca
    • NuevoBotón «Sincronizar previsiones» en el Programador de gastos/ingresos para crear de golpe las previsiones de miembros incorporados recientemente
    • MejoraPantalla de tesorería: tabla técnica Real/Previsión sustituida por vista accionable «quién debe» — se ven las personas pendientes ordenadas por deuda, con cuántos meses llevan pagados
    • MejoraFiltros de movimientos rediseñados: 4 secciones visuales (General, Fechas, Gastos, Importe), badge con número de filtros activos por sección, inputs destacados en azul cuando están activos
    • Mejora«Programación unificada» renombrado a «Programador de gastos/ingresos» en toda la interfaz
    • MejoraBanner de reglas en el Programador: instrucciones claras sobre cómo cambiar importes sin romper el histórico, e inmutabilidad de los cobros REAL
  100. v13Abr 2026

    Flujo de tickets completo, fix contabilidad y acceso directo desde menú

    • FixBug crítico de contabilidad: el dashboard de gastos sumaba el ticket Y el pago de reembolso, duplicando el déficit. Ahora solo cuenta el ticket (gasto de categoría); el pago de reembolso es solo movimiento de caja
    • NuevoCualquier miembro puede eliminar sus propios tickets pendientes o rechazados directamente desde «Mis tickets», con confirmación antes de borrar
    • NuevoEl tesorero puede eliminar cualquier ticket no reembolsado desde el panel de aprobación, también con confirmación
    • MejoraEl menú de usuario incluye ahora «Mis tickets» (acceso directo a /gastos/reembolsos con las opciones editar y eliminar). «Mis movimientos» sigue apuntando al historial
    • MejoraSeguridad: la lista de tickets del modal de pago solo muestra los ya aprobados — no se puede reembolsar un ticket que aún está en revisión o rechazado
    • MejoraLa columna «Pendiente» del resumen por usuario (vista tesorero) solo cuenta tickets aprobados. La vista propia del miembro sigue mostrando todo lo que tiene pendiente de cobrar
    • MejoraSeed 2025 actualizado: nombres y apellidos completos de todos los miembros, 3 nuevos miembros (Andrea, Álvaro, Ivan), email de Patricia corregido, ingreso de cierre 13,08€ para cerrar el ejercicio a cero
    • FixWarning React de key prop en la tabla de usuarios eliminado
  101. v12Abr 2026

    Panel de aprobación de tickets, tabla de usuarios compacta e icono PWA

    • NuevoPanel de aprobación de tickets en /tesoreria/reembolsos: botones «✓ Aprobar» y «Rechazar» con motivo, notificación push+email automática al miembro
    • MejoraTabla de gestión de usuarios rediseñada: filas compactas sin scroll lateral, panel expandible al tocar una fila con todos los controles de edición (email, teléfono, límite mensual, contraseña, modo test)
    • NuevoIcono PWA actualizado: caballo de frente sobre fondo dorado ámbar con texto «Yeguada» — se ve correctamente en pantalla de inicio de Android e iPhone
    • MejoraManifest.json separado en iconos «any» y «maskable» para compatibilidad óptima con adaptive icons de Android
    • Mejoraapple-touch-icon 180×180 dedicado para iPhone/iPad
    • MejoraFAQ y tutorial actualizados con los nuevos flujos de aprobación, tabla de usuarios y uso de PWA
  102. v11Abr 2026

    Edición de tickets, fix reset backup y seed cuadrado al céntimo

    • NuevoPágina /gastos/editar/[id]: formulario completo para editar tickets pendientes de reembolso, con líneas, categorías, cantidades y proveedor
    • NuevoBotón 'Editar ticket' en el modal de detalle de gastos recientes (solo tickets editables)
    • FixBug crítico Dockerfile: scripts/seed_inicial_snapshot.json no se copiaba al runner — el reset desde /admin/backup fallaba con ENOENT en producción
    • FixSeed 2025: 3 tickets con totales incorrectos corregidos (Patricia +8,76€, JoverFruits +0,10€, Paola +17,99€) → grand total exacto 9.623,66€
  103. v10Abr 2026

    Seed 2025 real, notificaciones ampliadas y mejoras de fiabilidad

    Sprint de datos y notificaciones: el seed de la fiesta 2025 ahora usa artículos y tickets reales del Excel, el sistema de notificaciones cubre reservas de cuartelillo y provisiones vencidas, y los errores del panel admin se muestran inline.

    • NuevoSeed de movimientos 2025 con datos reales por ticket: carnicero, JoverFruits, Dialsur, Carrefour y resto de proveedores con kg/litros/unidades exactos
    • NuevoCatálogo expandido a ~80 artículos reales (Pollo entero, Alhambra 25cl, Ginebra Seagram's, Fanta limón 2L…)
    • NuevoNotificación al reservar el cuartelillo: confirmación al usuario + aviso a admins
    • NuevoNotificación al cancelar una reserva: aviso al dueño si la cancela un admin, aviso a admins si la cancela el usuario
    • NuevoCron diario detecta gastos e ingresos en provisión con fecha vencida y notifica a admins para convertirlos en reales
    • MejoraPanel de backup: errores del reset/seed se muestran inline en lugar de romper la página
    • MejoraCLAUDE.md con contexto completo del proyecto para desarrollo en modo dispatch
  104. v9Abr 2026

    App instalable, modo oscuro y búsqueda global

    Sprint de experiencia: Yeguada ya se puede añadir como acceso directo en el móvil o el PC, incluye modo oscuro completo y una paleta de comandos para navegar rápido.

    • NuevoSe puede instalar como acceso directo en el móvil y el escritorio — sin APK ni tienda de apps, directamente desde el navegador
    • NuevoModo oscuro completo con alternancia sol/luna en la barra de navegación
    • NuevoEl tema recuerda tu preferencia entre sesiones (localStorage)
    • NuevoPaleta de comandos (Ctrl+K) para navegar a cualquier página al instante
    • NuevoLa paleta filtra resultados por rol (admin, tesorero, usuario)
    • MejoraFiltros avanzados en /gastos: categoría, subcategoría, proveedor, etiqueta e importe
    • MejoraSeed de instalación crea movimientos de 2025 automáticamente a nombre del admin
    • MejoraBarra de navegación rediseñada con soporte completo dark mode
    • MejoraMeta tags PWA y theme-color adaptativos según modo claro/oscuro
  105. v8Mar 2026

    Emails, proveedores y configuración del sistema

    Sprint de gestión avanzada: notificaciones por email, catálogo de proveedores, filtros en auditoría y ajustes globales de la plataforma.

    • NuevoEmails automáticos al aprobar, rechazar o reembolsar un ticket (vía Resend)
    • NuevoCada usuario puede activar o desactivar los emails desde su cuenta
    • NuevoEl admin puede gestionar las notificaciones email de cada usuario
    • NuevoGestión de proveedores: crear, editar, eliminar y fusionar duplicados
    • NuevoConfiguración del sistema: toggle global de emails y estado de credenciales
    • NuevoBotón «Reiniciar tour» por usuario para forzar el tutorial en el próximo login
    • MejoraFiltros de fecha y usuario en el registro de actividad (/admin/logs)
    • MejoraExportar presupuesto de compras a CSV (compatible con Excel)
    • MejoraAncho del panel de gestión de usuarios ampliado
    • FixCorrección de errores en notificaciones internas tras actualización de esquema
  106. v7Mar 2026

    Paginación, CSV y novedades

    Sprint de calidad: exportación de datos, navegación por páginas y este panel de novedades.

    • NuevoExportar movimientos a CSV desde Tesorería (compatible con Excel)
    • NuevoPaginación en el libro de movimientos (50 por página)
    • NuevoPanel de novedades con historial de versiones
    • MejoraFooter con versión actual, acceso a FAQ y novedades desde todas las páginas
    • FixScroll horizontal eliminado en la sección de movimientos en móvil
  107. v6Mar 2026

    Notificaciones en tiempo real

    Sistema de notificaciones internas para mantener a cada miembro informado de cambios que le afectan.

    • NuevoCampana de notificaciones en la barra de navegación
    • NuevoNotificación al aprobar o rechazar un ticket
    • NuevoNotificación al marcar un reembolso como pagado
    • MejoraBadge rojo con contador de no leídas (máx. 9+)
    • MejoraMarcar individualmente o todas como leídas
  108. v5Feb 2026

    Tour de bienvenida y FAQ mejorada

    Primera experiencia de usuario mejorada y guía de uso actualizada con flujos por rol.

    • NuevoTour animado de 5 pasos para nuevos usuarios
    • NuevoFAQ expandida con secciones por módulo y rol
    • NuevoFlujos visuales paso a paso en la guía de uso
    • MejoraSecciones de tesorero y administrador visibles solo para los roles correspondientes
    • NuevoSeed de instalación fresca con datos de demostración opcionales
  109. v4Feb 2026

    Auditoría con diff de campos

    El historial de cambios ahora muestra exactamente qué campo cambió, el valor anterior y el nuevo.

    • MejoraTimeline de auditoría en el detalle de cada movimiento
    • MejoraPágina /admin/logs muestra tabla de diferencias campo por campo
    • MejoraRegistro de cambios en gastos: fecha, descripción, cuenta, líneas
    • MejoraRegistro de cambios en ingresos: fecha, nota, cuenta
    • FixAdvertencia de encType eliminada en formularios con server actions
  110. v3Ene 2026

    Reembolsos y tickets de miembros

    Flujo completo para que los miembros soliciten reembolsos y el tesorero los gestione.

    • NuevoTickets de miembro: cualquier usuario puede registrar un gasto para reembolso
    • NuevoPanel de reembolsos pendientes en Tesorería
    • NuevoFlujo de aprobación / rechazo con motivo
    • NuevoPago de reembolso vinculado al gasto original
    • MejoraResumen 'Mis movimientos' para cada usuario
  111. v2Dic 2025

    Tesorería completa

    Módulo de tesorería con libro de movimientos, saldos por cuenta y presupuesto de compras.

    • NuevoLibro de movimientos con filtros por cuenta, fecha y tipo
    • NuevoSaldos en tiempo real por cuenta bancaria
    • NuevoPresupuesto de compras por categoría
    • NuevoIngresos: registro y categorización por tipo
    • MejoraDashboard de gastos con gráficos por categoría y proveedor
  112. v1Nov 2025

    Lanzamiento inicial

    Primera versión de la plataforma de gestión de la Yeguada.

    • NuevoRegistro de gastos con categorías, subcategorías y artículos
    • NuevoGestión de proveedores
    • NuevoAcceso por roles: Admin, Tesorero, Miembro
    • NuevoAutenticación con Google
    • NuevoGestión de comidas y cenas Moros