API de archivo de proyectos
Cada proyecto tiene una marca de tiempo archivedAt (epoch en ms, o null para un proyecto activo) — un
estado de ciclo de vida reversible, no una eliminación suave. {projectId} es el código del
proyecto (por ejemplo ACME) en todo lo que sigue.
Archivar hace que el contenido de un proyecto sea de solo lectura, mientras su administración sigue siendo accesible:
- Cada ruta existente sigue siendo totalmente legible: la página de detalle, las suites,
casos, ejecuciones, planes, hitos, defectos, adjuntos y exportaciones de un proyecto archivado
siguen funcionando exactamente igual que en un proyecto activo.
GET /api/v1/projects/{projectId}sigue devolviendo200, con unarchivedAtno nulo. - Cada escritura sobre el contenido es rechazada con
409 { code: "project_archived" }— ver Las escrituras de contenido se rechazan mientras está archivado más abajo. - No libera un asiento de proyecto. Una organización en su
projectLimitque archiva un proyecto sigue siendo rechazada al crear uno nuevo con409 { code: "project_limit_exceeded" }— eliminar sigue siendo la única forma de liberar un asiento.
Cambio disruptivo: la lista muestra solo activos por defecto
Sección titulada «Cambio disruptivo: la lista muestra solo activos por defecto»GET /api/v1/projects ahora oculta los proyectos archivados por defecto. Este es un cambio
deliberado a un contrato público ya publicado: un integrador que sondea este endpoint empieza a recibir
menos filas en cuanto algo se archiva en esa organización. Es observacionalmente inerte el día en que se
publica, porque ningún proyecto puede archivarse hasta que esta capacidad exista — pero surte efecto de
inmediato en cuanto tú (o alguien de tu organización) archiva un proyecto.
Pasa el parámetro de consulta opcional status para cambiar lo que devuelve la lista:
Valor de status | Resultado |
|---|---|
| ausente, vacío o solo tokens desconocidos | Solo activos — el nuevo valor por defecto |
active | Solo activos (igual que el valor por defecto) |
archived | Solo archivados |
active,archived (en cualquier orden) | Ambos — el comportamiento previo completo |
status es un conjunto de tokens separados por comas, igual que los filtros runs/defects/
milestones/cases que ya existen en este endpoint. Se combina con la paginación, q, memberUlid y
cualquier otro filtro, y el total devuelto siempre coincide con el filtro aplicado (nunca un conteo
fantasma de una consulta sin filtrar).
# Solo lo que cambió con el flip: proyectos archivadoscurl -sS -H "Authorization: Bearer $PROBARA_API_TOKEN" \ "https://app.probara.net/api/v1/projects?status=archived"
# Todo, exactamente como antes de este cambiocurl -sS -H "Authorization: Bearer $PROBARA_API_TOKEN" \ "https://app.probara.net/api/v1/projects?status=active,archived"Cualquier otro consumidor de la lista de proyectos hereda este mismo valor por defecto sin ningún
trabajo extra de tu parte: el directorio web, el selector de proyectos y cualquier otro lector interno
resuelven a solo-activos a menos que también pasen status explícitamente.
Archivar un proyecto
Sección titulada «Archivar un proyecto»/api/v1/projects/{projectId}/archiveSin cuerpo de solicitud. Devuelve 200 con el proyecto actualizado (ver
Acceso a proyectos para el recurso hermano; este es el objeto de
proyecto plano con su campo archivedAt).
{ "ulid": "01J...PROJECT", "name": "Acme", "id": "ACME", "description": null, "avatarKey": null, "avatarVersion": 0, "createdAt": 1700000000000, "updatedAt": 1700000005000, "archivedAt": 1700000005000}Idempotente: archivar un proyecto ya archivado responde 200 sin cambiar la marca de tiempo
almacenada — un doble clic o una solicitud reintentada se comportan igual que una sola llamada, y este
endpoint nunca responde 409.
Autorización
Sección titulada «Autorización»Misma restricción que PATCH/DELETE sobre un proyecto: solo un propietario o administrador de
la organización puede archivar. Un member o viewer es rechazado con 403 forbidden, dejando
archivedAt sin cambios. Un {projectId} desconocido, o uno que pertenece a otra organización, responde
404 not_found.
Desarchivar un proyecto
Sección titulada «Desarchivar un proyecto»/api/v1/projects/{projectId}/unarchiveSin cuerpo de solicitud. Devuelve 200 con el proyecto actualizado, archivedAt: null. Mismas reglas de
idempotencia y autorización que archivar, en espejo: desarchivar un proyecto que no está archivado tiene
éxito y deja archivedAt como null.
Ejemplo
Sección titulada «Ejemplo»curl -sS -X POST \ -H "Authorization: Bearer $PROBARA_API_TOKEN" \ "https://app.probara.net/api/v1/projects/ACME/archive"Las escrituras de contenido se rechazan mientras está archivado
Sección titulada «Las escrituras de contenido se rechazan mientras está archivado»El contenido de un proyecto archivado queda congelado. Cualquier escritura sobre él — crear una suite, actualizar un caso de prueba, iniciar una ejecución, guardar el resultado de una ejecución, vincular un defecto, mutar un plan de pruebas, escribir el valor de un campo personalizado, crear un comentario, subir un adjunto o un avatar, y cualquier otra mutación de contenido con alcance de proyecto — es rechazada:
{ "error": { "code": "project_archived", "message": "project is archived" }}Estado 409. Esto aplica tanto si la escritura apunta directamente al proyecto
(/api/v1/projects/{projectId}/...) como si apunta a una entidad alcanzada por su propio ULID
(/api/v1/test-cases/{ulid}, /api/v1/runs/{ulid}, etc.) — el rechazo se aplica donde vive el
dato, no donde apunta la URL, así que no existe ruta que lo evite. Una subida de adjunto rechazada
de esta forma nunca llega al almacenamiento: no queda ningún objeto parcial u huérfano. Esto aplica
a todo tipo de credencial, incluido un token de API de la organización.
El orden del rechazo es fijo: un proyecto que no existe (o pertenece a otra organización) responde
404 antes de consultar el estado de archivado; un llamador sin acceso a un proyecto privado
responde 403; solo un llamador que de otro modo habría sido admitido llega al 409. El estado
de archivado nunca filtra la existencia de un proyecto que el llamador no puede ver.
Este es un cambio disruptivo a un contrato público ya publicado, y a diferencia del cambio de valor por defecto de la lista anterior, no es observacionalmente inerte: cualquier proyecto archivado antes de este cambio empieza a rechazar escrituras en el momento en que se publica.
Operaciones administrativas exentas
Sección titulada «Operaciones administrativas exentas»Estas operaciones administran el proyecto en sí, no su contenido, y siguen funcionando mientras el proyecto está archivado:
| Operación | Ruta |
|---|---|
| Desarchivar | POST /api/v1/projects/{projectId}/unarchive |
| Eliminar | DELETE /api/v1/projects/{projectId} |
| Archivar (re-archivado idempotente) | POST /api/v1/projects/{projectId}/archive |
| Actualizar (renombrar/redescribir) | PATCH /api/v1/projects/{projectId} |
| Gestión de acceso (modo, membresía, propiedad) | PATCH /api/v1/projects/{projectId}/access y sus subrutas de miembro/grupo |
El avatar del proyecto es contenido, no administración, y no está exento:
POST/DELETE /api/v1/projects/{projectId}/avatar se rechazan con 409 como cualquier otra
escritura.
Reintentos idempotentes
Sección titulada «Reintentos idempotentes»Una escritura rechazada con 409 project_archived bajo una Idempotency-Key se registra como
cualquier otra respuesta por debajo de 500, así que un reintento idéntico dentro del TTL de la
clave repite el mismo 409 registrado — incluso después de que el proyecto haya sido
desarchivado. Envía una clave nueva y sin usar para obtener el resultado posterior al
desarchivado. Ver Idempotencia para el contrato general.
Limitación conocida
Sección titulada «Limitación conocida»La eliminación definitiva (DELETE /api/v1/projects/{projectId}) no tiene relación con archivar y sigue
siendo la única vía de eliminación irreversible. Eliminar no libera espacio de almacenamiento — la imagen
del proyecto y cada adjunto de paso descendiente sobreviven a la cascada. Esto es preexistente, está fuera
del alcance aquí, y se rastrea como su propio cambio futuro.