947 lines
35 KiB
YAML
947 lines
35 KiB
YAML
# TRACEABILITY-MGN-011.yaml
|
|
# Matriz de Trazabilidad - MGN-011: Proyectos Genéricos
|
|
# Fecha: 2025-11-24
|
|
# Versión: 1.0
|
|
|
|
module:
|
|
id: MGN-011
|
|
name: "Proyectos Genéricos"
|
|
description: "Gestión de proyectos: tareas, milestones, timesheet, miembros y seguimiento"
|
|
priority: P1
|
|
story_points: 40
|
|
status: Diseñado
|
|
|
|
metadata:
|
|
total_rf: 5
|
|
total_et_backend: 5
|
|
total_et_frontend: 5
|
|
total_tables: 5
|
|
total_tests: 100
|
|
coverage: 100%
|
|
|
|
requirements:
|
|
- rf_id: RF-MGN-011-001
|
|
rf_title: "Gestión de Proyectos"
|
|
rf_file: "requerimientos-funcionales/mgn-011/RF-MGN-011-001-gestión-de-proyectos.md"
|
|
priority: P1
|
|
story_points: 8
|
|
|
|
et_backend:
|
|
file: "especificaciones-tecnicas/backend/mgn-011/ET-BACKEND-MGN-011-001-gestión-de-proyectos.md"
|
|
endpoints:
|
|
- method: POST
|
|
path: /api/v1/projects
|
|
description: "Crear nuevo proyecto"
|
|
- method: GET
|
|
path: /api/v1/projects
|
|
description: "Listar todos los proyectos"
|
|
- method: GET
|
|
path: /api/v1/projects/:id
|
|
description: "Obtener proyecto por ID"
|
|
- method: PUT
|
|
path: /api/v1/projects/:id
|
|
description: "Actualizar proyecto"
|
|
- method: DELETE
|
|
path: /api/v1/projects/:id
|
|
description: "Eliminar proyecto (soft delete)"
|
|
services:
|
|
- name: "ProjectService"
|
|
file: "src/modules/projects/services/project.service.ts"
|
|
methods:
|
|
- create
|
|
- findAll
|
|
- findOne
|
|
- update
|
|
- remove
|
|
- validateBusinessRules
|
|
controllers:
|
|
- name: "ProjectController"
|
|
file: "src/modules/projects/controllers/project.controller.ts"
|
|
dtos:
|
|
- name: "CreateProjectDto"
|
|
file: "src/modules/projects/dto/create-project.dto.ts"
|
|
- name: "UpdateProjectDto"
|
|
file: "src/modules/projects/dto/update-project.dto.ts"
|
|
- name: "ProjectResponseDto"
|
|
file: "src/modules/projects/dto/project-response.dto.ts"
|
|
- name: "FilterProjectDto"
|
|
file: "src/modules/projects/dto/filter-project.dto.ts"
|
|
|
|
et_frontend:
|
|
file: "especificaciones-tecnicas/frontend/mgn-011/ET-FRONTEND-MGN-011-001-gestión-de-proyectos.md"
|
|
routes:
|
|
- path: "/projects"
|
|
component: "ProjectsPage"
|
|
- path: "/projects/create"
|
|
component: "CreateProjectPage"
|
|
- path: "/projects/:id/edit"
|
|
component: "EditProjectPage"
|
|
- path: "/projects/:id"
|
|
component: "ViewProjectPage"
|
|
components:
|
|
- name: "ProjectsTable"
|
|
file: "src/widgets/projects-table/ui/ProjectsTable.tsx"
|
|
type: widget
|
|
- name: "CreateProjectForm"
|
|
file: "src/features/create-project/ui/CreateProjectForm.tsx"
|
|
type: feature
|
|
- name: "ProjectCard"
|
|
file: "src/entities/project/ui/ProjectCard.tsx"
|
|
type: entity
|
|
- name: "ProjectPage"
|
|
file: "src/pages/projects/ProjectPage.tsx"
|
|
type: page
|
|
api_client:
|
|
- name: "projectApi"
|
|
file: "src/entities/project/api/project.api.ts"
|
|
methods:
|
|
- getAll
|
|
- getById
|
|
- create
|
|
- update
|
|
- delete
|
|
state_management:
|
|
- name: "useProjectStore"
|
|
file: "src/entities/project/model/project.store.ts"
|
|
type: zustand
|
|
- name: "useProjects"
|
|
file: "src/entities/project/api/project.queries.ts"
|
|
type: react-query
|
|
|
|
database_tables:
|
|
- schema: projects
|
|
table: projects
|
|
file: "database-design/schemas/projects-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- UPDATE
|
|
- DELETE (soft)
|
|
indices:
|
|
- idx_projects_tenant_id
|
|
- idx_projects_analytic_account_id
|
|
- idx_projects_status
|
|
rls_policy: tenant_isolation_projects
|
|
|
|
tests:
|
|
backend:
|
|
unit_tests:
|
|
- file: "src/modules/projects/services/project.service.spec.ts"
|
|
test_cases:
|
|
- "should create project with valid data"
|
|
- "should link to analytic account automatically"
|
|
- "should validate date range"
|
|
- "should find all projects for tenant"
|
|
- "should update project successfully"
|
|
integration_tests:
|
|
- file: "test/projects/project.controller.e2e-spec.ts"
|
|
test_cases:
|
|
- "POST /api/v1/projects should create project"
|
|
- "GET /api/v1/projects should return all projects"
|
|
- "GET /api/v1/projects/:id should return project"
|
|
- "PUT /api/v1/projects/:id should update project"
|
|
- "DELETE /api/v1/projects/:id should soft delete project"
|
|
- "should enforce tenant isolation"
|
|
- "should require authentication"
|
|
- "should check permissions"
|
|
frontend:
|
|
component_tests:
|
|
- file: "src/widgets/projects-table/ui/ProjectsTable.test.tsx"
|
|
test_cases:
|
|
- "should render table with projects"
|
|
- "should handle pagination"
|
|
- "should filter by status"
|
|
- file: "src/features/create-project/ui/CreateProjectForm.test.tsx"
|
|
test_cases:
|
|
- "should validate required fields"
|
|
- "should submit valid form"
|
|
- "should show error messages"
|
|
e2e_tests:
|
|
- file: "e2e/projects/projects.spec.ts"
|
|
test_cases:
|
|
- "should create project successfully"
|
|
- "should edit project successfully"
|
|
- "should delete project with confirmation"
|
|
- "should enforce permissions"
|
|
|
|
acceptance_criteria:
|
|
- id: AC-001
|
|
description: "Usuario puede crear proyectos con nombre, fechas y presupuesto"
|
|
status: Pending
|
|
test_reference: "test/projects/project.controller.e2e-spec.ts:35"
|
|
- id: AC-002
|
|
description: "Proyecto se vincula automáticamente a cuenta analítica"
|
|
status: Pending
|
|
test_reference: "src/modules/projects/services/project.service.spec.ts:72"
|
|
- id: AC-003
|
|
description: "Sistema calcula progreso basado en tareas completadas"
|
|
status: Pending
|
|
test_reference: "test/projects/project.controller.e2e-spec.ts:108"
|
|
|
|
business_rules:
|
|
- id: RN-001
|
|
description: "Fecha de fin debe ser posterior a fecha de inicio"
|
|
implementation: "src/modules/projects/dto/create-project.dto.ts:@IsDateAfter('start_date')"
|
|
test_reference: "src/modules/projects/services/project.service.spec.ts:95"
|
|
- id: RN-002
|
|
description: "Proyecto crea automáticamente cuenta analítica asociada"
|
|
implementation: "src/modules/projects/services/project.service.ts:create()"
|
|
test_reference: "src/modules/projects/services/project.service.spec.ts:122"
|
|
- id: RN-003
|
|
description: "Progreso se calcula como: tareas completadas / total tareas"
|
|
implementation: "src/modules/projects/services/project.service.ts:calculateProgress()"
|
|
test_reference: "src/modules/projects/services/project.service.spec.ts:148"
|
|
|
|
dependencies:
|
|
rf_dependencies:
|
|
- RF-MGN-008-001
|
|
module_dependencies:
|
|
- MGN-001
|
|
- MGN-008
|
|
external_dependencies:
|
|
- name: "@nestjs/common"
|
|
version: "^10.0.0"
|
|
- name: "ant-design"
|
|
version: "^5.0.0"
|
|
|
|
- rf_id: RF-MGN-011-002
|
|
rf_title: "Gestión de Tareas (Kanban)"
|
|
rf_file: "requerimientos-funcionales/mgn-011/RF-MGN-011-002-gestión-de-tareas-kanban.md"
|
|
priority: P1
|
|
story_points: 13
|
|
|
|
et_backend:
|
|
file: "especificaciones-tecnicas/backend/mgn-011/ET-BACKEND-MGN-011-002-gestión-de-tareas-kanban.md"
|
|
endpoints:
|
|
- method: POST
|
|
path: /api/v1/projects/tasks
|
|
description: "Crear nueva tarea"
|
|
- method: GET
|
|
path: /api/v1/projects/tasks
|
|
description: "Listar todas las tareas"
|
|
- method: GET
|
|
path: /api/v1/projects/tasks/:id
|
|
description: "Obtener tarea por ID"
|
|
- method: PUT
|
|
path: /api/v1/projects/tasks/:id
|
|
description: "Actualizar tarea"
|
|
- method: POST
|
|
path: /api/v1/projects/tasks/:id/move
|
|
description: "Mover tarea a otro stage"
|
|
services:
|
|
- name: "TaskService"
|
|
file: "src/modules/projects/services/task.service.ts"
|
|
methods:
|
|
- create
|
|
- findAll
|
|
- findOne
|
|
- update
|
|
- move
|
|
- validateBusinessRules
|
|
controllers:
|
|
- name: "TaskController"
|
|
file: "src/modules/projects/controllers/task.controller.ts"
|
|
dtos:
|
|
- name: "CreateTaskDto"
|
|
file: "src/modules/projects/dto/create-task.dto.ts"
|
|
- name: "UpdateTaskDto"
|
|
file: "src/modules/projects/dto/update-task.dto.ts"
|
|
- name: "TaskResponseDto"
|
|
file: "src/modules/projects/dto/task-response.dto.ts"
|
|
- name: "MoveTaskDto"
|
|
file: "src/modules/projects/dto/move-task.dto.ts"
|
|
|
|
et_frontend:
|
|
file: "especificaciones-tecnicas/frontend/mgn-011/ET-FRONTEND-MGN-011-002-gestión-de-tareas-kanban.md"
|
|
routes:
|
|
- path: "/projects/:projectId/tasks"
|
|
component: "ProjectTasksPage"
|
|
- path: "/projects/:projectId/tasks/kanban"
|
|
component: "TasksKanbanPage"
|
|
- path: "/projects/tasks/:id"
|
|
component: "ViewTaskPage"
|
|
components:
|
|
- name: "TasksKanban"
|
|
file: "src/widgets/tasks-kanban/ui/TasksKanban.tsx"
|
|
type: widget
|
|
- name: "CreateTaskForm"
|
|
file: "src/features/create-task/ui/CreateTaskForm.tsx"
|
|
type: feature
|
|
- name: "TaskCard"
|
|
file: "src/entities/task/ui/TaskCard.tsx"
|
|
type: entity
|
|
- name: "TaskPage"
|
|
file: "src/pages/projects/TaskPage.tsx"
|
|
type: page
|
|
api_client:
|
|
- name: "taskApi"
|
|
file: "src/entities/task/api/task.api.ts"
|
|
methods:
|
|
- getAll
|
|
- getById
|
|
- create
|
|
- update
|
|
- move
|
|
state_management:
|
|
- name: "useTaskStore"
|
|
file: "src/entities/task/model/task.store.ts"
|
|
type: zustand
|
|
- name: "useTasks"
|
|
file: "src/entities/task/api/task.queries.ts"
|
|
type: react-query
|
|
|
|
database_tables:
|
|
- schema: projects
|
|
table: tasks
|
|
file: "database-design/schemas/projects-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- UPDATE
|
|
- DELETE (soft)
|
|
indices:
|
|
- idx_tasks_tenant_id
|
|
- idx_tasks_project_id
|
|
- idx_tasks_stage_id
|
|
- idx_tasks_assigned_to
|
|
rls_policy: tenant_isolation_tasks
|
|
- schema: projects
|
|
table: task_stages
|
|
file: "database-design/schemas/projects-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- UPDATE
|
|
indices:
|
|
- idx_task_stages_project_id
|
|
rls_policy: tenant_isolation_task_stages
|
|
|
|
tests:
|
|
backend:
|
|
unit_tests:
|
|
- file: "src/modules/projects/services/task.service.spec.ts"
|
|
test_cases:
|
|
- "should create task with valid data"
|
|
- "should assign task to user"
|
|
- "should move task between stages"
|
|
- "should find all tasks for project"
|
|
- "should update task successfully"
|
|
integration_tests:
|
|
- file: "test/projects/task.controller.e2e-spec.ts"
|
|
test_cases:
|
|
- "POST /api/v1/projects/tasks should create task"
|
|
- "GET /api/v1/projects/tasks should return all tasks"
|
|
- "GET /api/v1/projects/tasks/:id should return task"
|
|
- "PUT /api/v1/projects/tasks/:id should update task"
|
|
- "POST /api/v1/projects/tasks/:id/move should move task"
|
|
- "should enforce tenant isolation"
|
|
- "should require authentication"
|
|
- "should check permissions"
|
|
frontend:
|
|
component_tests:
|
|
- file: "src/widgets/tasks-kanban/ui/TasksKanban.test.tsx"
|
|
test_cases:
|
|
- "should render kanban board"
|
|
- "should drag and drop tasks"
|
|
- "should show task details"
|
|
- file: "src/features/create-task/ui/CreateTaskForm.test.tsx"
|
|
test_cases:
|
|
- "should validate required fields"
|
|
- "should submit valid form"
|
|
- "should show error messages"
|
|
e2e_tests:
|
|
- file: "e2e/projects/tasks.spec.ts"
|
|
test_cases:
|
|
- "should create task successfully"
|
|
- "should drag task to new stage"
|
|
- "should assign task to user"
|
|
- "should enforce permissions"
|
|
|
|
acceptance_criteria:
|
|
- id: AC-001
|
|
description: "Usuario puede crear tareas dentro de proyectos"
|
|
status: Pending
|
|
test_reference: "test/projects/task.controller.e2e-spec.ts:42"
|
|
- id: AC-002
|
|
description: "Tareas se visualizan en formato Kanban"
|
|
status: Pending
|
|
test_reference: "src/widgets/tasks-kanban/ui/TasksKanban.test.tsx:78"
|
|
- id: AC-003
|
|
description: "Tareas se mueven entre stages con drag & drop"
|
|
status: Pending
|
|
test_reference: "e2e/projects/tasks.spec.ts:115"
|
|
|
|
business_rules:
|
|
- id: RN-001
|
|
description: "Tarea debe estar asociada a un proyecto"
|
|
implementation: "src/modules/projects/services/task.service.ts:validateProject()"
|
|
test_reference: "src/modules/projects/services/task.service.spec.ts:102"
|
|
- id: RN-002
|
|
description: "Al mover tarea, se registra actividad automáticamente"
|
|
implementation: "src/modules/projects/services/task.service.ts:move()"
|
|
test_reference: "src/modules/projects/services/task.service.spec.ts:128"
|
|
- id: RN-003
|
|
description: "Tarea completada actualiza progreso del proyecto"
|
|
implementation: "src/modules/projects/services/task.service.ts:updateProgress()"
|
|
test_reference: "src/modules/projects/services/task.service.spec.ts:155"
|
|
|
|
dependencies:
|
|
rf_dependencies:
|
|
- RF-MGN-011-001
|
|
module_dependencies:
|
|
- MGN-001
|
|
- MGN-014
|
|
external_dependencies:
|
|
- name: "@dnd-kit/core"
|
|
version: "^6.0.0"
|
|
|
|
- rf_id: RF-MGN-011-003
|
|
rf_title: "Milestones (Hitos)"
|
|
rf_file: "requerimientos-funcionales/mgn-011/RF-MGN-011-003-milestones-hitos.md"
|
|
priority: P1
|
|
story_points: 3
|
|
|
|
et_backend:
|
|
file: "especificaciones-tecnicas/backend/mgn-011/ET-BACKEND-MGN-011-003-milestones-hitos.md"
|
|
endpoints:
|
|
- method: POST
|
|
path: /api/v1/projects/milestones
|
|
description: "Crear milestone"
|
|
- method: GET
|
|
path: /api/v1/projects/milestones
|
|
description: "Listar milestones"
|
|
- method: GET
|
|
path: /api/v1/projects/milestones/:id
|
|
description: "Obtener milestone por ID"
|
|
- method: PUT
|
|
path: /api/v1/projects/milestones/:id
|
|
description: "Actualizar milestone"
|
|
- method: POST
|
|
path: /api/v1/projects/milestones/:id/complete
|
|
description: "Marcar milestone como completado"
|
|
services:
|
|
- name: "MilestoneService"
|
|
file: "src/modules/projects/services/milestone.service.ts"
|
|
methods:
|
|
- create
|
|
- findAll
|
|
- findOne
|
|
- update
|
|
- complete
|
|
- validateBusinessRules
|
|
controllers:
|
|
- name: "MilestoneController"
|
|
file: "src/modules/projects/controllers/milestone.controller.ts"
|
|
dtos:
|
|
- name: "CreateMilestoneDto"
|
|
file: "src/modules/projects/dto/create-milestone.dto.ts"
|
|
- name: "UpdateMilestoneDto"
|
|
file: "src/modules/projects/dto/update-milestone.dto.ts"
|
|
- name: "MilestoneResponseDto"
|
|
file: "src/modules/projects/dto/milestone-response.dto.ts"
|
|
- name: "FilterMilestoneDto"
|
|
file: "src/modules/projects/dto/filter-milestone.dto.ts"
|
|
|
|
et_frontend:
|
|
file: "especificaciones-tecnicas/frontend/mgn-011/ET-FRONTEND-MGN-011-003-milestones-hitos.md"
|
|
routes:
|
|
- path: "/projects/:projectId/milestones"
|
|
component: "MilestonesPage"
|
|
- path: "/projects/milestones/:id"
|
|
component: "ViewMilestonePage"
|
|
components:
|
|
- name: "MilestonesTimeline"
|
|
file: "src/widgets/milestones-timeline/ui/MilestonesTimeline.tsx"
|
|
type: widget
|
|
- name: "CreateMilestoneForm"
|
|
file: "src/features/create-milestone/ui/CreateMilestoneForm.tsx"
|
|
type: feature
|
|
- name: "MilestoneCard"
|
|
file: "src/entities/milestone/ui/MilestoneCard.tsx"
|
|
type: entity
|
|
- name: "MilestonePage"
|
|
file: "src/pages/projects/MilestonePage.tsx"
|
|
type: page
|
|
api_client:
|
|
- name: "milestoneApi"
|
|
file: "src/entities/milestone/api/milestone.api.ts"
|
|
methods:
|
|
- getAll
|
|
- getById
|
|
- create
|
|
- update
|
|
- complete
|
|
state_management:
|
|
- name: "useMilestoneStore"
|
|
file: "src/entities/milestone/model/milestone.store.ts"
|
|
type: zustand
|
|
- name: "useMilestones"
|
|
file: "src/entities/milestone/api/milestone.queries.ts"
|
|
type: react-query
|
|
|
|
database_tables:
|
|
- schema: projects
|
|
table: milestones
|
|
file: "database-design/schemas/projects-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- UPDATE
|
|
- DELETE (soft)
|
|
indices:
|
|
- idx_milestones_tenant_id
|
|
- idx_milestones_project_id
|
|
- idx_milestones_target_date
|
|
rls_policy: tenant_isolation_milestones
|
|
|
|
tests:
|
|
backend:
|
|
unit_tests:
|
|
- file: "src/modules/projects/services/milestone.service.spec.ts"
|
|
test_cases:
|
|
- "should create milestone with valid data"
|
|
- "should validate target date"
|
|
- "should complete milestone successfully"
|
|
- "should find all milestones for project"
|
|
- "should update milestone successfully"
|
|
integration_tests:
|
|
- file: "test/projects/milestone.controller.e2e-spec.ts"
|
|
test_cases:
|
|
- "POST /api/v1/projects/milestones should create milestone"
|
|
- "GET /api/v1/projects/milestones should return all milestones"
|
|
- "GET /api/v1/projects/milestones/:id should return milestone"
|
|
- "PUT /api/v1/projects/milestones/:id should update milestone"
|
|
- "POST /api/v1/projects/milestones/:id/complete should complete"
|
|
- "should enforce tenant isolation"
|
|
- "should require authentication"
|
|
- "should check permissions"
|
|
frontend:
|
|
component_tests:
|
|
- file: "src/widgets/milestones-timeline/ui/MilestonesTimeline.test.tsx"
|
|
test_cases:
|
|
- "should render timeline"
|
|
- "should show completed milestones"
|
|
- "should highlight overdue milestones"
|
|
- file: "src/features/create-milestone/ui/CreateMilestoneForm.test.tsx"
|
|
test_cases:
|
|
- "should validate required fields"
|
|
- "should submit valid form"
|
|
- "should show error messages"
|
|
e2e_tests:
|
|
- file: "e2e/projects/milestones.spec.ts"
|
|
test_cases:
|
|
- "should create milestone successfully"
|
|
- "should complete milestone"
|
|
- "should view milestones timeline"
|
|
- "should enforce permissions"
|
|
|
|
acceptance_criteria:
|
|
- id: AC-001
|
|
description: "Usuario puede crear milestones con nombre y fecha objetivo"
|
|
status: Pending
|
|
test_reference: "test/projects/milestone.controller.e2e-spec.ts:45"
|
|
- id: AC-002
|
|
description: "Milestones se visualizan en timeline del proyecto"
|
|
status: Pending
|
|
test_reference: "src/widgets/milestones-timeline/ui/MilestonesTimeline.test.tsx:82"
|
|
- id: AC-003
|
|
description: "Sistema alerta sobre milestones próximos o vencidos"
|
|
status: Pending
|
|
test_reference: "e2e/projects/milestones.spec.ts:118"
|
|
|
|
business_rules:
|
|
- id: RN-001
|
|
description: "Milestone debe estar asociado a un proyecto"
|
|
implementation: "src/modules/projects/services/milestone.service.ts:validateProject()"
|
|
test_reference: "src/modules/projects/services/milestone.service.spec.ts:108"
|
|
- id: RN-002
|
|
description: "Fecha objetivo debe estar dentro del rango del proyecto"
|
|
implementation: "src/modules/projects/services/milestone.service.ts:validateDate()"
|
|
test_reference: "src/modules/projects/services/milestone.service.spec.ts:135"
|
|
- id: RN-003
|
|
description: "Completar milestone actualiza progreso del proyecto"
|
|
implementation: "src/modules/projects/services/milestone.service.ts:complete()"
|
|
test_reference: "src/modules/projects/services/milestone.service.spec.ts:162"
|
|
|
|
dependencies:
|
|
rf_dependencies:
|
|
- RF-MGN-011-001
|
|
module_dependencies:
|
|
- MGN-001
|
|
- MGN-014
|
|
external_dependencies:
|
|
- name: "@nestjs/common"
|
|
version: "^10.0.0"
|
|
|
|
- rf_id: RF-MGN-011-004
|
|
rf_title: "Timesheet de Proyectos"
|
|
rf_file: "requerimientos-funcionales/mgn-011/RF-MGN-011-004-timesheet-de-proyectos.md"
|
|
priority: P1
|
|
story_points: 8
|
|
|
|
et_backend:
|
|
file: "especificaciones-tecnicas/backend/mgn-011/ET-BACKEND-MGN-011-004-timesheet-de-proyectos.md"
|
|
endpoints:
|
|
- method: POST
|
|
path: /api/v1/projects/timesheet-entries
|
|
description: "Registrar entrada de timesheet"
|
|
- method: GET
|
|
path: /api/v1/projects/timesheet-entries
|
|
description: "Listar entradas de timesheet"
|
|
- method: GET
|
|
path: /api/v1/projects/timesheet-entries/:id
|
|
description: "Obtener entrada por ID"
|
|
- method: PUT
|
|
path: /api/v1/projects/timesheet-entries/:id
|
|
description: "Actualizar entrada"
|
|
- method: GET
|
|
path: /api/v1/projects/timesheet-entries/report
|
|
description: "Reporte de timesheet"
|
|
services:
|
|
- name: "TimesheetService"
|
|
file: "src/modules/projects/services/timesheet.service.ts"
|
|
methods:
|
|
- create
|
|
- findAll
|
|
- findOne
|
|
- update
|
|
- getReport
|
|
- validateBusinessRules
|
|
controllers:
|
|
- name: "TimesheetController"
|
|
file: "src/modules/projects/controllers/timesheet.controller.ts"
|
|
dtos:
|
|
- name: "CreateTimesheetEntryDto"
|
|
file: "src/modules/projects/dto/create-timesheet-entry.dto.ts"
|
|
- name: "UpdateTimesheetEntryDto"
|
|
file: "src/modules/projects/dto/update-timesheet-entry.dto.ts"
|
|
- name: "TimesheetEntryResponseDto"
|
|
file: "src/modules/projects/dto/timesheet-entry-response.dto.ts"
|
|
- name: "TimesheetReportDto"
|
|
file: "src/modules/projects/dto/timesheet-report.dto.ts"
|
|
|
|
et_frontend:
|
|
file: "especificaciones-tecnicas/frontend/mgn-011/ET-FRONTEND-MGN-011-004-timesheet-de-proyectos.md"
|
|
routes:
|
|
- path: "/projects/timesheet"
|
|
component: "TimesheetPage"
|
|
- path: "/projects/timesheet/report"
|
|
component: "TimesheetReportPage"
|
|
components:
|
|
- name: "TimesheetGrid"
|
|
file: "src/widgets/timesheet-grid/ui/TimesheetGrid.tsx"
|
|
type: widget
|
|
- name: "CreateTimesheetEntry"
|
|
file: "src/features/create-timesheet-entry/ui/CreateTimesheetEntry.tsx"
|
|
type: feature
|
|
- name: "TimesheetCard"
|
|
file: "src/entities/timesheet/ui/TimesheetCard.tsx"
|
|
type: entity
|
|
- name: "TimesheetPage"
|
|
file: "src/pages/projects/TimesheetPage.tsx"
|
|
type: page
|
|
api_client:
|
|
- name: "timesheetApi"
|
|
file: "src/entities/timesheet/api/timesheet.api.ts"
|
|
methods:
|
|
- getAll
|
|
- getById
|
|
- create
|
|
- update
|
|
- getReport
|
|
state_management:
|
|
- name: "useTimesheetStore"
|
|
file: "src/entities/timesheet/model/timesheet.store.ts"
|
|
type: zustand
|
|
- name: "useTimesheet"
|
|
file: "src/entities/timesheet/api/timesheet.queries.ts"
|
|
type: react-query
|
|
|
|
database_tables:
|
|
- schema: projects
|
|
table: timesheet_entries
|
|
file: "database-design/schemas/projects-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- UPDATE
|
|
- DELETE (soft)
|
|
indices:
|
|
- idx_timesheet_entries_tenant_id
|
|
- idx_timesheet_entries_project_id
|
|
- idx_timesheet_entries_task_id
|
|
- idx_timesheet_entries_user_id
|
|
- idx_timesheet_entries_date
|
|
rls_policy: tenant_isolation_timesheet_entries
|
|
|
|
tests:
|
|
backend:
|
|
unit_tests:
|
|
- file: "src/modules/projects/services/timesheet.service.spec.ts"
|
|
test_cases:
|
|
- "should create timesheet entry"
|
|
- "should validate hours range"
|
|
- "should generate timesheet report"
|
|
- "should find all entries for user"
|
|
- "should update entry successfully"
|
|
integration_tests:
|
|
- file: "test/projects/timesheet.controller.e2e-spec.ts"
|
|
test_cases:
|
|
- "POST /api/v1/projects/timesheet-entries should create entry"
|
|
- "GET /api/v1/projects/timesheet-entries should return entries"
|
|
- "GET /api/v1/projects/timesheet-entries/:id should return entry"
|
|
- "PUT /api/v1/projects/timesheet-entries/:id should update entry"
|
|
- "GET /api/v1/projects/timesheet-entries/report should return report"
|
|
- "should enforce tenant isolation"
|
|
- "should require authentication"
|
|
- "should check permissions"
|
|
frontend:
|
|
component_tests:
|
|
- file: "src/widgets/timesheet-grid/ui/TimesheetGrid.test.tsx"
|
|
test_cases:
|
|
- "should render timesheet grid"
|
|
- "should edit inline hours"
|
|
- "should calculate weekly totals"
|
|
- file: "src/features/create-timesheet-entry/ui/CreateTimesheetEntry.test.tsx"
|
|
test_cases:
|
|
- "should validate hours"
|
|
- "should submit valid entry"
|
|
- "should show error messages"
|
|
e2e_tests:
|
|
- file: "e2e/projects/timesheet.spec.ts"
|
|
test_cases:
|
|
- "should log hours successfully"
|
|
- "should view timesheet report"
|
|
- "should edit timesheet entry"
|
|
- "should enforce permissions"
|
|
|
|
acceptance_criteria:
|
|
- id: AC-001
|
|
description: "Usuario puede registrar horas trabajadas en proyectos/tareas"
|
|
status: Pending
|
|
test_reference: "test/projects/timesheet.controller.e2e-spec.ts:48"
|
|
- id: AC-002
|
|
description: "Timesheet se visualiza en formato grid semanal"
|
|
status: Pending
|
|
test_reference: "src/widgets/timesheet-grid/ui/TimesheetGrid.test.tsx:85"
|
|
- id: AC-003
|
|
description: "Reportes muestran horas por proyecto/tarea/usuario"
|
|
status: Pending
|
|
test_reference: "e2e/projects/timesheet.spec.ts:122"
|
|
|
|
business_rules:
|
|
- id: RN-001
|
|
description: "Horas registradas deben estar entre 0 y 24"
|
|
implementation: "src/modules/projects/dto/create-timesheet-entry.dto.ts:@Min(0) @Max(24)"
|
|
test_reference: "src/modules/projects/services/timesheet.service.spec.ts:112"
|
|
- id: RN-002
|
|
description: "Entrada debe estar asociada a proyecto o tarea"
|
|
implementation: "src/modules/projects/services/timesheet.service.ts:validateRelation()"
|
|
test_reference: "src/modules/projects/services/timesheet.service.spec.ts:138"
|
|
- id: RN-003
|
|
description: "Horas facturables generan líneas analíticas automáticamente"
|
|
implementation: "src/modules/projects/services/timesheet.service.ts:createAnalyticLine()"
|
|
test_reference: "src/modules/projects/services/timesheet.service.spec.ts:165"
|
|
|
|
dependencies:
|
|
rf_dependencies:
|
|
- RF-MGN-011-001
|
|
- RF-MGN-011-002
|
|
- RF-MGN-008-002
|
|
module_dependencies:
|
|
- MGN-001
|
|
- MGN-008
|
|
external_dependencies:
|
|
- name: "@nestjs/common"
|
|
version: "^10.0.0"
|
|
- name: "date-fns"
|
|
version: "^2.30.0"
|
|
|
|
- rf_id: RF-MGN-011-005
|
|
rf_title: "Vista Gantt de Proyectos"
|
|
rf_file: "requerimientos-funcionales/mgn-011/RF-MGN-011-005-vista-gantt-de-proyectos.md"
|
|
priority: P2
|
|
story_points: 8
|
|
|
|
et_backend:
|
|
file: "especificaciones-tecnicas/backend/mgn-011/ET-BACKEND-MGN-011-005-vista-gantt-de-proyectos.md"
|
|
endpoints:
|
|
- method: GET
|
|
path: /api/v1/projects/:id/gantt
|
|
description: "Obtener datos para vista Gantt"
|
|
- method: PUT
|
|
path: /api/v1/projects/tasks/:id/reschedule
|
|
description: "Reprogramar tarea"
|
|
- method: POST
|
|
path: /api/v1/projects/tasks/:id/dependencies
|
|
description: "Crear dependencia entre tareas"
|
|
- method: GET
|
|
path: /api/v1/projects/:id/critical-path
|
|
description: "Calcular ruta crítica"
|
|
services:
|
|
- name: "GanttService"
|
|
file: "src/modules/projects/services/gantt.service.ts"
|
|
methods:
|
|
- getGanttData
|
|
- rescheduleTask
|
|
- createDependency
|
|
- calculateCriticalPath
|
|
controllers:
|
|
- name: "GanttController"
|
|
file: "src/modules/projects/controllers/gantt.controller.ts"
|
|
dtos:
|
|
- name: "RescheduleTaskDto"
|
|
file: "src/modules/projects/dto/reschedule-task.dto.ts"
|
|
- name: "CreateDependencyDto"
|
|
file: "src/modules/projects/dto/create-dependency.dto.ts"
|
|
- name: "GanttDataResponseDto"
|
|
file: "src/modules/projects/dto/gantt-data-response.dto.ts"
|
|
|
|
et_frontend:
|
|
file: "especificaciones-tecnicas/frontend/mgn-011/ET-FRONTEND-MGN-011-005-vista-gantt-de-proyectos.md"
|
|
routes:
|
|
- path: "/projects/:id/gantt"
|
|
component: "ProjectGanttPage"
|
|
components:
|
|
- name: "GanttChart"
|
|
file: "src/widgets/gantt-chart/ui/GanttChart.tsx"
|
|
type: widget
|
|
- name: "GanttControls"
|
|
file: "src/features/gantt-controls/ui/GanttControls.tsx"
|
|
type: feature
|
|
- name: "TaskDependencies"
|
|
file: "src/entities/task/ui/TaskDependencies.tsx"
|
|
type: entity
|
|
- name: "GanttPage"
|
|
file: "src/pages/projects/GanttPage.tsx"
|
|
type: page
|
|
api_client:
|
|
- name: "ganttApi"
|
|
file: "src/entities/gantt/api/gantt.api.ts"
|
|
methods:
|
|
- getGanttData
|
|
- rescheduleTask
|
|
- createDependency
|
|
- getCriticalPath
|
|
state_management:
|
|
- name: "useGanttStore"
|
|
file: "src/entities/gantt/model/gantt.store.ts"
|
|
type: zustand
|
|
|
|
database_tables:
|
|
- schema: projects
|
|
table: tasks
|
|
file: "database-design/schemas/projects-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- UPDATE
|
|
indices:
|
|
- idx_tasks_start_date
|
|
- idx_tasks_end_date
|
|
rls_policy: tenant_isolation_tasks
|
|
- schema: projects
|
|
table: task_dependencies
|
|
file: "database-design/schemas/projects-schema-ddl.sql"
|
|
operations:
|
|
- SELECT
|
|
- INSERT
|
|
- DELETE
|
|
indices:
|
|
- idx_task_dependencies_task_id
|
|
- idx_task_dependencies_depends_on_id
|
|
rls_policy: tenant_isolation_task_dependencies
|
|
|
|
tests:
|
|
backend:
|
|
unit_tests:
|
|
- file: "src/modules/projects/services/gantt.service.spec.ts"
|
|
test_cases:
|
|
- "should generate Gantt data"
|
|
- "should reschedule task with dependencies"
|
|
- "should create task dependency"
|
|
- "should calculate critical path"
|
|
- "should validate circular dependencies"
|
|
integration_tests:
|
|
- file: "test/projects/gantt.controller.e2e-spec.ts"
|
|
test_cases:
|
|
- "GET /api/v1/projects/:id/gantt should return Gantt data"
|
|
- "PUT /api/v1/projects/tasks/:id/reschedule should reschedule"
|
|
- "POST /api/v1/projects/tasks/:id/dependencies should create dependency"
|
|
- "GET /api/v1/projects/:id/critical-path should return path"
|
|
- "should prevent circular dependencies"
|
|
- "should enforce tenant isolation"
|
|
- "should require authentication"
|
|
- "should check permissions"
|
|
frontend:
|
|
component_tests:
|
|
- file: "src/widgets/gantt-chart/ui/GanttChart.test.tsx"
|
|
test_cases:
|
|
- "should render Gantt chart"
|
|
- "should drag to reschedule task"
|
|
- "should show task dependencies"
|
|
- file: "src/features/gantt-controls/ui/GanttControls.test.tsx"
|
|
test_cases:
|
|
- "should zoom in/out"
|
|
- "should filter by resource"
|
|
- "should highlight critical path"
|
|
e2e_tests:
|
|
- file: "e2e/projects/gantt.spec.ts"
|
|
test_cases:
|
|
- "should display Gantt chart"
|
|
- "should reschedule task by dragging"
|
|
- "should create task dependency"
|
|
- "should enforce permissions"
|
|
|
|
acceptance_criteria:
|
|
- id: AC-001
|
|
description: "Usuario puede visualizar proyecto en vista Gantt"
|
|
status: Pending
|
|
test_reference: "test/projects/gantt.controller.e2e-spec.ts:52"
|
|
- id: AC-002
|
|
description: "Tareas pueden reprogramarse con drag & drop"
|
|
status: Pending
|
|
test_reference: "src/widgets/gantt-chart/ui/GanttChart.test.tsx:88"
|
|
- id: AC-003
|
|
description: "Sistema calcula y muestra ruta crítica"
|
|
status: Pending
|
|
test_reference: "e2e/projects/gantt.spec.ts:125"
|
|
|
|
business_rules:
|
|
- id: RN-001
|
|
description: "Dependencias no deben formar ciclos"
|
|
implementation: "src/modules/projects/services/gantt.service.ts:validateNoCycles()"
|
|
test_reference: "src/modules/projects/services/gantt.service.spec.ts:115"
|
|
- id: RN-002
|
|
description: "Reprogramar tarea ajusta automáticamente dependientes"
|
|
implementation: "src/modules/projects/services/gantt.service.ts:rescheduleTask()"
|
|
test_reference: "src/modules/projects/services/gantt.service.spec.ts:142"
|
|
- id: RN-003
|
|
description: "Ruta crítica identifica secuencia de tareas sin holgura"
|
|
implementation: "src/modules/projects/services/gantt.service.ts:calculateCriticalPath()"
|
|
test_reference: "src/modules/projects/services/gantt.service.spec.ts:168"
|
|
|
|
dependencies:
|
|
rf_dependencies:
|
|
- RF-MGN-011-001
|
|
- RF-MGN-011-002
|
|
module_dependencies:
|
|
- MGN-001
|
|
external_dependencies:
|
|
- name: "dhtmlx-gantt"
|
|
version: "^8.0.0"
|
|
|
|
coverage:
|
|
rf_to_et_backend: 100%
|
|
rf_to_et_frontend: 100%
|
|
rf_to_database: 100%
|
|
rf_to_tests: 100%
|
|
backend_tests: 100%
|
|
frontend_tests: 100%
|
|
|
|
statistics:
|
|
total_endpoints: 25
|
|
total_components: 20
|
|
total_tables: 5
|
|
total_test_cases: 100
|
|
estimated_duration_sprints: 2
|