Misiones
Resumen
Sección titulada «Resumen»El módulo de Misiones cubre el ciclo completo de una misión (tarea de desarrollo/evaluación asignada a un colaborador): verla, avanzarla, entregarla, y — si el usuario autenticado es responsable de otras personas — asignarla a un miembro de su equipo y evaluarla (aprobar/rechazar tareas o la misión completa, calificarla y agendar feedback).
Acciones cubiertas:
- Ver mis misiones (listado + resumen de estados) y el detalle de una misión, incluyendo tareas, archivos de soporte, entregas y feedbacks.
- Crear una misión para mí mismo o para un miembro de mi equipo, con tareas opcionales y vínculo opcional a un proceso/objetivo de evaluación.
- Avanzar el estado de mi misión (marcarla leída, iniciarla) y enviarla a revisión adjuntando una entrega (comentario + archivo/link) a nivel de misión o de tarea.
- Eliminar una misión propia o de mi equipo.
- Evaluar misiones de mi equipo: aprobar o rechazar tareas/misión con calificación (1-5), rechazar con comentario, agendar y marcar feedback como realizado.
- Consultar la actividad (bitácora de auditoría) de una misión.
Prerrequisitos:
- El controlador exige JWT y contexto de tenant (
@RequiresTenancy()) en todas las rutas; no requiereRequiresOrganizationalInfopara las rutas de este documento (a diferencia del listadoteam/all, fuera de alcance — ver nota abajo).
:::
Fuera de la paginación (GET /missions, que responde { data, meta, links }), ninguna respuesta viene envuelta en { data: ... }: el TransformInterceptor del backend no agrega ese sobre — sólo aplica class-transformer cuando el endpoint declara un DTO de salida, y no existe otro interceptor global que envuelva la respuesta. Los tipos TypeScript de referencia del portal (ApiDataResponse<T>) asumen un sobre { data } que en la práctica no llega; el código de referencia maneja ambos casos de forma defensiva. Los ejemplos de este documento reflejan el body real (sin sobre).
Este documento no cubre GET /missions/team/all, POST /v2/missions/search, POST /v2/missions/search/creators ni POST /v2/missions/search/export (tablero/búsqueda administrativa fuera del alcance de autoservicio) ni los endpoints de “planes de acción” legacy bajo /me/mission/* (action-plans, team/:username, team/summary/all), que pertenecen a un módulo distinto (src/mission/, migración de planes de acción legacy) y no son consumidos por la pantalla de Misiones de referencia.
sequenceDiagram
participant App as App móvil
participant API as th-core-api
Note over App,API: Carga inicial de Mis misiones
App->>API: GET /missions/summary
API-->>App: contadores por estado + avgCsat/avgCes
App->>API: GET /missions?filter.status=$btw:1,6
API-->>App: listado paginado de mis misiones
Note over App,API: Abrir el detalle de una misión
App->>API: PATCH /missions/:missionId (status=READ) si estaba ASSIGNED
App->>API: GET /missions/:missionId
API-->>App: misión completa (tareas, archivos, entregas, feedbacks)
App->>API: GET /missions/:missionId/activity
API-->>App: bitácora de eventos
Note over App,API: Asignar una misión nueva (a mí o a un miembro de mi equipo)
App->>API: POST /missions o POST /missions/:userId
API-->>App: misión creada (status ASSIGNED)
Note over App,API: Avanzar y entregar mi misión
App->>API: PATCH /missions/:missionId (status=IN_PROGRESS)
Note over App: bloqueado si startDate es futura
App->>API: POST /missions/:missionId/deliveries o /tasks/:taskId/deliveries
App->>API: PATCH /missions/tasks/:taskId (taskStatus=SENT)
App->>API: PATCH /missions/:missionId (status=COMPLETED, missionDifficulty)
API-->>App: misión en revisión
Note over App,API: Evaluar la misión de un miembro del equipo
App->>API: PATCH /missions/tasks/:taskId (taskQuality) luego (taskStatus=APPROVED|REJECTED)
App->>API: PATCH /missions/:missionId/deliveries/:deliveryId (rejectionComment) si se rechaza
App->>API: PATCH /missions/:missionId (status calculado: TO_BE_CORRECTED, APPROVED o FINALIZED)
API-->>App: misión evaluada
Note over App,API: Agendar y cerrar feedback
App->>API: POST /missions/:missionId/feedbacks
App->>API: PATCH /missions/feedbacks/:feedbackId (feedbackStatus=DONE)
Note over App: si la misión estaba APPROVED, se envía además PATCH status=FINALIZED
Note over App,API: Eliminar
App->>API: DELETE /missions/:missionId
Endpoints
Sección titulada «Endpoints»GET /missions/summary
Sección titulada «GET /missions/summary»Resumen de estados de mis misiones (usuario autenticado).
No recibe query params.
Response:
| Campo | Tipo | Descripción |
|---|---|---|
assigned |
number | Misiones en estado ASSIGNED (1). |
read |
number | Misiones en estado READ (2). Se calcula en el backend pero no está documentado en el Swagger del endpoint — verificado en getMissionSummaryForUser. |
inProgress |
number | Misiones en estado IN_PROGRESS (3). |
toBeCorrected |
number | Misiones en estado TO_BE_CORRECTED (5). |
toBeReviewed |
number | Misiones en estado COMPLETED (4), es decir enviadas y pendientes de revisión. |
avgCsat |
number | Promedio de missionQuality (1-5) sobre misiones FINALIZED calificadas (0 si no hay ninguna). |
avgCes |
number | Promedio de missionDifficulty (1-5) sobre misiones FINALIZED calificadas (0 si no hay ninguna). |
{ "assigned": 2, "read": 0, "inProgress": 1, "toBeCorrected": 0, "toBeReviewed": 3, "avgCsat": 4.5, "avgCes": 3.8}Sin errores específicos adicionales a los comunes.
GET /missions/{userId}/summary
Sección titulada «GET /missions/{userId}/summary»Igual que el anterior, para un miembro del equipo. Misma respuesta y estructura.
Path param: userId (string, usr_usuario del colaborador).
GET /missions
Sección titulada «GET /missions»Listado paginado de mis misiones (usuario autenticado). Usa nestjs-paginate.
Query params (ver también Convenciones para el formato general de paginación):
| Param | Tipo | Descripción |
|---|---|---|
page, limit |
number | Paginación (defaultLimit 20, maxLimit 100). |
sortBy |
string | Formato campo:ASC|DESC. Columnas ordenables: id, userId, status, missionProgress, assignedDate, readDate, startDate, endDate, deadlineDate, finishedDate, processType, processId, objectiveId. Orden por defecto: createdAt:DESC. |
search |
string | Búsqueda libre sobre missionTitle, missionDescription, createdBy, userId. |
filter.status |
string | Filtro por estado. La pantalla de referencia usa $btw:1,6 (rango ASSIGNED..APPROVED) para excluir FINALIZED y DELETED de la vista activa. Columnas filtrables: id, userId, status, missionProgress, missionQuality, missionDifficulty, createdBy, missionTitle, missionDescription, processType, processId, objectiveId, assignedDate, readDate, startDate, endDate, deadlineDate, finishedDate. |
select |
string | Selección de columnas (JSON:API). |
Response: { data, meta, links } (JSON:API paginado). Cada ítem trae los campos base de la misión más createdByFullName y missionsTasksSummary — no trae missionsTasks, supportFiles, feedbacks ni deliveries completos (para eso usar el detalle).
{ "data": [ { "id": 8937, "userId": "jperez", "processType": null, "processId": null, "objectiveId": null, "missionTitle": "Actualizar manual de onboarding", "missionDescription": "Revisar y actualizar el manual con los cambios de política 2026", "assignedDate": "2026-07-14T09:12:00.000Z", "readDate": null, "startDate": "2026-07-15T00:00:00.000Z", "endDate": "2026-07-25T00:00:00.000Z", "status": 1, "missionProgress": 0, "missionQuality": null, "missionDifficulty": null, "createdBy": "jperez", "createdByFullName": "Juan Pérez", "deadlineDate": "2026-07-25T00:00:00.000Z", "finishedDate": null, "createdAt": "2026-07-14T09:12:00.000Z", "updatedAt": "2026-07-14T09:12:00.000Z", "missionsTasksSummary": { "pending": 2, "sent": 0, "approved": 0, "rejected": 0, "total": 2 } } ], "meta": { "itemsPerPage": 20, "totalItems": 1, "currentPage": 1, "totalPages": 1, "sortBy": [["createdAt", "DESC"]] }, "links": { "current": "..." }}Sin errores específicos adicionales a los comunes.
GET /missions/user/{userId}
Sección titulada «GET /missions/user/{userId}»Igual que el anterior, para un miembro del equipo (misma paginación y forma de respuesta).
Path param: userId (string).
GET /missions/{missionId}
Sección titulada «GET /missions/{missionId}»Detalle completo de una misión: tareas (con archivos de soporte y entregas), archivos de soporte de la misión, entregas, feedbacks y objetivo vinculado.
Path param: missionId (number).
A diferencia de los endpoints de creación/actualización, este no aplica @TransformTo(...) — devuelve la entidad cruda con sus relaciones cargadas. Puede incluir campos adicionales no documentados aquí (por ejemplo createdByUser con el objeto User relacionado completo, o objective con el objeto ReferenceObjective completo). Usa sólo los campos listados abajo; no asumas estabilidad del resto.
Response (campos relevantes para la UI, alineados con el tipo ApiMission de referencia):
| Campo | Tipo | Descripción |
|---|---|---|
id, userId, missionTitle, missionDescription |
— | Datos base. |
status |
number | Ver tabla de estados en Lógica de cliente. |
missionProgress |
number | null | null si no tiene tareas; si tiene, (tareas aprobadas / total) * 100 redondeado. |
assignedDate, readDate, startDate, endDate, deadlineDate, finishedDate |
date | Ver nota sobre deadlineDate vs endDate en Lógica de cliente. |
missionQuality |
number | null | Calificación 1-5 (CSAT) cargada por el evaluador al aprobar. |
missionDifficulty |
number | null | Calificación 1-5 (CES) cargada por el propio ejecutor al enviar. |
createdBy |
string | Username de quien creó la misión. |
createdByFullName |
string | null | Nombre formateado, calculado en el backend. |
processName |
string | Nombre del proceso de evaluación vinculado, si aplica (adjuntado por el repositorio, fuera del alcance de este documento). |
objective.name |
string | Nombre del objetivo vinculado, si aplica. |
supportFiles[] |
{ id, type: 'link'|'attached', fileUrl, fileComment } |
Archivos de soporte de la misión. |
missionsTasks[] |
— | Ver MissionTaskDto abajo, con taskSupportFiles[] y deliveries[] anidados. |
feedbacks[] |
— | Ver FeedbackDto abajo. |
deliveries[] |
— | Entregas a nivel de misión (referenceType: "MISSION"). |
{ "id": 8937, "userId": "jperez", "missionTitle": "Actualizar manual de onboarding", "missionDescription": "Revisar y actualizar el manual con los cambios de política 2026", "assignedDate": "2026-07-14T09:12:00.000Z", "readDate": "2026-07-14T10:00:00.000Z", "startDate": "2026-07-15T00:00:00.000Z", "endDate": "2026-07-25T00:00:00.000Z", "deadlineDate": "2026-07-25T00:00:00.000Z", "finishedDate": null, "status": 3, "missionProgress": 50, "missionQuality": null, "missionDifficulty": null, "createdBy": "lgomez", "createdByFullName": "Laura Gómez", "processName": null, "objective": null, "supportFiles": [ { "id": 401, "type": "link", "fileUrl": "https://drive.example.com/manual-2025.pdf", "fileComment": "Versión anterior" } ], "missionsTasks": [ { "id": 5201, "taskDescription": "Revisar sección de beneficios", "taskStatus": 3, "taskQuality": 4, "taskDifficulty": 2, "taskSupportFiles": [], "deliveries": [] }, { "id": 5202, "taskDescription": "Actualizar sección de políticas de vacaciones", "taskStatus": 1, "taskQuality": null, "taskDifficulty": null, "taskSupportFiles": [], "deliveries": [] } ], "feedbacks": [], "deliveries": []}Errores específicos:
| Código | Cuándo ocurre |
|---|---|
404 |
La misión no existe ("Mission not found"). |
POST /missions
Sección titulada «POST /missions»Crea una misión para el usuario autenticado (self-service).
Body (CreateMissionDto):
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
missionTitle |
string | Sí | Título. |
missionDescription |
string | No* | El DTO sólo exige @IsString() (no @IsNotEmpty); el formulario de referencia tampoco la valida como obligatoria. |
startDate, endDate |
date | Sí | Pese a required: false en el Swagger, el DTO valida @IsNotEmpty @IsDateString — enviarlas siempre. |
processType |
'PROCESS' | 'EVALUATION' |
No | Si se omite y se envía processId, el backend infiere EVALUATION. |
processId, objectiveId |
string | No | Vínculo opcional a un proceso/objetivo de evaluación. La búsqueda de procesos/objetivos (GET /evaluation/type, GET /processes, GET /processes/{id}/objectives) es fuera del alcance de este documento. |
supportFiles[] |
{ type: 'link'|'attached', fileUrl, fileComment? } |
No | Archivos de soporte a nivel de misión. |
missionsTasks[] |
{ taskDescription, taskFiles?/taskSupportFiles? } |
No | Tareas iniciales. taskFiles es alias de taskSupportFiles (mismo formato { type: 'link'|'attached', fileUrl, fileComment? }, string — no confundir con el type numérico de POST /missions/{missionId}/tasks, ver caution abajo). |
Response (MissionResponseDto): misión creada, status = 1 (ASSIGNED) siempre, missionProgress = 0 si se enviaron tareas o null si no.
{ "id": 8940, "userId": "jperez", "processType": null, "processId": null, "objectiveId": null, "missionTitle": "Preparar demo del sprint", "missionDescription": "Armar la demo para el review del viernes", "assignedDate": "2026-07-16T14:00:00.000Z", "readDate": null, "startDate": "2026-07-17T00:00:00.000Z", "endDate": "2026-07-24T00:00:00.000Z", "status": 1, "missionProgress": null, "missionQuality": null, "missionDifficulty": null, "createdBy": "jperez", "deadlineDate": "2026-07-24T00:00:00.000Z", "finishedDate": null}Sin errores específicos adicionales a los comunes (400 si processId no es numérico).
POST /missions/{userId}
Sección titulada «POST /missions/{userId}»Crea una misión para el userId indicado (usada por el responsable para asignar una misión a un miembro de su equipo). Mismo body, DTO y forma de respuesta que POST /missions. Ver caution de autorización en Resumen.
Path param: userId (string).
PATCH /missions/{missionId}
Sección titulada «PATCH /missions/{missionId}»Actualiza estado, fecha fin y/o calificaciones de una misión.
Body (UpdateMissionDto):
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
status |
number | No | Ver tabla de transiciones en Lógica de cliente. Si se envía 3 (IN_PROGRESS) y startDate es futura, responde 400. |
endDate |
date | No | Sólo actualiza endDate; no actualiza deadlineDate (ver caution en Lógica de cliente). |
missionQuality |
number | No | Calificación 1-5 (CSAT), la carga el evaluador al aprobar. |
missionDifficulty |
number | No | Calificación 1-5 (CES), la carga el ejecutor al enviar. |
Response (MissionResponseDto): misión actualizada, incluye missionsTasks/supportFiles/feedbacks (no incluye deliveries, ese campo no está en MissionResponseDto).
Errores específicos:
| Código | Cuándo ocurre |
|---|---|
400 |
Se intenta pasar a IN_PROGRESS (status=3) antes de la startDate ("Cannot set mission to in-progress before start date"). |
404 |
La misión no existe. |
DELETE /missions/{missionId}
Sección titulada «DELETE /missions/{missionId}»Elimina (soft delete) una misión propia o de un miembro del equipo. Marca status = 8 (DELETED) y aplica soft delete (queda fuera de listados por defecto).
Path param: missionId (number).
Response:
{ "id": "8940", "deleted": true }Sin errores específicos adicionales a los comunes.
POST /missions/{missionId}/tasks
Sección titulada «POST /missions/{missionId}/tasks»Agrega una tarea a una misión existente. En la UI de referencia las tareas normalmente se cargan dentro de missionsTasks al crear la misión (POST /missions / POST /missions/{userId}); este endpoint permite agregarlas después.
Body (CreateTaskDto):
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
taskDescription |
string | Sí | — |
taskFiles[] |
{ type: TaskFileType (1=link, 2=attached), fileUrl, fileComment? } |
No | type es numérico aquí (enum TaskFileType), a diferencia de MissionFileInputDto (string 'link'|'attached') usado en la creación de misión y en entregas. Verificar el tipo esperado según el endpoint. |
missionQuality, missionDifficulty |
number (1-5) | No | Presentes en el DTO, pero ver caution abajo — no persisten en la tarea. |
missionQuality/missionDifficulty están declarados en CreateTaskDto, pero el servicio guarda la tarea usando esas mismas claves mientras que la entidad miss_mission_tasks tiene las columnas taskQuality/taskDifficulty — el nombre no coincide y TypeORM descarta el valor al insertar. No uses estos campos para precargar la calificación; calificarla siempre vía PATCH /missions/tasks/{taskId}.
Response (MissionTaskDto): la tarea creada. También recalcula missionProgress de la misión.
{ "id": 5203, "taskDescription": "Grabar la demo", "taskStatus": 1, "taskQuality": null, "taskDifficulty": null, "taskFiles": []}Sin errores específicos adicionales a los comunes.
PATCH /missions/tasks/{taskId}
Sección titulada «PATCH /missions/tasks/{taskId}»Actualiza estado y/o calificaciones de una tarea. Es el único camino real para fijar taskQuality/taskDifficulty (ver caution arriba).
Path param: taskId (number).
Body (UpdateTaskDto):
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
taskStatus |
number | No | Ver TaskStatus en Lógica de cliente. |
taskQuality |
number (1-5) | No | Calificación del evaluador al aprobar la tarea. |
taskDifficulty |
number (1-5) | No | Autocalificación del ejecutor al marcarla como enviada. |
Response (MissionTaskDto): tarea actualizada. También recalcula missionProgress de la misión.
Sin errores específicos adicionales a los comunes (404 si la tarea no existe).
DELETE /missions/tasks/{taskId}
Sección titulada «DELETE /missions/tasks/{taskId}»Elimina (soft delete) una tarea y recalcula el progreso de la misión.
Response:
{ "id": "5203", "deleted": true }Sin errores específicos adicionales a los comunes.
POST /missions/{missionId}/deliveries
Sección titulada «POST /missions/{missionId}/deliveries»Crea una entrega a nivel de misión (para misiones sin tareas). Sólo aplica cuando la misión no tiene missionsTasks.
Body (CreateDeliveryDto):
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
deliveryComment |
string | Sí | Comentario de la entrega. |
deliveryFiles[] |
{ type: 'link'|'attached', fileUrl, fileComment? } |
No | — |
rejectionComment |
string | No | Normalmente no se envía al crear; se agrega después vía PATCH cuando el evaluador rechaza. |
Response (DeliveryDto): status = 1 (SENT) siempre al crear.
{ "id": 3010, "missionId": 8937, "taskId": null, "referenceType": "MISSION", "status": 1, "deliveryComment": "Listo, adjunto el documento actualizado", "rejectionComment": null, "deliveryFiles": [ { "id": 601, "type": "attached", "fileUrl": "deliveries/manual-v2.pdf", "fileComment": "manual-v2.pdf" } ], "createdAt": "2026-07-20T16:00:00.000Z", "updatedAt": "2026-07-20T16:00:00.000Z"}Errores específicos:
| Código | Cuándo ocurre |
|---|---|
400 |
Falta deliveryComment. |
404 |
La misión no existe. |
POST /missions/{missionId}/tasks/{taskId}/deliveries
Sección titulada «POST /missions/{missionId}/tasks/{taskId}/deliveries»Igual al anterior, pero para una tarea puntual dentro de una misión con tareas. referenceType = "TASK".
Path params: missionId, taskId (number).
Errores específicos: además de los del endpoint anterior, 404 si la tarea no pertenece a la misión.
PATCH /missions/{missionId}/deliveries/{deliveryId}
Sección titulada «PATCH /missions/{missionId}/deliveries/{deliveryId}»Actualiza una entrega: cambia su estado (con transiciones validadas) y/o edita comentario/archivos/comentario de rechazo.
Path params: missionId, deliveryId (number).
Body (UpdateDeliveryDto):
| Campo | Tipo | Obligatorio | Enum | Descripción |
|---|---|---|---|---|
status |
number | No | 1 SENT, 2 RECEIVED, 3 APPROVED, 4 REJECTED |
Transiciones válidas: SENT→RECEIVED, RECEIVED→APPROVED|REJECTED. Cualquier otra combinación responde 400. |
deliveryComment |
string | No | — | Sólo se persiste si el estado actual (antes del patch) es SENT. |
deliveryFiles[] |
— | No | — | Ídem: sólo se agregan archivos si el estado actual es SENT. |
rejectionComment |
string | No | — | Se puede actualizar en cualquier estado, incluso sin cambiar status — así es como el flujo de referencia adjunta el motivo de rechazo de una misión sin tareas (sin mover la entrega a REJECTED). |
Errores específicos:
| Código | Cuándo ocurre |
|---|---|
400 |
Transición de estado inválida, o se intenta pasar a REJECTED (referencia MISSION) sin rejectionComment (ni uno previo en la entrega). |
404 |
La entrega no existe o no pertenece a la misión. |
POST /missions/{missionId}/feedbacks
Sección titulada «POST /missions/{missionId}/feedbacks»Agenda un feedback (presencial o virtual) para una misión.
Body (CreateFeedbackDto):
| Campo | Tipo | Obligatorio | Enum | Descripción |
|---|---|---|---|---|
feedbackType |
number | Sí | 1 inPerson, 2 virtual |
— |
feedbackScheduledDate |
date | Sí | — | Fecha/hora agendada. |
feedbackComment |
string | No | — | — |
feedbackMeetUrl |
string | No | — | Link de la reunión virtual, si feedbackType = 2. |
Response (FeedbackDto): feedbackStatus = 1 (PLANNED) siempre al crear.
{ "id": 701, "missionId": 8937, "feedbackType": "inPerson", "feedbackStatus": 1, "feedbackScheduledDate": "2026-07-22T15:00:00.000Z", "feedbackComment": "Revisar el resultado final juntos", "feedbackMeetUrl": null}Sin errores específicos adicionales a los comunes.
POST /missions/feedbacks
Sección titulada «POST /missions/feedbacks»Variante en lote: crea el mismo feedback para varias misiones a la vez.
Body (CreateBulkFeedbackDto): igual a CreateFeedbackDto pero sin missionId, con missionIds: number[] obligatorio en su lugar.
Response: array de FeedbackDto (uno por misión).
La pantalla de referencia (AssignFeedback.vue) permite seleccionar varias misiones en el mismo formulario, pero no usa este endpoint en lote — dispara N llamadas en paralelo a POST /missions/{missionId}/feedbacks, una por misión seleccionada. El endpoint en lote existe y funciona (createBulkFeedback reutiliza createFeedback internamente), pero no está en uso.
PATCH /missions/feedbacks/{feedbackId}
Sección titulada «PATCH /missions/feedbacks/{feedbackId}»Actualiza estado y/o fecha de un feedback.
Body (UpdateFeedbackDto):
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
feedbackStatus |
number | No | 1 PLANNED, 2 DONE. |
feedbackScheduledDate |
date | No | — |
Response (FeedbackDto): feedback actualizado.
Sin errores específicos adicionales a los comunes (404 si el feedback no existe).
GET /missions/{missionId}/activity
Sección titulada «GET /missions/{missionId}/activity»Bitácora de auditoría de la misión (creación, cambios de estado, tareas, feedbacks), orden occurredAt DESC.
Response: array de eventos, sin sobre.
| Campo | Tipo | Descripción |
|---|---|---|
entityType |
'mission' | 'task' | 'feedback' |
Entidad afectada. |
entityId |
number | Id de esa entidad. |
eventType |
enum | missionCreated, missionUpdated, taskAdded, taskUpdated, taskDeleted, feedbackScheduled, feedbackUpdated, statusChanged. |
previousStatus, newStatus |
string | null | Estado anterior/nuevo (como string), sólo en statusChanged/taskUpdated. |
performedById, performedByName |
string | null | Quién ejecutó la acción (null = sistema). |
occurredAt |
date | — |
comments |
string[] | Comentario asociado (p. ej. motivo de rechazo), si aplica. |
metadata |
object | Datos adicionales según el evento (p. ej. deliveryId, taskId). |
[ { "id": 9001, "missionId": 8937, "entityType": "mission", "entityId": 8937, "eventType": "statusChanged", "previousStatus": "1", "newStatus": "3", "performedById": "jperez", "performedByName": "jperez", "occurredAt": "2026-07-17T09:00:00.000Z", "comments": [], "metadata": {} }]Sin errores específicos adicionales a los comunes (404 si la misión no existe).
Lógica de cliente
Sección titulada «Lógica de cliente»Estados de una misión (MissionStatusEnum)
Sección titulada «Estados de una misión (MissionStatusEnum)»| Valor | Significado backend | Texto sugerido (vista del ejecutor) | Texto sugerido (vista del evaluador) | Color sugerido |
|---|---|---|---|---|
1 |
ASSIGNED | Asignada | Asignada | neutral |
2 |
READ | Leída | Leída | neutral |
3 |
IN_PROGRESS | En progreso | En progreso | info |
4 |
COMPLETED | Completada / en revisión | Por revisar | success |
5 |
TO_BE_CORRECTED | Por corregir | Por corregir | error |
6 |
APPROVED | Aprobada (falta feedback) | Aprobada | success |
7 |
FINALIZED | Finalizada | Finalizada | success |
8 |
DELETED | — (excluir de listados y contadores) | — | — |
Estados de una tarea (TaskStatus)
Sección titulada «Estados de una tarea (TaskStatus)»| Valor | Significado | Texto sugerido | Color sugerido |
|---|---|---|---|
1 |
PENDING | Pendiente | neutral |
2 |
SENT | Enviada | info |
3 |
APPROVED | Aprobada | success |
4 |
REJECTED | Rechazada | error |
Estados de una entrega (DeliveryStatusCode)
Sección titulada «Estados de una entrega (DeliveryStatusCode)»| Valor | Significado | Transición siguiente permitida |
|---|---|---|
1 |
SENT | → RECEIVED |
2 |
RECEIVED | → APPROVED o REJECTED |
3 |
APPROVED | (final) |
4 |
REJECTED | (final) |
En el flujo de referencia, el evaluador no siempre mueve la entrega por sus estados formales: para rechazar una misión sin tareas sólo adjunta rejectionComment a la última entrega (sin status) y cambia el status de la misión a TO_BE_CORRECTED. Tratar DeliveryStatusCode como informativo/de auditoría, no como el disparador único del rechazo.
Estados de un feedback (FeedbackStatus)
Sección titulada «Estados de un feedback (FeedbackStatus)»| Valor | Significado | Texto sugerido |
|---|---|---|
1 |
PLANNED | Planeada |
2 |
DONE | Realizada |
Tipo de feedback
Sección titulada «Tipo de feedback»| Valor | Significado |
|---|---|
1 / inPerson |
Presencial |
2 / virtual |
Virtual (requiere feedbackMeetUrl) |
Qué mostrar/habilitar según el estado (vista del ejecutor — “Mis misiones”)
Sección titulada «Qué mostrar/habilitar según el estado (vista del ejecutor — “Mis misiones”)»- Botón de acción de la tabla: “Detalles” si
statusesASSIGNED,READ,COMPLETEDoAPPROVED; “Continuar” en cualquier otro caso (IN_PROGRESS,TO_BE_CORRECTED). - Al abrir el detalle desde
ASSIGNED: el cliente dispara automáticamentePATCH { status: READ }antes de mostrar el detalle (no requiere acción explícita del usuario). - Footer “Iniciar misión”: visible sólo si
statusesASSIGNEDoREAD. DisparaPATCH { status: IN_PROGRESS }; si la misión aún no llegó a sustartDate, mostrar el error del backend en vez de reintentar. - Footer “Enviar”: visible sólo si
statusesIN_PROGRESS,TO_BE_CORRECTEDoCOMPLETED.- Si la misión tiene tareas: sólo se pueden seleccionar/enviar tareas en estado
PENDING(1) oREJECTED(4); lasSENT/APPROVEDaparecen ya marcadas y deshabilitadas. Antes de habilitar el envío hay que validar que cada tarea seleccionada tenga comentario de entrega. Al seleccionar una tarea se abre el modal de dificultad (1-5,taskDifficulty) — es obligatorio elegir una calificación para poder confirmar la selección. - Si la misión no tiene tareas: se requiere comentario de entrega antes de habilitar el envío; al confirmar se abre el modal de dificultad de la misión (
missionDifficulty, obligatorio) antes de mandar elPATCH { status: COMPLETED, missionDifficulty }.
- Si la misión tiene tareas: sólo se pueden seleccionar/enviar tareas en estado
- Sección de corrección (
status = TO_BE_CORRECTED): mostrar elrejectionCommentde la última entrega/tarea rechazada antes de permitir un nuevo envío.
Qué mostrar/habilitar según el estado (vista del evaluador — misiones de un miembro del equipo)
Sección titulada «Qué mostrar/habilitar según el estado (vista del evaluador — misiones de un miembro del equipo)»- Botones “Aprobar” / “Rechazar” a nivel de misión: sólo para misiones sin tareas, y sólo si
statusno esASSIGNED,READ,IN_PROGRESS,APPROVEDniTO_BE_CORRECTED(en la práctica,COMPLETED). Aprobar exige seleccionar una calificación (missionQuality, 1-5) antes de habilitar el botón de confirmar; el nuevo estado esAPPROVEDsi la misión tiene algún feedbackPLANNED, oFINALIZEDsi no tiene ninguno. - Rechazar misión sin tareas: requiere comentario obligatorio; el flujo agrega el comentario a la última entrega (
PATCH deliveries/{id} { rejectionComment }) y cambia la misión aTO_BE_CORRECTED. - Aprobar/rechazar por tarea (misiones con tareas, tarea en
SENT): el botón “Calificar” (estrella) es obligatorio antes de habilitar “Aprobar”/“Rechazar” (ambos deshabilitados hasta quetask.taskQualitytenga valor). Rechazar exige comentario. Al enviar todas las revisiones seleccionadas, el nuevo estado de la misión se calcula así:- alguna tarea quedó
REJECTED→TO_BE_CORRECTED. - todas quedaron
APPROVED→APPROVED(si hay feedbackPLANNED) oFINALIZED(si no hay ninguno). - quedan tareas
PENDING/SENTsin revisar →IN_PROGRESS.
- alguna tarea quedó
- Botón “Eliminar misión”: siempre visible en el detalle (con o sin tareas), abre modal de confirmación simple.
- Feedback “Marcar como realizado”: visible sólo en feedbacks con
feedbackStatus = PLANNED. DisparaPATCH feedbacks/{id} { feedbackStatus: DONE }; si la misión estaba enAPPROVED, además disparaPATCH mission { status: FINALIZED }para cerrarla.
Nota sobre endDate vs deadlineDate
Sección titulada «Nota sobre endDate vs deadlineDate»La UI de referencia muestra siempre deadlineDate como “fecha límite/fin”, nunca el campo endDate crudo. deadlineDate se fija una sola vez, al crear la misión (copia de endDate en ese momento); PATCH /missions/{missionId} sólo puede modificar endDate, no deadlineDate. Si se expone edición de fecha fin en la app, considerar que el valor mostrado en el resto de la UI de referencia no se actualizaría.
Validaciones previas a cada acción
Sección titulada «Validaciones previas a cada acción»- Antes de “Iniciar misión”: la misión debe estar en
ASSIGNED/READy sustartDateno puede ser futura (el backend rechaza con400si lo es). - Antes de “Enviar” una misión sin tareas: comentario de entrega no vacío + calificación de dificultad seleccionada.
- Antes de enviar tareas: comentario de entrega no vacío por cada tarea seleccionada + calificación de dificultad por tarea.
- Antes de aprobar (misión o tarea): calificación de calidad (
missionQuality/taskQuality) seleccionada. - Antes de rechazar (misión o tarea): comentario de rechazo no vacío.
- Antes de agendar feedback presencial: hora seleccionada (
startTime); para virtual, no se exige el link (feedbackMeetUrles opcional en el DTO), pero si se ingresa se envía.
Estados vacíos y casos borde
Sección titulada «Estados vacíos y casos borde»- Sin misiones activas:
GET /missionsconfilter.status=$btw:1,6devuelvedata: []— mostrar estado vacío (“Aún no tienes misiones activas”). - Misión sin tareas y sin entregas:
missionsTasksydeliveriesllegan como arrays vacíos; no mostrar el bloque de progreso (sólo aplica simissionsTasks.length > 0). missionProgress = null: ocurre cuando la misión no tiene tareas; no mostrar la barra de progreso o mostrarla en0sin dato.- Feedback sin
feedbackMeetUrl: ocultar el botón de “unirse a la reunión” si el campo viene vacío/null. processName/objectiveausentes: mostrar “Independiente” (sin vínculo a proceso) en vez de un campo vacío.