Menu propio en la barra lateral, independiente de Proyectos:
- Periodicidad configurable (cada N dias/meses/años), proximo
vencimiento, responsable, proyecto de origen opcional.
- "Completar ciclo" avanza el proximo vencimiento sumando la
periodicidad y limpia el recordatorio ya enviado.
- Recordatorio por correo automatico N dias antes del vencimiento
(default 7), a una hora del dia configurable. Un job en el propio
proceso del backend (setInterval cada 15 min) revisa y envia, sin
infraestructura nueva (cron del SO, cola, etc).
- Desde la pestaña Tareas de una actividad, cada tarea tiene un boton
"Convertir en recurrente" que la promueve (la tarea original no se
borra).
Probado en dev con curl (crear, completar ciclo avanza next_due_date,
promover desde una tarea real, disparo real del job de recordatorios
verificado forzando fecha/hora, segunda corrida no reenvia) y Playwright
(listado, popup de creacion, popup de promocion anidado sobre el detalle
de actividad) sin errores de consola.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Al agregar un miembro, el popup ahora permite elegir un usuario existente
o escribir un correo nuevo. Si ese correo no pertenece a nadie, se crea
una cuenta en estado 'invited' (nombre/clave placeholder) y se le manda
un correo con un enlace de un solo uso para que complete su registro
(elige su nombre y clave). La fila de project_members se crea de una vez
al invitar, asi que en cuanto acepta ya es miembro sin pasos adicionales.
A diferencia del autorregistro publico, no pasa por aprobacion de un
admin -- quien lo agrego a su proyecto ya lo vetó.
Nuevos endpoints publicos GET /api/auth/invite y POST /api/auth/accept-invite.
Nueva pagina AcceptInvitePage (/aceptar-invitacion). Migracion 004 agrega
el status 'invited' al enum de users.
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>
Nuevo PUT /api/auth/change-password: exige la clave actual (a diferencia de
reset-password, que usa un token de correo sin sesion). Opcion "Cambiar clave"
agregada al menu de usuario (popup), disponible para cualquier rol.
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>