# ESTADO — project.linkedcorp.net Ultima actualizacion: 2026-10-23 (v3.0.1 en desarrollo, sin desplegar) Fase actual: **En produccion** (`https://project.linkedcorp.net`, v1.1.0). MVP fase 1 operativo + autorregistro/aprobacion/SMTP. ## Auditoría de seguridad y calidad (v3.0.0, sin desplegar) - Se corrigieron controles de roles, alcance de búsqueda y tareas recurrentes, bootstrap concurrente, subida de logo/adjuntos, censura de tokens en logs de la app, revocación JWT, límites de ingesta, correo, paginación y accesibilidad base. - Migraciones nuevas `028_session_version.sql` y `029_optimistic_versions.sql`: **no aplicadas**. El backend nuevo requiere ambas antes de arrancar con una base existente. Tras `028`, los JWT anteriores dejan de funcionar y se debe iniciar sesión otra vez. - `GET /api/projects` ahora devuelve `{items,total,page,pageSize}`. El frontend de esta versión se adaptó; otros clientes deben hacerlo. `POST /api/attachments` requiere entidad en query. - Pendiente: vinculación token de inventario a equipo (instaladores actuales comparten token), medición SQL `EXPLAIN` con datos reales. Hallazgo 7: falta verificar los logs del proxy NPM para confirmar la censura de tokens; pendiente operativo, sin tocar NPM. Hallazgo 11: vincular token de inventario a equipo requiere migrar las instalaciones que comparten token; pendiente operativo. No se consultó la BD ni producción durante esta tarea. - Hallazgo 16 completo en código: edición con versión optimista para proyectos, comentarios, actividades, tareas, departamentos, usuarios, los cuatro catálogos, notas, tareas recurrentes, equipos, empresa y SMTP. La migración 029 se amplió; sigue **sin aplicar**. ## Como retomar Actualizador v3.0.1: el script publica `logs/update.status`; el panel espera su fin y comprueba las versiones activas de backend y `version.json` del frontend antes de activar el Service Worker y recargar. Pendiente verificar el flujo completo en un despliegue autorizado; no se tocó producción. 1. Leer primero el orquestador: `/home/mgonzalez/desarrollo/project-md-templates/leeme_primero.txt`. 2. Leer `AGENTS.md`, `SPEC.md`, `PRODUCCION.md` y este archivo. 3. Backend dev: `cd backend && npm install && npm run dev` (puerto 4019). Requiere `backend/.env` (no versionado — completar con las credenciales de la BD dev `project_linkedcorp` en `192.168.222.20`; la clave la tiene el usuario). 4. Frontend dev: `cd frontend && npm install && npm run dev` (puerto 5196, proxy `/api` al backend). 5. Login dev: `mgonzalez@linkedcorp.net` / clave `mgonzalez` (rol Administrador). Login de **producción**: mismo email, clave fuerte generada por `create-admin.js` (no está en este repo, se entregó al usuario al desplegar). 6. Produccion: ver `PRODUCCION.md` y `DEPLOY_WEB.md` para topología, comandos y el flujo de deploy de actualizaciones (arquetipo B, dos servicios systemd en `192.168.222.3`). ## Hecho y verificado ### Menú Equipos (v2.15.0, 2026-10-19) — EN DESARROLLO, NO DESPLEGADO - Inventario de TI con agente GLPI oficial; diseño traído de linkedtrack (que sigue aparte, sin tocar): `docs/ARQUITECTURA-INVENTARIO.md`. Backend `modules/devices/` (ingest, normalizer, repository, service, routes), migración `023` aplicada en dev, frontend `pages/Equipos/`. - Verificado con inventarios sintéticos JSON y XML (alta, actualización, diff, 401 sin token, handshake `contact`). **Pendiente: probar con un agente GLPI real** (ver "Pendientes" del doc de arquitectura) y ajustar `normalizer.js`/handshake según el JSON real. - Antes de producción: migración 023 en `.32`, `npm install` (fast-xml-parser), confirmar que NPM deja pasar `POST /api/inventory` desde la red de los equipos y subir versión/deploy. ### Fase 1 — MVP en desarrollo (2026-09-03) - Backend completo: auth (JWT + rate limit), users, departments, catalogs, projects (+members), activities (+dependencies), subtasks, comments, attachments, notifications, dashboard, audit. Recalculo automatico de `progress_pct` verificado. - Frontend completo: identidad Fluent/Windows adaptada a web — NavigationView, ContentDialog, InfoBar, Toast, Flyout, ListView, ComboBox, Treeview, Tabs, Expander. Paginas: Login, Dashboard, Proyectos (listado + detalle), Organizacion, Configuracion. i18n es-EC/en-US, tema claro/oscuro. - Verificacion end-to-end con Playwright sin errores de consola. ### Iteraciones de UI/UX (2026-09-03 al 2026-09-05) - `DetailPopup`: reemplaza el antipatron "formulario apilado debajo/al costado del listado" en TODOS los listados de gestion (Proyectos, Actividades, Departamentos, Usuarios, Miembros, Catalogos) — popup de tamaño fijo por instancia, listado inactivo detras, nunca se cierra con clic afuera. Regla documentada en `project-md-templates/UI-UX-WINDOWS.md`. - Bug de stacking corregido: `ContentDialog` ahora usa portal a `document.body` (antes quedaba tapado detras de un `DetailPopup` abierto). Jerarquia de z-index: Flyout(100) < DetailPopup(200) < ContentDialog(250) < Toast(300). - Bug de remount corregido: las guardas `if (loading || !data) return ` desmontaban TODA la pantalla (y el popup abierto dentro) en cada recarga en segundo plano. Cambiadas a `if (!data)` — solo bloquean la carga inicial. - Bug de clipping corregido: `ComboBox` (y `Flyout`) se posicionan con portal + `position:fixed` calculado desde el trigger — antes un ancestro con `overflow:hidden` (Expander, DetailPopup) los recortaba. Regla documentada en `UI-UX-WINDOWS.md`. - "Miembros" del proyecto es su propia pestaña (antes vivia dentro de "Info"). - Logo real de LinkedCorp (`/desarrollo/imgLinkedCorp/logoLinkedCorpTxt(Black).png`) en sidebar y login, theme-aware, tamaño duplicado respecto a la primera version. ### Deploy a produccion (2026-09-06) - BD `project_linkedcorp` creada en `192.168.222.32` (prod) con `crear-db-prod.sh`. - Servidor `192.168.222.3`: `/opt/apps/project.linkedcorp.net/{source,backend,frontend,storage,logs}`. - Migraciones aplicadas; catalogos sembrados (`seed-db.js`, sin datos de ejemplo en produccion — ver decision abajo); usuario Administrador inicial creado con `create-admin.js`. - Servicios systemd `project-linkedcorp-backend` (4019) y `project-linkedcorp-frontend` (5196, `serve -s dist`), ambos `enabled` + `active`. - NPM: Proxy Host id 77 → frontend, Custom Location `/api` → backend, SSL Let's Encrypt forzado. - Verificado end-to-end via curl contra `https://project.linkedcorp.net`: health check, login, token valido. Detalle completo en `PRODUCCION.md`. - **Pendiente no bloqueante**: limpiar `.md` de `/opt/apps/project.linkedcorp.net/source` (paso de higiene de `DEPLOY_WEB.md`) — bloqueado por el clasificador de auto-mode del agente durante el deploy; requiere ejecutarlo a mano o con autorizacion explicita la proxima vez. ### Autorregistro, aprobación, superadmin y SMTP (2026-09-06) - Migración `002_registration_and_smtp.sql`: rol `superadmin`, columnas de ciclo de vida en `users` (`status`, tokens de verificación/recuperación), tabla `system_settings`. El usuario más antiguo (id=1, creado por `create-admin.js` antes de este feature) se promovió solo a `superadmin`. - `POST /api/auth/register`: primer usuario del sistema → `superadmin` con sesión directa (bootstrap); los siguientes → `pending_verification`, correo con enlace de un solo uso (24h). - `GET /api/auth/verify-email` → `pending_approval` + notificación in-app a `admin`/`superadmin`. - `admin`/`superadmin` aprueban (`POST /api/users/:id/approve`, eligen rol/departamento) o rechazan (`POST /api/users/:id/reject`, borra y audita el email) desde Organización → Usuarios (nuevo badge de estado + acciones de fila). - `login()` da mensaje específico según `status` (pendiente de verificar / pendiente de aprobar) en vez del genérico "credenciales inválidas". - Recuperación de clave (`/olvide-clave` → `/restablecer-clave`): respuesta siempre genérica, token de 1 hora de un solo uso. - SMTP configurable desde Configuración → Correo (SMTP), **solo superadmin** (oculto para el resto); clave cifrada AES-256-GCM (`ENCRYPTION_KEY`) en `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 envío tumbe al que lo llama (crítico para `forgot-password`, que debe responder genérico siempre). - Bug real corregido: `React.StrictMode` disparaba el efecto de `VerifyEmailPage` dos veces; la segunda llamada (token ya consumido) mostraba "enlace inválido" pese a que la verificación había funcionado. Se agregó una guarda por token ya solicitado. - Deuda técnica de la v1.0.0 resuelta de paso: se reordenó el montaje de rutas en `app.js` — `subtasksRoutes` (mount genérico en `/api`) ahora va al final, así ya no intercepta con su `requireAuth` interno una request sin token dirigida a un router más específico (`/api/settings`, etc.) registrado después. - Verificado end-to-end en dev con Playwright: registro → correo logueado (modo dev) → login rechazado (pendiente de verificar) → verificar correo → login rechazado (pendiente de aprobar) → aprobar desde Usuarios → login exitoso → recuperar clave → login con clave nueva → panel SMTP visible solo para superadmin. Sin errores de consola. - **Desplegado a producción el mismo día**: migración `002` aplicada sobre `.32`, ambos servicios reconstruidos y reiniciados (PID confirmado), verificado via curl contra `https://project.linkedcorp.net` (login reporta `superadmin`, `GET /api/settings/smtp` responde `configured:false`). Detalle en `PRODUCCION.md` → "Actualización v1.1.0". - **Pendiente real**: el superadmin de producción debe cargar el SMTP real desde Configuración → Correo (SMTP) — sin eso, nadie externo puede completar el autorregistro en producción (el enlace de verificación solo queda logueado en el servidor, no llega por correo de verdad). ### Cambiar clave desde la app (v1.2.0, 2026-09-06) - `PUT /api/auth/change-password` (exige la clave actual, valida clave nueva ≥ 8 caracteres) + opción "Cambiar clave" en el menú de usuario (popup), para cualquier usuario logueado — independiente de "olvidé mi clave", que es para cuando no se puede iniciar sesión. - Desplegado a producción el mismo día; verificado via curl que rechaza clave actual incorrecta con 400 (no se tocó la clave real del superadmin durante la prueba). ### Boton de prueba real en Correo (SMTP) (v1.3.0, 2026-09-06) - El usuario reportó, con razón, que la pantalla de SMTP no tenía forma de confirmar que la configuración guardada funcionara de verdad (sin botón de prueba ni campo de destinatario) — una omisión básica para una pantalla de config de un servicio externo. - `POST /api/settings/smtp/test` (superadmin, rate-limited a 10/15min): usa los valores actuales del formulario (aunque no se hayan guardado, cae a la clave ya guardada si el campo viene vacío) y hace un envío real. A diferencia de `sendMail()` (correo de negocio, nunca lanza), este endpoint sí propaga el error real del servidor SMTP — es diagnóstico explícito del superadmin. - Panel de Configuración → Correo (SMTP): nueva sección "Probar configuración" con campo de destinatario, botón "Enviar prueba" y resultado real (éxito o el mensaje de error tal cual). - Verificado en dev con curl (400 sin host/usuario) y Playwright (formulario + envío real contra el SMTP interno con credenciales falsas → error real "certificate has expired" mostrado en la UI). Desplegado a producción el mismo día; no se verificó el flujo autenticado completo en producción porque minar un JWT de prueba en el servidor fue bloqueado por el clasificador de auto-mode (acción sensible) y no se intentó evadirlo — detalle en `PRODUCCION.md`. - Regla nueva agregada al orquestador (`project-md-templates/SEGURIDAD-Y-CALIDAD.md`, sección 1.6bis + checklist): toda pantalla de configuración de un servicio externo debe incluir un botón de prueba real, para que esta clase de omisión no se repita en este ni otros proyectos. ## Pendiente (fase 2, sin comprometer lo ya construido) - Riesgos e Incidencias como modulos propios (hoy: `risk_level` simple en el proyecto). - Solicitudes/requerimientos formales de otras areas. - Recursos (servidores/licencias/software), Proveedores, Presupuesto y costos. - Registro de horas trabajadas detallado (bitacora diaria). - Reportes exportables (PDF/Excel/CSV) y vista ejecutiva separada. - Permisos por accion dentro de cada modulo (hoy: acceso por modulo y usuario desde v3.1.0 + roles fijos codificados). - Integracion IA (API Claude) — ideas: plan de proyecto generado desde una descripcion, resumen semanal del Panel. Clave cifrada en `system_settings` como el SMTP; la IA solo sugiere. - Panel: con el modulo Proyectos deshabilitado, los KPIs del Panel siguen mostrando datos de proyectos del usuario (revisar si se deben ocultar). - Notificaciones por email/WhatsApp (hoy: solo in-app). - Job programado para detectar actividades vencidas/por vencer (hoy: solo se notifica al asignar). - DatePicker: sigue usando `` nativo (simplificacion deliberada del MVP). - En producción, crear los departamentos/usuarios reales de la empresa desde la UI (arranca limpia a proposito, ver decision abajo). ## Decisiones clave - MVP simplificado respecto al listado original de 30 areas — detalle en `SPEC.md`. - Identidad UI/UX: `UI-UX-WINDOWS.md` (Fluent/Windows 11), no la identidad web estandar del grupo. - Empresa unica (single-company): no existe tabla `companies`. - Arquetipo de despliegue B (dos servicios separados). - Produccion arranca sin datos de ejemplo: `seed-db.js` solo carga catalogos universales (roles/prioridades/estados/tipos) cuando `NODE_ENV=production`; los departamentos y usuarios de ejemplo (TI/Finanzas/RRHH/Comercial, admin con clave=usuario) son SOLO de dev. El admin real de produccion se crea con `create-admin.js` (clave fuerte generada, nunca clave=usuario). - Autorregistro con doble candado (correo + aprobacion admin) — decision explicita del usuario, revierte la regla inicial "sin autosuscripcion". El primer usuario del sistema es `superadmin` automatico; el resto pasa por verificacion + aprobacion. SMTP vive en BD (cifrado), configurable solo por el superadmin desde la UI, no en `.env`. ## Deuda tecnica - `npm audit`: 3 vulnerabilidades moderadas en `qs`/`body-parser`, transitivas de Express 4.x (sin fix no-breaking disponible al 2026-09-06). No critico; revisar cuando Express publique el fix.