Dependencias

El orden entre tareas: qué tiene que estar terminado antes de que otra cosa pueda empezar.

La dirección

Una dependencia relaciona dos tareas del mismo proyecto: la bloqueante va primero, la bloqueada espera. En todos los endpoints la tarea de la URL es la bloqueada, y la bloqueante viaja en el cuerpo o en la ruta. Así no hay forma de invertirla por confundir dos campos con nombres parecidos.

Al consultarlas verás las dos direcciones: blockedBy es lo que tiene que terminar antes de esta tarea, y blocks lo que está esperando a que termine.

Cuándo una tarea está bloqueada

blocked no se guarda en ningún sitio: se calcula. Una tarea está bloqueada mientras alguna de sus bloqueantes siga sin terminar — es decir, mientras no esté en done ni en cancelled.

La consecuencia práctica es que cerrar la última bloqueante desbloquea sola a la que esperaba, sin ninguna llamada extra. El campo viaja en todas las tareas, así que filtrar «lo que se puede empezar hoy» es un listado normal:

Ejemplo
# Tareas listas para empezar: sin terminar y sin nada por delante.
curl "$PLANELY_URL/api/v1/tasks?status=todo" \
  -H "Authorization: Bearer $PLANELY_API_KEY" \
  | jq '[.tasks[] | select(.blocked == false)]'

Las tres reglas

Las comprueba el servidor en cada alta, y ninguna se puede saltar:

  • Mismo proyecto. Una tarea de otro proyecto responde 404, igual que si no existiera: una key no debe poder averiguar qué hay fuera del suyo.
  • Nada se bloquea a sí mismo.
  • Sin círculos. Se comprueba contra el grafo entero, no solo contra el par: el círculo suele cerrarse a varios saltos de distancia. Cuando ocurre, la respuesta es 409 dependency_cycle y no se registra nada.

Listar las dependencias de una tarea

GET/api/v1/tasks/{taskId}/dependenciesLectura (cualquier key)

Las dos direcciones: blockedBy (lo que tiene que terminar antes) y blocks (lo que espera a esta tarea).

  • Solo aparecen tareas vivas: una que esté en la papelera desaparece de las listas sin que se pierda la relación, y vuelve al restaurarla.
Request
curl https://planely.dev/api/v1/tasks/9b2f6c3a-…/dependencies \
  -H "Authorization: Bearer $PLANELY_API_KEY"
200 OK
{
  "blockedBy": [
    { "id": "1a2b…", "title": "Diseñar el esquema", "status": "in_progress" }
  ],
  "blocks": [
    { "id": "3c4d…", "title": "Publicar la nota de versión", "status": "todo" }
  ]
}

Añadir una dependencia

POST/api/v1/tasks/{taskId}/dependenciesPermiso: Editar tareas

Registra que blockerId debe terminar antes que la tarea de la URL. Devuelve el grafo ya actualizado.

Cuerpo (JSON)

  • blockerIdstringobligatorio

    Tarea que va primero. Del mismo proyecto y distinta de la de la URL

  • Repetir la misma dependencia no es un error: el par es la clave, así que la segunda llamada no cambia nada y responde igual.
  • Una dependencia que cerraría un círculo responde 409 dependency_cycle, aunque el círculo se cierre a varios saltos de distancia.
  • Una tarea de otro proyecto responde 404, igual que si no existiera.
Request
curl -X POST https://planely.dev/api/v1/tasks/9b2f6c3a-…/dependencies \
  -H "Authorization: Bearer $PLANELY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "blockerId": "1a2b3c4d-…" }'
201 Created
{
  "blockedBy": [
    { "id": "1a2b…", "title": "Diseñar el esquema", "status": "in_progress" }
  ],
  "blocks": [
    { "id": "3c4d…", "title": "Publicar la nota de versión", "status": "todo" }
  ]
}

Quitar una dependencia

DELETE/api/v1/tasks/{taskId}/dependencies/{blockerId}Permiso: Editar tareas

Elimina esa relación. Las tareas no se tocan: solo deja de haber una espera entre ellas.

  • Idempotente: quitar algo que ya no está también responde 204.
Request
curl -X DELETE https://planely.dev/api/v1/tasks/9b2f6c3a-…/dependencies/1a2b3c4d-… \
  -H "Authorization: Bearer $PLANELY_API_KEY"
204 No Content
(sin cuerpo)