c84a07968f
useDragReorder resincronizaba su copia local solo cuando cambiaba el conjunto de ids, no cuando se editaba un campo de una tarea existente (marcar hecho, renombrar) -- la fila se quedaba mostrando el snapshot viejo para siempre despues de guardar. Ahora compara el contenido completo. De paso: draggable/onDragStart pasan a vivir solo en el icono de agarre, nunca en toda la fila -- un ancestro draggable=true le gana el mousedown a los controles interactivos que tenga adentro en algunos navegadores (no era la causa de este bug puntual, pero es un problema real del mismo patron que conviene cerrar ya que se reutiliza en cualquier lista futura). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
18 KiB
18 KiB
Changelog - project.linkedcorp.net
[1.15.2] - 2026-09-16
Fixed
- El checkbox de "hecho" de una tarea (y el renombrado en linea) dejaba de reflejarse tras
guardar:
useDragReorder(hook de arrastrar-para-reordenar, introducido en v1.14.0) resincronizaba su copia local solo cuando cambiaba el CONJUNTO de ids, no cuando se editaba un campo de una tarea ya existente (marcar hecho, renombrar) — la fila se quedaba mostrando el snapshot viejo para siempre. Reportado por el usuario ("no se marca, debe ser por el drag de mover tareas") — tenia razon en que era el drag, aunque la causa real no era la interferencia del arrastre con el click sino esta resincronizacion incompleta. Corregido comparando el contenido completo, no solo los ids. - De paso, separado
draggable/onDragStart(antes en toda la fila) para que vivan SOLO en el icono de agarre (GripVertical), nunca en la fila completa: un ancestrodraggable=truele gana el mousedown a los controles interactivos que tenga adentro en algunos navegadores. No era la causa de este bug puntual, pero es una corrección real y necesaria para que el patrón sea seguro de reutilizar en cualquier lista futura con controles interactivos en la fila.
[1.15.1] - 2026-09-15
Added
scripts/install.sh: instalador para desplegar en un servidor nuevo. Verifica requisitos (Node.js, npm, cliente mysql, systemd, espacio, puertos), pregunta dominio/puertos y base de datos (MariaDB local auto-instalada o un servidor existente), generabackend/.envcon secretos aleatorios, corre migraciones + catálogos, compila el frontend y crea/arranca los servicios systemd. No crea ningún usuario — el primer registro público se vuelve superadministrador solo (bootstrap ya existente).
Fixed
- Migración
006_seed_it_baseline.sqlfallaba (error de foreign key) al correr sobre una base de datos nueva/vacía, porque insertaba proyectos de ejemplo específicos de LinkedCorp asumiendo catálogos y un usuario ya existentes. Encontrado probando el instalador de punta a punta contra una BD recién creada. Ahora detecta si esos prerequisitos no existen (instalación nueva, otra empresa) y queda inerte para siempre ahí, sin afectar el comportamiento ya probado en dev/prod (donde el marcador de "ya aplicado" sigue intacto).
[1.15.0] - 2026-09-15
Added
- Marca de la empresa configurable: nombre y logo editables desde Configuración → Empresa (solo
superadmin), guardados en
system_settings(mismo patrón que SMTP, sin tabla nueva). Nuevo endpoint públicoGET /api/company(+/logo) para que login/registro/recuperación de clave puedan mostrar la marca antes de iniciar sesión. Sin configurar, se ve "LinkedCorp" y el logo estático de siempre — no rompe instalaciones existentes. - Solo desplegado en desarrollo por pedido explícito del usuario (no se tocó producción esta vez) — queda commiteado para poder retroceder/avanzar por git antes de decidir el despliegue.
[1.14.1] - 2026-09-15
Fixed
- El pie del menú lateral mostraba siempre el texto fijo "v0.1.0" en vez de la versión real de la
app (se lee ahora de
package.jsondel frontend).
Changed
- El logo de LinkedCorp en el menú lateral pasa de la parte superior a la parte inferior izquierda, justo encima del número de versión.
[1.14.0] - 2026-09-15
Added
- Arrastrar con el mouse para reordenar: actividades (dentro de un proyecto) y tareas (dentro de
una actividad), ambas con el mismo mecanismo — un hook reutilizable (
useDragReorder, drag & drop nativo, sin librería nueva) usado tanto enListView(opt-in víaonReorder, deshabilitado mientras haya un ordenamiento por columna activo) como en el listado de tareas. Orden persistido (sort_orderenactivities/tasks, migración012, posiciones 1..N).
[1.13.0] - 2026-09-15
Added
- Eliminar actividad:
DELETE /api/activities/:id(no existía) + botón "Eliminar" en el listado de actividades, con popup de confirmación. Si la actividad tiene tareas, se bloquea con un mensaje claro ("Esta actividad tiene N tarea(s). Elimina primero las tareas antes de borrar la actividad.") en vez de borrar en cascada silenciosamente.
Changed
- Adjuntos: la lógica de borrar archivo + fila (antes solo inline en el controller) se movió a un
nuevo
attachments/service.jsreutilizable, usado tanto por el borrado individual como por el borrado en cascada al eliminar una actividad (evita archivos huérfanos en disco).
[1.12.5] - 2026-09-14
Changed
- Listado de Proyectos: columna "Creado" reemplazada por "Actualizado" (fecha y hora), y es ahora el orden por defecto — el proyecto tocado más recientemente aparece primero.
[1.12.4] - 2026-09-14
Added
- Botón "Editar" (lápiz) en cada tarea de una actividad — el backend ya soportaba renombrar una
tarea (
PUT /api/tasks/:id), solo faltaba el botón en la UI. Edición en línea (input + guardar con Enter o el ícono, cancelar con Escape o el ícono).
[1.12.3] - 2026-09-14
Added
- Fecha del documento en la lista de Documentos (proyecto/actividad) — el dato ya lo devolvía el backend, solo faltaba mostrarlo junto a quién lo subió y el tamaño.
[1.12.2] - 2026-09-14
Fixed
- El icono nativo de calendario en campos
type="date"/time/datetime-localsalía negro sobre fondo oscuro en tema oscuro (invisible). Se agregacolor-scheme: darka esos inputs cuandodata-theme="dark", para que el navegador dibuje el icono en un tono claro.
[1.12.1] - 2026-09-11
Added
- Tareas recurrentes: campo opcional "Hasta" (fecha de fin). Vacío = se repite sin fin (como hasta ahora). Al completar un ciclo cuyo próximo vencimiento supera "Hasta", la tarea se desactiva sola — no requiere acción manual.
[1.12.0] - 2026-09-11
Added
- Tareas recurrentes: menú propio en la barra lateral, independiente de Proyectos. Cada tarea recurrente tiene periodicidad configurable (cada N días/meses/años), próximo vencimiento, responsable y proyecto de origen opcional. "Completar ciclo" avanza el próximo vencimiento sumando la periodicidad. Recordatorio por correo automático N días antes del vencimiento (configurable, default 7) a una hora del día configurable — un job en el propio proceso del backend revisa cada 15 minutos, sin infraestructura nueva.
- Desde la pestaña "Tareas" de una actividad, cada tarea puntual tiene un botón "Convertir en recurrente" que la promueve a una tarea recurrente (la tarea original no se borra).
[1.11.0] - 2026-09-11
Added
- Filtros en el listado de Proyectos: Estado, Prioridad (ambos ya soportados por el backend, solo faltaba exponerlos en la UI) y "Solo próximos a vencer" (checkbox, ventana de 7 días — misma definición que el KPI del dashboard).
[1.10.0] - 2026-09-11
Added
- Ordenar proyectos por Prioridad ahora usa la severidad real (Baja→Media→Alta→Crítica), no el orden alfabético del texto. El resto de columnas (Nombre, Estado, Creado, etc.) ya se podían ordenar con clic en el encabezado — no era nuevo, solo Prioridad tenía este detalle.
Changed
- "Páginas web y dominios" separada en dos tareas dentro de "Inventario de servicios de tecnología": "Páginas web" y "Dominios".
[1.9.3] - 2026-09-11
Added
- Nueva actividad en Infraestructura y redes: "Inventario de servicios de tecnología", con 8 tareas propuestas como checklist inicial (internet corporativo, páginas web/dominios, certificados SSL, correo/SMTP, nube, SaaS de terceros, telefonía/VoIP, respaldos).
[1.9.2] - 2026-09-11
Changed
- "Revision periodica de equipos" (Gestión de equipos y activos de TI) renombrada a "Revisión de equipos para verificar obsolescencia y mejoras" — dejaba dudas sobre qué cubría.
- Nueva actividad en Infraestructura y redes: "Reponchado de cableado de red y certificación de los puntos".
[1.9.1] - 2026-09-11
Changed
- Migración de datos de una sola vez (
006_seed_it_baseline.sql, con marcador ensystem_settings— nunca se repite en un deploy futuro): reemplaza el proyecto de prueba "Sistema ERP" por 6 proyectos reales de TI (Cumplimiento legal, Correos, Equipos, Credenciales y licencias, Infraestructura y redes, Mejoras a SAGA) con sus actividades, y da de baja la cuentapflores@hotmail.es(autorregistro nunca verificado). Pedido explícito del superadmin.
[1.9.0] - 2026-09-10
Added
- Organización → Usuarios: ahora se puede "Rechazar" (eliminar) también a un usuario en
pending_verification(autorregistro que nunca confirmó su correo) — antes esa acción solo existía parapending_approval, así que una cuenta abandonada antes de verificar el correo no tenía ninguna forma de quitarse desde la UI.
[1.8.1] - 2026-09-10
Fixed
- "Agregar dependencia" en una actividad no daba ninguna señal cuando no había otra actividad del proyecto disponible para elegir (proyecto con una sola actividad, o ya se agregaron todas) — el combo quedaba vacío, no se seleccionaba nada, y el botón hacía clic sin ningún efecto visible. Reportado como "el botón no hace nada". El mecanismo en sí funcionaba bien (verificado con curl y Playwright con 2+ actividades); ahora, cuando no hay opciones, se muestra un mensaje explicando por qué en vez del selector, y el botón queda deshabilitado si no hay nada seleccionado.
[1.8.0] - 2026-09-10
Changed
- Renombrado "Subtareas" a "Tareas" en todo el sistema (Actividad → Tarea, sin nivel "sub"
intermedio): tabla
subtasks→tasks(migración005,RENAME TABLEidempotente), módulo backendsubtasks/→tasks/, rutas/api/activities/:id/subtasks→/api/activities/:id/tasksy/api/subtasks/:id→/api/tasks/:id, servicio frontend, pestaña dentro del detalle de actividad, i18n (es-EC/en-US) y documentación (API.md,BASE_DE_DATOS.md,AGENTS.md,README.md,SPEC.md). Sin cambios de comportamiento, solo nombres.
[1.7.0] - 2026-09-10
Added
- Agregar miembro a un proyecto ahora acepta un correo que todavía no es usuario del sistema
(campo "Invitar por correo" en el popup de Miembros, alternativo a elegir uno existente). Si el
correo no pertenece a nadie, se crea una cuenta en estado
invitedy se le manda un correo con un enlace de un solo uso (/aceptar-invitacion?token=..., vence en 7 días) para que complete su propio registro (elige nombre y clave); la fila deproject_membersya queda creada de una vez, así que en cuanto acepta ya aparece como miembro sin pasos adicionales. A diferencia del autorregistro público, no pasa por aprobación de un admin — quien lo agregó a su proyecto ya lo vetó. Nuevos endpoints públicosGET /api/auth/inviteyPOST /api/auth/accept-invite.
[1.6.1] - 2026-09-09
Changed
- Nuevo ícono/logo de la app derivado del ícono original de LinkedCorp (círculo azul de marca
#1C55FFcon la red de nodos): se agregó una insignia con el acento de la app (#0078D4) para identificar visualmente el módulo de Proyectos. ActualizadoslogoLinked1.png,logoLinkedCorpTxt.pngylogoLinkedCorpTxtBlack.png(sidebar y login, temas oscuro/claro). - Favicon nuevo (
favicon.svg+favicon.png+apple-touch-icon.png); antes la app no declaraba ninguno.
[1.6.0] - 2026-09-09
Added
- Un proyecto puede tener uno o más administradores del proyecto (
role_in_project = 'admin'enproject_members), sin importar el rol global del usuario — uncollaboratorpuede ser administrador de un proyecto puntual. Se otorga/quita desde Miembros: casilla "Agregar como administrador del proyecto" al agregar, y un botón de escudo para promover/degradar a un miembro existente (protegido: nunca toca alDueño). NuevoPUT /api/projects/:id/members/:userId/role.canWriteProjectahora reconoce este rol por-proyecto además del comportamiento previo (admin/superadmin/it_manager global, o project_lead miembro).
Changed
- El menú "Configuración" (apariencia, catálogos, SMTP) ahora es visible y accesible solo para
el superadmin — antes cualquier usuario logueado lo veía y podía entrar (el tema/idioma
personal sigue disponible para todos desde los íconos de la barra superior, eso no cambió). Se
guarda tanto en el menú lateral como en la ruta directa
/configuracion. - Escritura de catálogos (
/api/catalogs/*, usado por la pantalla de Configuración) restringida de[superadmin, admin]a solosuperadmin, para que el backend sea consistente con queadminya no ve ni puede entrar a esa pantalla — la lectura sigue abierta a cualquier usuario (los combos de prioridad/estado en el resto de la app la necesitan).
[1.5.0] - 2026-09-09
Added
- Eliminar proyecto: eliminación lógica (
deleted_at/deleted_by) disponible para quien puede editar el proyecto (superadmin/admin/it_manager/project_lead dueño o miembro), con popup de confirmación (ContentDialog) antes de aplicarla. El proyecto desaparece del listado y del dashboard, pero sigue en la base de datos. - Papelera de proyectos, visible solo para el superadmin (botón "Papelera" en Proyectos):
lista los proyectos eliminados lógicamente, con acciones "Restaurar" y "Eliminar
definitivamente" (esta última con su propia confirmación, más severa — advierte que también
borra actividades/comentarios/adjuntos). El borrado físico (
DELETE) solo puede aplicarse sobre un proyecto que ya pasó por la eliminación lógica (nunca en un solo paso). - Columna "Creado" (fecha) en el listado de proyectos, ordenada por defecto de más nuevo a más
antiguo — un proyecto recién creado aparece primero sin tener que buscarlo.
ListViewahora soporta un orden inicial (initialSort) además del ordenamiento por clic en cabecera que ya tenía.
Fixed
- Los KPIs del dashboard (proyectos activos/atrasados/por vencer, avance promedio, actividades pendientes/atrasadas/de hoy, proyectos por estado) ahora excluyen proyectos eliminados lógicamente — antes de este cambio no existía el concepto, así que no aplica como regresión, pero se dejó explícito para que un futuro cambio no los vuelva a incluir por accidente.
[1.4.0] - 2026-09-09
Added
- Boton de revelar/ocultar clave (icono de ojo) en todos los campos de contraseña de la app:
login, registro, restablecer clave, cambiar clave (usuario logueado), crear usuario y la clave
SMTP en Configuración. Nuevo componente reutilizable
PasswordInput.
Fixed
- El fix de espacios en SMTP del v1.3.0 usaba
trim(), que solo recorta los bordes. El caso real en producción tenía el espacio a mitad del host ("mail.linkedcorp." + " " + "net"), asi que seguia fallando tras el primer fix. Corregido para quitar cualquier espacio, no solo los bordes.
[1.3.0] - 2026-09-06
Added
- Configuración → Correo (SMTP): botón "Enviar prueba" con campo de destinatario. Ejecuta un envío
real (
POST /api/settings/smtp/test, solo superadmin, rate-limited) usando los valores actuales del formulario (aunque no se hayan guardado) y muestra el resultado real — éxito o el error tal cual lo devuelve el servidor SMTP — a diferencia desendMail()(correo de negocio), que nunca lanza para no romper flujos comoforgot-password.
Fixed
- La pantalla de SMTP no tenía forma de verificar que la configuración guardada funcionara de
verdad; un error de host/certificado/credenciales solo se detectaba cuando fallaba un correo real
de negocio, sin ningún diagnóstico. Regla agregada a
SEGURIDAD-Y-CALIDAD.mddel orquestador: toda config de servicio externo debe incluir una acción de prueba real.
[1.2.0] - 2026-09-06
Added
- Cambiar clave desde la app:
PUT /api/auth/change-password(exige la clave actual) + opción "Cambiar clave" en el menú de usuario (popup), disponible para cualquier usuario logueado.
[1.1.0] - 2026-09-06
Added
- Autorregistro público (
/registro) con verificación de correo (enlace de un solo uso, 24h) y aprobación posterior por Administrador/Superadministrador (/api/users/:id/approve|reject). - Recuperación de clave (
/olvide-clave→/restablecer-clave), respuesta siempre genérica. - Rol
superadmin: el usuario más antiguo del sistema (bootstrap automático al primer registro). - Configuración → Correo (SMTP), solo visible/editable por el superadmin; clave cifrada
(AES-256-GCM) en
system_settings, nunca expuesta por la API. Sin configurar, los correos de verificación/recuperación se loguean en vez de enviarse (modo dev, no rompe el flujo).
Fixed
- Bug real:
React.StrictModedisparaba dos veces el efecto deVerifyEmailPage, y la segunda llamada (token ya consumido) mostraba "enlace inválido" aunque la verificación sí había funcionado. Corregido con una guarda por token ya solicitado. - Reordenado el montaje de rutas del backend:
subtasksRoutes(mount genérico en/api) queda al final, para no interceptar con surequireAuthinterno una request sin token dirigida a un router más específico registrado después (ver deuda técnica de la v1.0.0).
[1.0.0] - 2026-09-06
Added
- Primer despliegue a producción:
https://project.linkedcorp.net(arquetipo B, dos servicios). create-admin.js: bootstrap del usuario Administrador de producción con clave fuerte generada.
Changed
seed-db.jssepara catálogos (universal) de datos de ejemplo (solo entornos no productivos).- Logo real de LinkedCorp (sidebar, login) en vez del placeholder "LC"; tamaño duplicado.
ComboBox/Flyoutse posicionan con portal adocument.body(ya no se recortan dentro de unExpanderoDetailPopup).- Master-detail de listados unificado en
DetailPopup(popup de tamaño fijo, no se cierra con clic afuera) en Proyectos, Actividades, Departamentos, Usuarios, Miembros y Catálogos. - "Miembros" del proyecto pasa a ser su propia pestaña (antes vivía dentro de "Info").
[0.1.0] - 2026-09-03
Added
- Estructura inicial del proyecto (backend Express + frontend React/Vite + MariaDB).
- Modelo de datos MVP: usuarios/roles, departamentos, proyectos, actividades, subtareas, dependencias, comentarios, adjuntos, notificaciones, auditoría, catálogos.
- Identidad UI/UX Fluent/Windows 11 (UI-UX-WINDOWS) adaptada a app web.