---
id: projects-get-project-graph
title: "GET /api/projects/:id/graph — Граф проекта (для агента)"
domain: projects
kind: api-method
http: "GET /api/projects/:id/graph"
---

# GET /api/projects/:id/graph — Граф проекта (для агента) {#projects-get-project-graph}

## Сводка

| Поле | Значение |
|---|---|
| **HTTP** | `GET /api/projects/:id/graph` |
| **Auth** | `optionalAuth, requireProjectAccess` — гость + авторизованный, доступ к проекту (read/write) |
| **Scope токена** | `read` |
| **PG-функции** | `api.get_project_graph` |
| **Таблицы** | `project`, `project_node`, `project_edge`, `project_node_role` |
| **SRM** | SRM-343 |
| **RP (права)** | — |
| **Файл роута** | `server/routes/projects.js` |
| **Статус** | done |

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

| Аргумент | Где | Обяз. | Заметка |
|---|---|---|---|
| `diff_from` | query | | _подтвердить_ |
| `format` | query | | _подтвердить_ |
| `view` | query | | _подтвердить_ |

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

Чтение — достаточно токена со scope `read` (см. [Конвенции](../../../shared/conventions.md#conventions)). Это основной агентный read для структуры проекта. `requireProjectAccess` проверяет доступ владельца токена; если проект не найден или невидим — `404`. Ноды всегда отдаются в топологическом порядке (`server/agent/toposort.js`), так что зависимости идут раньше зависимых блоков.

**Query-параметры:**

| Параметр | Значения | Назначение |
|---|---|---|
| `view` | `summary` (по умолч.) · `full` | `summary` — только счётчики нод/рёбер, роли и версия; `full` — все ноды и рёбра текстом |
| `diff_from` | `<updated_at>` | Вернуть только список нод, изменившихся после этой версии (инкрементальный опрос) |
| `format` | `md` | Альтернатива заголовку `Accept: text/markdown` (только для токена) |

**Пример запроса (полный граф, Markdown):**

```bash
curl "https://specbuilder.vnimanie.ai/api/projects/a1b2c3d4-1111-4aaa-9bbb-000000000001/graph?view=full" \
  -H "Authorization: Bearer tak_..." \
  -H "Accept: text/markdown"
```

**Ответ `200` (Markdown-зеркало, `view=full`):** ноды в топо-порядке, рёбра отсортированы (`server/agent/markdown.js → serializeGraph`):

```
# graph
version: 2026-06-20T11:42:08.512Z

## Nodes
- n1: Сбор требований
- n2: Проектирование схемы данных

## Edges
- n1 -> n2
```

При `view=summary` тело короче — `nodes`/`edges` числом и список ролей, без перечисления нод.

**Ответ `200` (JSON, cookie-клиент или токен без markdown):** `version` + `view` + сами массивы (`server/routes/projects.js:181`):

```json
{
  "version": "2026-06-20T11:42:08.512Z",
  "view": "summary",
  "nodes": [ { "id": "n1", "label": "Сбор требований" } ],
  "edges": [ { "source_id": "n1", "target_id": "n2" } ],
  "roles": [ { "id": "ba", "label": "Бизнес-аналитик" } ]
}
```

**Инкрементальный опрос.** Полный markdown-ответ несёт `ETag` (= версия графа, максимум по `updated_at` нод); повтор с `If-None-Match: "<version>"` → `304` без тела, если граф не менялся. Если граф мог измениться, передайте `diff_from=<прошлая версия>` — вернётся только список изменившихся нод (JSON: `{ "from", "to", "changed": ["n2"], "removed": null }`; markdown: строки `changed: n2`, удаления в v1 не отслеживаются). Так агент тянет полный `view=full` лишь когда `304` не пришёл, а точечно — только изменившиеся блоки.

<!-- gen:start:related -->
## Связанные
- [Конвенции](../../../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/projects/api/get-project-graph/