Leadera — Фильтры и реорганизация списка диаграмм Ганта
~/Projects/docs-a2v/content/guides/leadera-gantt-filters.md
Фильтры и реорганизация списка диаграмм Ганта
Дата: 07.04.2026 Статус: Требования Проект: Leadera (dev — sand.a2v.space)
1. Постановка задачи
Список диаграмм Ганта должен показывать все доступные пользователю диаграммы из всех пространств (spaces), с возможностью фильтрации и поиска. Сейчас список привязан к одному пространству — нужно убрать эту зависимость и добавить удобный toolbar.
2. Изменения API
2.1. Новый endpoint списка диаграмм
Было:
GET /api/v1/spaces/{spaceId}/gantt-charts?page=1&per_page=10
Стало:
GET /api/v1/gantt-charts?page=1&per_page=10
Пользователь видит все диаграммы из всех пространств, где он является подтверждённым участником (статус accepted).
2.2. Параметры фильтрации и поиска
| Параметр | Тип | Описание |
|---|---|---|
page |
int | Номер страницы (default: 1) |
per_page |
int | Записей на странице (default: 10) |
space_id |
UUID (optional) | Фильтр по конкретному пространству |
created_by |
UUID (optional) | Фильтр по создателю диаграммы |
search |
string (optional) | Поиск по назвению и описанию (ILIKE, case-insensitive) |
sort |
string (optional) | Сортировка: created_at, updated_at, title (default: updated_at) |
order |
string (optional) | asc / desc (default: desc) |
Примеры:
GET /api/v1/gantt-charts?search=миграция
GET /api/v1/gantt-charts?space_id=0b334ded-...&created_by=a1b2c3d4-...
GET /api/v1/gantt-charts?page=2&per_page=20&sort=title&order=asc
2.3. Изменение структуры ответа
Добавить поле space в каждую диаграмму:
{
"data": [
{
"id": "uuid",
"title": "Миграция backend",
"description": "...",
"created_by": "uuid",
"created_by_name": "Антон Агальцов",
"created_at": "2026-04-01T10:00:00Z",
"updated_at": "2026-04-07T09:00:00Z",
"space": {
"id": "uuid",
"name": "IT Ландшафт",
"color": "#c4623a"
},
"is_archived": false
}
],
"pagination": {
"page": 1,
"per_page": 10,
"total": 42,
"total_pages": 5
}
}
2.4. Endpoint для списка фильтров
Вспомогательный endpoint для заполнения dropdown-фильтров:
GET /api/v1/gantt-charts/filters
Ответ:
{
"spaces": [
{ "id": "uuid", "name": "IT Ландшафт", "color": "#c4623a" },
{ "id": "uuid", "name": "DevOps", "color": "#27ae60" }
],
"creators": [
{ "id": "uuid", "display_name": "Антон Агальцов" },
{ "id": "uuid", "display_name": "Иван Петров" }
]
}
Логика creators: уникальные создатели всех диаграмм, доступных текущему пользователю. Получается через DISTINCT-запрос по created_by с JOIN на users.
2.5. Backend — изменения в Go
Файлы для изменения:
internal/handlers/gantt_handler.go
- Добавить новый handler
ListAllGanttCharts— без привязки к space - Зарегистрировать маршрут
GET /gantt-charts(без/spaces/:id/) - Парсить query-параметры:
space_id,created_by,search,sort,order - Старый маршрут
GET /spaces/:id/gantt-charts— оставить для обратной совместимости (или удалить, если не используется)
internal/service/gantt_service.go
- Новый метод
ListAll(ctx, userId, filters)— запрашивает все spaces пользователя (черезspace_memberсstatus=accepted), затем выбирает все gantt_charts из этих spaces с фильтрами
internal/repository/gantt_repository.go
- Новый метод с динамическим SQL:
- Базовый JOIN:
gantt_charts→spaces→space_members - WHERE:
space_members.user_id = $1 AND space_members.status = 'accepted' - Опциональные фильтры:
AND space_id = $N,AND created_by = $N,AND (title ILIKE '%' || $N || '%' OR description ILIKE '%' || $N || '%') - Возвращать поле
space(id, name, color) через JOIN
- Базовый JOIN:
internal/dto/gantt/
- Новые DTO:
GanttChartListFilters,GanttChartWithSpaceResponse,GanttFiltersResponse
SQL (пример):
SELECT gc.*, s.id as space_id, s.name as space_name, s.color as space_color,
u.display_name as created_by_name
FROM gantt_charts gc
JOIN spaces s ON s.id = gc.space_id
JOIN space_members sm ON sm.space_id = s.id
LEFT JOIN users u ON u.id = gc.created_by
WHERE sm.user_id = $1
AND sm.status = 'accepted'
AND ($2::uuid IS NULL OR gc.space_id = $2)
AND ($3::uuid IS NULL OR gc.created_by = $3)
AND ($4::text IS NULL OR gc.title ILIKE '%' || $4 || '%'
OR gc.description ILIKE '%' || $4 || '%')
ORDER BY
CASE WHEN $5 = 'title' THEN gc.title END,
CASE WHEN $5 = 'created_at' THEN gc.created_at::text END,
gc.updated_at DESC
LIMIT $6 OFFSET $7;
3. Изменения Frontend (Angular)
3.1. Toolbar фильтров
Добавить toolbar над списком диаграмм:
┌──────────────────────────────────────────────────────────────────┐
│ [🔍 Поиск... ] [▼ Пространство] │
│ [▼ Создатель] [▼ Сортировка] [Сбросить фильтры] │
└──────────────────────────────────────────────────────────────────┘
Компоненты:
- Строка поиска — input с debounce (300ms), поиск по назвению и описанию
- Dropdown «Пространство» — список из
/gantt-charts/filters, с цветовой меткой - Dropdown «Создатель» — список уникальных создателей
- Dropdown «Сортировка» — по дате обновления, дате создания, названию
- Кнопка «Сбросить» — очищает все фильтры
Состояние фильтров в URL (query params):
/gantt?search=миграция&space_id=xxx&sort=updated_at
Это позволяет делиться ссылкой с уже настроенными фильтрами.
3.2. Карточка диаграммы — бейдж пространства
На каждой карточке добавить бейдж с названием пространства:
┌─────────────────────────────────────┐
│ 🟠 IT Ландшафт │ ← бейдж с цветом пространства
│ Миграция backend │
│ Перевод PHP→Go, этап 2 │
│ Создал: Антон А. · 07.04.2026 │
└─────────────────────────────────────┘
3.3. Форма создания диаграммы — выбор пространства
В модальном окне создания:
- Dropdown со списком пространств, где пользователь имеет роль editor или выше
- Валидация: если пользователь не editor ни в одном пространстве — показать сообщение «Нет доступных пространств для создания»
Запрос доступных пространств: переиспользовать существующий GET /api/v1/spaces с фильтрацией на клиенте по role ∈ [owner, admin, editor], либо добавить параметр ?min_role=editor на backend.
3.4. Изменение routing
Было:
/gantt → список гантов текущего пространства
Стало:
/gantt → список всех доступных гантов (из всех пространств)
Убрать зависимость от SpaceStorageService.getSelectedSpaceId() в списке гантов.
3.5. Frontend — файлы для изменения
| Файл | Изменение |
|---|---|
pages/gantt/services/gantt.service.ts |
Новый метод listAll(filters), getFilters() |
pages/gantt/gantt.component.ts |
Подключить toolbar, парсинг URL-параметров |
pages/gantt/gantt.component.html |
Добавить toolbar, бейджи на карточках |
pages/gantt/components/gantt-card/ |
Добавить бейдж пространства |
pages/gantt/components/create-chart-modal/ |
Dropdown выбора пространства |
core/models/ |
Обновить модели: добавить space в GanttChart |
4. Обратная совместимость
| Endpoint | Статус |
|---|---|
GET /api/v1/spaces/{id}/gantt-charts |
Сохранить (для детального view внутри пространства) |
GET /api/v1/gantt-charts |
Новый — глобальный список |
GET /api/v1/gantt-charts/filters |
Новый — данные для dropdown’ов |
POST /api/v1/spaces/{id}/gantt-charts |
Сохранить (создание в контексте пространства) |
| Все CRUD для sections/tasks | Без изменений |
5. Критерии приёмки
- Endpoint
GET /api/v1/gantt-chartsвозвращает все доступные диаграммы - Фильтр по
space_id— показывает только диаграммы конкретного пространства - Фильтр по
created_by— показывает только диаграммы выбранного создателя - Поиск
search— ищет по title и description (case-insensitive) - Dropdown фильтров заполняется реальными данными из
/filters - Карточка диаграммы показывает бейдж пространства с цветом
- Форма создания предлагает только пространства с ролью ≥ editor
- Состояние фильтров сохраняется в URL (можно поделиться ссылкой)
- Старые endpoints (
/spaces/{id}/gantt-charts) продолжают работать - Swagger документация обновлена
6. Порядок реализации
- Backend: DTO для новых запросов/ответов
- Backend: Repository — SQL-запрос с фильтрами + JOIN на spaces
- Backend: Service —
ListAll,GetFilters - Backend: Handler —
ListAllGanttCharts,GetGanttFilters, регистрация маршрутов - Backend: Swagger — обновить документацию
- Frontend: Модели — обновить GanttChart, добавить Space в ответ
- Frontend: Service —
listAll(),getFilters() - Frontend: Toolbar компонент — поиск + dropdown’ы
- Frontend: Карточка — бейдж пространства
- Frontend: Модальное окно создания — dropdown пространства
- Frontend: URL-параметры — синхронизация фильтров с router
- Тестирование