Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions docs/project-goals-achievements-workspace-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Project Goals and Achievements Workspace API

## Назначение

API дополняет безопасный React workspace отдельным CRUD целей и достижений проекта.
Он не использует `ProjectDetailSerializer` и `check_related_fields_update()`, поэтому
изменение вложенного объекта не запускает массовую замену legacy-связей проекта.

Модели `ProjectGoal` и `Achievement` остаются прежними. Миграция не требуется.
Legacy endpoints также сохраняют существующий контракт.

## Endpoints

| Метод | URL | Назначение |
| --- | --- | --- |
| `GET` | `/projects/<project_id>/workspace/goals/` | Список целей проекта |
| `POST` | `/projects/<project_id>/workspace/goals/` | Создание цели |
| `PATCH` | `/projects/<project_id>/workspace/goals/<goal_id>/` | Частичное изменение цели |
| `DELETE` | `/projects/<project_id>/workspace/goals/<goal_id>/` | Удаление цели |
| `GET` | `/projects/<project_id>/workspace/achievements/` | Список достижений проекта |
| `POST` | `/projects/<project_id>/workspace/achievements/` | Создание достижения |
| `PATCH` | `/projects/<project_id>/workspace/achievements/<achievement_id>/` | Частичное изменение достижения |
| `DELETE` | `/projects/<project_id>/workspace/achievements/<achievement_id>/` | Удаление достижения |

Все endpoints требуют аутентификацию.

## Контракты

Цель:

```json
{
"id": 12,
"title": "Подготовить прототип",
"completion_date": "2026-12-15",
"responsible": 42
}
```

`title` обязателен и после удаления крайних пробелов не может быть пустым.
`completion_date` может быть `null`. `responsible` должен быть руководителем или
участником именно проекта из URL. Поля `project` и `is_done` этот контракт не
принимает.

Достижение:

```json
{
"id": 7,
"title": "Победа в конкурсе",
"year": 2025
}
```

`title` обязателен и не может состоять из пробелов. `year` — целое число от 2000
до текущего года включительно. Модель исторически хранит это значение в строковом
поле `Achievement.status`; workspace serializer выполняет явное преобразование,
не меняя legacy-модель и API.

## Доступ и изоляция

| Пользователь | Публичный опубликованный проект | Свой private/draft | Чужой private/draft | Изменение |
| --- | --- | --- | --- | --- |
| Руководитель | чтение | чтение | нет | свой проект |
| Collaborator | чтение | чтение своего проекта | нет | нет |
| Авторизованный посторонний | чтение | нет | нет | нет |
| Staff/superuser | чтение | чтение | чтение | административное |

Видимость совпадает с `GET /projects/<id>/workspace/`: публичным считается только
проект с `draft=false` и `is_public=true`. Недоступный private/draft проект скрыт
ответом `404`; видимый пользователю проект без права изменения возвращает `403`
для `POST`, `PATCH` и `DELETE`.

Идентификатор проекта не принимается из request body. Queryset вложенного объекта
всегда одновременно фильтруется по `project_id` из URL и по собственному ID,
поэтому цель или достижение нельзя прочитать, изменить либо удалить через URL
другого проекта.

## Транзакции и производительность

Создание, изменение и удаление выполняются внутри `transaction.atomic`. Сначала
валидируется весь payload, затем меняется одна строка; ошибка в одном поле не
оставляет частично сохраненные значения других полей.

Список целей загружает ответственных через `select_related`. Контракты списков не
выполняют запрос на каждый элемент и покрыты regression-тестом на постоянный
query budget.

## Что не входит в этот этап

API не меняет основные поля, правила публикации и черновиков Project, загрузку
файлов, вакансии, партнеров, ресурсы, приглашения, подписки, конкурсные связи,
Application или Submission lifecycle. Управление выполнением цели (`is_done`)
остается в legacy-контуре до отдельного продуктового решения.
Loading
Loading