Files
project.linkedcorp.net/ESTADO.md
T
Milton Gonzalez e25c2c3b35 feat: version 2.15.0 -- menu Equipos (inventario de TI con agente GLPI)
Ingesta POST /api/inventory (JSON/XML, token de instalacion), upsert por deviceid,
historial de cambios, pestañas Resumen/Equipos/Software/Agentes, detalle con buscador
por pestaña y casilla para ocultar actualizaciones/drivers/componentes del software.
Migraciones 023 y 024. Diseño en docs/ARQUITECTURA-INVENTARIO.md.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-19 19:05:00 -05:00

178 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ESTADO — project.linkedcorp.net
Ultima actualizacion: 2026-10-19 (v2.15.0 en desarrollo, sin desplegar)
Fase actual: **En produccion** (`https://project.linkedcorp.net`, v1.1.0). MVP fase 1 operativo +
autorregistro/aprobacion/SMTP.
## Como retomar
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 <Cargando/>` 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 configurables por modulo × accion desde la UI (hoy: roles fijos codificados).
- 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 `<input type="date">` 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.