name: proyecto_module description: Referencia completa del módulo de Proyectos en v2sistema (Backend, Frontend, Móvil). Incluye SPs, servicios, controllers, componentes y mapeos de campos críticos.
Módulo de Proyectos - Referencia Completa
Arquitectura General
v2sistema/
├── v2backend/ → NestJS (API REST)
├── v2frontend/ → React + Vite (SPA)
└── v2flutter_movil/ → Flutter (App Móvil)
⚠️ MAPEO CRÍTICO DE CAMPOS
porcentaje ↔ progreso
- En SQL Server (p_Tareas): el campo se llama
porcentaje(INT). - En los SPs de listado (
sp_Proyectos_Listar,sp_Proyecto_ObtenerVisibles,sp_ObtenerProyectos): devuelven el nombre de columnaporcentaje. - En el Frontend (React): el tipo
Proyectotieneprogreso?: number. - Normalización (React): Los métodos
getProyectosygetProyectoenclarity.service.tsmapean automáticamenteporcentajeaprogresosi este último viene como undefined. - Normalización (Flutter): Se utiliza
p['avance'] ?? p['progreso'] ?? p['porcentaje'] ?? 0en las vistas de proyectos. - RIESGO: Si un SP devuelve
porcentajey el código lo lee comoprogresosin normalización, el valor será 0 → error de cálculo de atraso.
Fallback recomendado (defensivo): (p as any).progreso ?? (p as any).porcentaje ?? 0
Backend (v2backend)
Stored Procedures de Proyectos
| SP | Uso | Ubicación del Script |
|---|---|---|
sp_Proyectos_Listar |
Admin: listar con filtros y paginación | src/db/scripts/v3_fix_project_progress.sql |
sp_ObtenerProyectos |
Usuario: ver mis proyectos | src/db/scripts/v3_fix_project_progress.sql |
sp_Proyecto_ObtenerVisibles |
Jerarquía: ver proyectos del equipo (TVP) | src/db/scripts/v3_fix_project_progress.sql |
sp_Proyectos_Gestion |
CRUD: Crear/Actualizar/Eliminar/Restaurar | database/migrations/012_sp_proyectos_gestion.sql |
sp_Proyecto_Eliminar |
Eliminar proyecto | src/db/scripts/sp_Proyecto_Eliminar.sql |
sp_Tareas_ObtenerPorProyecto |
Tareas del proyecto (para Plan de Trabajo) | migrations/2026-02-24-fix-project-progress.sql |
Cálculo de Progreso en SPs
porcentaje = ISNULL((
SELECT ROUND(AVG(CAST(
CASE WHEN t.estado = 'Hecha' THEN 100
ELSE ISNULL(t.porcentaje, 0) END AS FLOAT)), 0)
FROM p_Tareas t
WHERE t.idProyecto = p.idProyecto
AND t.idTareaPadre IS NULL -- Solo tareas raíz (nivel 0)
AND t.activo = 1
AND t.estado NOT IN ('Descartada', 'Eliminada', 'Anulada', 'Cancelada')
), 0)
Reglas:
- Solo tareas raíz (
idTareaPadre IS NULL) - Excluye descartadas/eliminadas/anuladas/canceladas
- Si estado es 'Hecha' → fuerza 100 (aunque porcentaje sea 0)
Controllers (NestJS)
ClarityController (src/clarity/clarity.controller.ts):
GET /proyectos→tasksService.proyectoListar(userId, filter)POST /proyectos→tasksService.proyectoCrear(dto, userId)GET /proyectos/:id→tasksService.proyectoObtener(id, userId)PATCH /proyectos/:id→tasksService.proyectoActualizar(id, dto, userId)DELETE /proyectos/:id→tasksService.proyectoEliminar(id, userId)POST /proyectos/:id/clonar→tasksService.proyectoClonar(id, nombre, userId)GET /proyectos/:id/tareas→tasksService.tareasDeProyecto(id, userId)GET /proyectos/:id/historial→auditService.getHistorialProyecto(id, page, limit)
ColaboradoresController (src/colaboradores/colaboradores.controller.ts):
@Controller('proyectos')→ Manejo de colaboradores del proyecto
Services
TasksService (src/clarity/tasks.service.ts):
proyectoListar()→ Si Admin:obtenerTodosProyectos(), sino:obtenerProyectosVisibles()proyectoCrear()→planningRepo.crearProyecto()+obtenerProyectoPorId()proyectoClonar()→ Clona proyecto + sus tareas (sin asignados, estados reset)proyectoObtener()→ Verifica acceso (Admin/Creador/Responsable/Jerarquía)proyectoActualizar()→ Verifica permisos +actualizarDatosProyecto()+ auditoríatareasDeProyecto()→obtenerTareasPorProyecto()+ merge con pending requests
Repos
planning.repo.ts:
obtenerProyectosPorUsuario(carnet)→sp_ObtenerProyectosobtenerTodosProyectos(filter)→sp_Proyectos_Listar(page=1, pageSize=2000)obtenerProyectosVisibles(idUsuario, usuario, filter)→sp_Proyecto_ObtenerVisibles(usa TVP)obtenerProyectoPorId(id)→ Query inline con cálculo de progreso (aliasprogreso)crearProyecto(dto)→sp_Proyectos_Gestion CREARactualizarDatosProyecto(id, updates)→sp_Proyectos_Gestion ACTUALIZAR(JSON dinámico)eliminarProyecto(id)→sp_Proyectos_Gestion ELIMINAR
Tabla Principal
p_Proyectos (
idProyecto INT PK,
nombre NVARCHAR(100),
descripcion NVARCHAR(MAX),
estado NVARCHAR(50), -- Activo, Confirmado, Borrador, Cancelado, etc.
prioridad NVARCHAR(50),
fechaInicio DATETIME,
fechaFin DATETIME,
fechaCreacion DATETIME,
area NVARCHAR(100),
gerencia NVARCHAR(100),
subgerencia NVARCHAR(100),
idCreador INT FK,
creadorCarnet NVARCHAR(50),
responsableCarnet NVARCHAR(50),
tipo NVARCHAR(50), -- administrativo, Estratégico, AMX, CENAM
idNodoDuenio INT,
requiereAprobacion BIT,
enllavado BIT
)
Frontend (v2frontend)
Páginas
| Archivo | Ruta | Descripción |
|---|---|---|
ProyectosPage.tsx |
/app/planning/proyectos |
Lista de proyectos con filtros, paginación, CRUD |
GestionProyecto2.tsx |
/app/planning/gestion-proyecto |
Vista de gestión detallada |
PlanTrabajoPage.tsx |
/app/planning/plan-trabajo |
Plan de trabajo por proyecto |
ProjectHistoryPage.tsx |
/app/planning/proyecto-historial |
Historial/timeline del proyecto |
ProjectSimulationPage.tsx |
/app/planning/simulacion |
Simulación de escenarios |
RoadmapPage.tsx |
/app/planning/roadmap |
Vista roadmap multi-proyecto |
TimelinePage.tsx |
/app/planning/timeline |
Vista timeline (Gantt) |
WorkloadPage.tsx |
/app/planning/workload |
Carga laboral del equipo |
TeamPlanningPage.tsx |
/app/planning/team |
Planificación de equipo |
Componentes
| Archivo | Descripción |
|---|---|
components/proyectos/GestionColaboradoresModal.tsx |
Modal para gestionar colaboradores del proyecto |
Servicio API
clarity.service.ts:
getProyectos(filters?) → GET /proyectos → { items: Proyecto[], total, page, lastPage }
getProyectosTareas(id) → GET /proyectos/:id/tareas → Tarea[]
postProyecto(nombre, ...) → POST /proyectos
updateProyecto(id, data) → PATCH /proyectos/:id
deleteProyecto(id) → DELETE /proyectos/:id
Tipo TypeScript
interface Proyecto {
idProyecto: number;
nombre: string;
descripcion?: string;
estado: string; // 'Borrador' | 'Confirmado' | 'EnEjecucion' | 'Cerrado' | 'Activo'
fechaInicio?: string;
fechaFin?: string;
area?: string;
subgerencia?: string;
gerencia?: string;
creadorNombre?: string;
creadorCarnet?: string;
responsableCarnet?: string;
responsableNombre?: string;
progreso?: number; // ⚠️ Mapeado desde 'porcentaje' del SP
tipo?: string;
}
Lógica de Progreso/Atraso (Frontend)
renderProgreso(p): Barra visual 0-100% calculateDelay(p):
- Si progreso >= 100 → 0 (sin atraso)
- Si estado terminado/final/completado → 0
- Si hoy < fechaInicio → 0
- Calcula:
expected = min(100, (elapsed / totalDuration) * 100) - Atraso =
max(0, expected - progress)
renderAtraso(p): Badge visual con severidad (low/warning/critical)
Paginación
- Modo Local: Frontend descarga todos los proyectos (limit 2000) y pagina localmente
- Permite filtrado rápido (búsqueda, estado, gerencia, fecha, progreso, solo con atraso)
Flutter (v2flutter_movil)
Documentación en: v2flutter_movil/docs/ANALISIS_COMPLETO_PROYECTO.md
Errores Comunes y Soluciones
1. Progreso siempre en 0
Causa: El SP devuelve porcentaje pero el frontend lee progreso
Solución: Normalizar campos en el punto de ingesta: (p.progreso ?? p.porcentaje ?? 0)
2. Atraso 100% con tareas completas
Causa: Derivado del error #1 - progreso = 0 genera delay = expected (puede ser ~100%) Solución: Mismo fix que #1
3. Proyecto no aparece en lista
Posibles causas:
- Estado es 'Cancelado', 'Eliminado', o 'Inactivo' (filtrados en frontend)
- Usuario no tiene visibilidad (no es creador, responsable, ni tiene equipo asignado)
4. Progreso no refleja tareas hijas completadas
Causa: Solo se calculan tareas de nivel 0 (idTareaPadre IS NULL)
Solución: Las subtareas deben propagarse al padre vía recalcularJerarquia()