- DELETE /api/projects/🆔 eliminacion logica (deleted_at/deleted_by), mismo
permiso que editar el proyecto. Popup de confirmacion antes de aplicarla.
- Papelera (GET /api/projects?trash=true, POST /:id/restore, DELETE
/:id/permanent) restringida al superadmin; el borrado fisico exige que el
proyecto ya este en la papelera y arrastra actividades/comentarios/adjuntos
por ON DELETE CASCADE.
- Dashboard (KPIs, actividades pendientes/calendario, proyectos por estado)
excluye proyectos eliminados logicamente.
- Columna "Creado" en el listado de proyectos, ordenado por defecto de mas
nuevo a mas antiguo (ListView admite initialSort ademas del orden por clic
en cabecera que ya tenia).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Componente reutilizable PasswordInput (icono de ojo) usado en login, registro,
restablecer clave, cambiar clave, crear usuario y la clave SMTP de
Configuracion, para que el usuario pueda verificar que la esta escribiendo
correctamente.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Agrega POST /api/settings/smtp/test (superadmin, rate-limited) que envia un
correo real usando los valores actuales del formulario y propaga el error
real del servidor SMTP, a diferencia de sendMail() que nunca lanza. El panel
de SMTP ahora tiene un campo de destinatario y boton "Enviar prueba" con el
resultado real (exito o error), en vez de solo "Guardar" sin forma de
verificar que la configuracion funcione.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- POST /api/auth/register: primer usuario del sistema -> superadmin con sesion
directa (bootstrap, sin correo ni aprobacion); los siguientes quedan
pending_verification y reciben un correo con enlace de un solo uso (24h).
- GET /api/auth/verify-email: pasa a pending_approval y notifica in-app a los
admin/superadmin activos.
- admin/superadmin aprueban (POST /api/users/:id/approve, eligen rol y
departamento) o rechazan (POST /api/users/:id/reject, borra y audita el
email) desde Organizacion -> Usuarios (nuevo badge de estado + acciones).
- login() da mensaje especifico segun el status de la cuenta en vez del
generico "credenciales invalidas".
- Recuperacion de clave (forgot/reset-password): respuesta siempre generica,
token de 1 hora de un solo uso.
- Nuevo modulo settings: SMTP configurable SOLO por superadmin desde
Configuracion -> Correo (SMTP); clave cifrada AES-256-GCM (ENCRYPTION_KEY)
en la tabla system_settings, nunca expuesta por la API. sendMail() degrada
a modo dev (loguea en vez de enviar) si no hay SMTP configurado, y nunca
deja que un fallo de envio tumbe al que lo llama.
- Migracion 002_registration_and_smtp.sql: rol superadmin, columnas de ciclo
de vida en users (status, tokens), tabla system_settings, y promueve al
usuario mas antiguo del sistema a superadmin.
- Fix: React.StrictMode disparaba el efecto de VerifyEmailPage dos veces; la
segunda llamada (token ya consumido) mostraba "enlace invalido" pese a que
la verificacion ya habia funcionado. Se agrega una guarda por token.
- Fix (deuda tecnica v1.0.0): se reordena el montaje de rutas en app.js —
subtasksRoutes (mount generico en /api) va al final, para no interceptar
con su requireAuth interno una request sin token dirigida a un router mas
especifico registrado despues.
- Documentacion actualizada: AGENTS.md, SPEC.md, API.md, BASE_DE_DATOS.md,
CONFIGURACION.md, ESTADO.md, CHANGELOG.md. Version 1.1.0.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reemplaza el cuadro "LC" del NavigationView y del login por los logos
oficiales de /desarrollo/imgLinkedCorp: logoLinkedCorpTxtBlack (tema claro,
texto negro) y logoLinkedCorpTxt (tema oscuro, texto blanco), elegido segun
el tema activo. En modo compacto del sidebar (sin espacio para el texto) se
usa el isotipo redondo (logoLinked1) en vez del logo con texto.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Antes la lista de miembros del proyecto vivia dentro de la pestaña Info,
mezclada con los campos del proyecto. Se extrae a un componente propio
(ProjectMembersTab) y se agrega como pestaña "Miembros" justo a la derecha
de "Info" en el detalle del proyecto.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Auditoria completa del frontend: quedaban 2 lugares con el mismo antipatron que
ya se habia corregido en Proyectos/Departamentos/Usuarios/Catalogos.
- ProjectActivitiesTab: "Nueva actividad" se apilaba debajo del listado de
actividades. Ahora abre en su propio DetailPopup, igual que el resto.
- ProjectInfoTab (pestaña Info de un proyecto): el combo "agregar miembro" se
apilaba debajo de la lista de miembros. Ahora hay un boton "Agregar miembro"
en el encabezado de esa tarjeta que abre un DetailPopup chico.
Con esto no queda ningun listado del sistema con un formulario apilado debajo:
todos usan DetailPopup (ver regla en project-md-templates/UI-UX-WINDOWS.md).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Las 11 pantallas con listado/detalle bloqueaban TODO su render con
"if (loading || !data) return <Cargando/>". Como useAsync pone loading=true en
cada reload (no solo en la carga inicial), cualquier accion dentro de un
DetailPopup abierto que dispara un reload del padre (agregar subtarea, agregar
dependencia, guardar comentario, etc.) desmontaba momentaneamente TODA la
pantalla -y con ella el popup y su estado interno (pestaña activa)-, que volvia
a montarse desde cero con sus valores iniciales.
Sintoma reportado: al agregar una subtarea (Enter o boton "Nuevo"), el popup de
la actividad volvia a la pestaña Info en vez de quedarse en Subtareas.
Fix: la guarda ahora es solo "if (!data)" -bloquea unicamente la carga
inicial, cuando todavia no hay nada que mostrar-. Las recargas subsiguientes
actualizan el contenido en el sitio sin desmontar nada.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
El detalle de un item de listado (actividad, departamento, usuario, proyecto nuevo,
catalogo) ya no se apila debajo ni al costado del listado: ahora abre en un popup que
cubre la ventana, deja el listado inactivo detras, nunca se cierra con clic afuera (solo
con el boton Cerrar o una accion explicita del formulario) y mantiene un alto FIJO por
instancia para que cambiar de pestaña interna (Info/Subtareas/Dependencias/Comentarios/
Documentos) no reajuste su tamaño.
De paso corrige un bug real de stacking: ContentDialog no usaba portal a document.body,
así que un dialogo de confirmacion abierto desde dentro de un DetailPopup quedaba oculto
detras de este. Ahora ambos son portales con una jerarquia de z-index explicita
(Flyout 100 < DetailPopup 200 < ContentDialog 250 < Toast 300).
En el detalle de actividad, Subtareas y Dependencias pasan de estar apiladas dentro de la
pestaña Info a ser cada una su propia pestaña.
Regla documentada en project-md-templates/UI-UX-WINDOWS.md (componente DetailPopup) para
que aplique a futuros proyectos de escritorio Windows del grupo.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>