---
id: collections-post-id-undo
title: "POST /api/collections/:id/undo"
domain: collections
kind: api-method
http: "POST /api/collections/:id/undo"
---

# POST /api/collections/:id/undo {#collections-post-id-undo}

## Сводка

| Поле | Значение |
|---|---|
| **HTTP** | `POST /api/collections/:id/undo` |
| **Auth** | `—` |
| **Scope токена** | `read_write` |
| **PG-функции** | `api.undo_last_operation` |
| **Таблицы** | `collection_block`, `collection_edge`, `collection` |
| **SRM** | SRM-364 |
| **RP (права)** | — |
| **Файл роута** | `server/routes/collections.js` |
| **Статус** | done |

**Аргументы запроса** (best-effort из хендлера; путь-параметры опущены):

_аргументов не обнаружено (подтвердить вручную по `server/routes/collections.js`)_

**Коды ответов/ошибок** (из хендлера): `200` — _уточнить причины вручную_

**Scope токена:** `read_write`. Требует прав collection admin (как декомпозиция).

Откатывает последнюю операцию коллекции над `collection_block` / `collection_edge` / `collection` к прежнему состоянию. Инверсия строится из SCD4-архивов (`*_archive`, читаются append-only) последней операции по её `op_id`; живые таблицы переписываются в FK-безопасном порядке. Сам откат ловится триггерами архива под новым `op_id` (`op_name = COLLECTION_UNDO`), поэтому undo сам логируется, а повторный вызов = redo (откат отката).

**Риск:** `IRREVERSIBLE` (op `COLLECTION_UNDO`). Для Bearer-токена глобальный confirm-гейт требует `{"confirm": true}` в теле — иначе `409`.

**Тело запроса** (`Content-Type: application/json`): собственных полей нет. Для агента — только `{"confirm": true}` (обязательно, иначе confirm-гейт вернёт `409`).

**Заголовки:**

| Заголовок | Описание |
|---|---|
| `If-Match: <updated_at>` | Защита от TOCTOU. Если коллекция изменилась с момента снятия снимка — `412 Precondition Failed` (ранний `guardIfMatch`; PG-backstop `STALE` тоже → `412`) |

**Пример:**

```
POST /api/collections/{id}/undo
Authorization: Bearer <token>
If-Match: <updated_at>
Content-Type: application/json

{"confirm": true}
```

Ответ `200` — откат выполнен:
```json
{"undone": true, "op_name": "COLLECTION_BLOCK_DECOMPOSE", "op_id": "uuid"}
```

Ответ `200` — откатывать нечего:
```json
{"undone": false, "reason": "no_ops"}
```

**Коды ошибок:** `409` — нужен `{"confirm": true}` (confirm-гейт); `412` — конфликт `If-Match` / `STALE`; `403` — нет прав collection admin; `404` — коллекция не найдена (или в корзине).

<!-- gen:start:related -->
## Связанные
- Экраны: [Редактор коллекции](../screens/collection-editor.md#collections-screen-collection-editor)
- [Конвенции](../../../shared/conventions.md#conventions) · [Роли](../../../shared/roles.md#roles) · [Ошибки](../../../shared/errors.md#errors) · [Глоссарий](../../../shared/glossary.md#glossary)
<!-- gen:end:related -->

---

Human view: https://docs.vnimanie.ai/specbuilder/v1/domains/collections/api/post-id-undo/