Files
team-planner/ARCHITECTURE.md
vigdorov dea0676169
Some checks reported errors
continuous-integration/drone/push Build encountered an error
add ai functions
2026-01-15 01:59:16 +03:00

2032 lines
88 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Архитектура Team Planner
---
## 1. C4 Model
### 1.1 Level 1: System Context
```mermaid
flowchart TB
subgraph external [" "]
User["👤 Пользователь<br/><i>Член команды разработки</i>"]
AI["🤖 AI Proxy Service<br/><i>LLM для оценки задач</i>"]
KC["🔐 Keycloak<br/><i>auth.vigdorov.ru<br/>Identity Provider</i>"]
end
subgraph system ["Team Planner"]
TP["🎯 Team Planner<br/><i>Приложение для управления<br/>бэклогом идей команды</i>"]
end
User -->|"Управляет идеями,<br/>командой, комментариями<br/>[HTTPS]"| TP
User -->|"Авторизация<br/>[OIDC/PKCE]"| KC
KC -->|"JWT токены"| TP
TP -->|"Запросы на оценку<br/>трудозатрат<br/>[HTTPS/REST]"| AI
style TP fill:#1168bd,color:#fff
style User fill:#08427b,color:#fff
style AI fill:#999,color:#fff
style KC fill:#c92a2a,color:#fff
```
### 1.2 Level 2: Container Diagram
```mermaid
flowchart TB
User["👤 Пользователь<br/><i>Член команды разработки</i>"]
Admin["👤 Администратор<br/><i>email из K8s Secret</i>"]
KC["🔐 Keycloak<br/><i>auth.vigdorov.ru</i>"]
subgraph TeamPlanner ["Team Planner"]
SPA["📱 Frontend SPA<br/><i>React, TypeScript, MUI</i><br/><br/>Веб-интерфейс для<br/>работы с идеями"]
API["⚙️ Backend API<br/><i>NestJS, TypeScript</i><br/><br/>REST API"]
WS["🔌 WebSocket Gateway<br/><i>Socket.io</i><br/><br/>Real-time обновления"]
DB[("🗄️ Database<br/><i>PostgreSQL</i><br/><br/>Идеи, команда,<br/>права, аудит")]
end
AI["🤖 AI Proxy Service<br/><i>LLM для оценки задач</i>"]
User -->|"Использует<br/>[HTTPS]"| SPA
Admin -->|"Управляет правами<br/>[HTTPS]"| SPA
User <-->|"OIDC Login<br/>[Redirect]"| KC
SPA -->|"API запросы<br/>[REST + Bearer JWT]"| API
SPA <-->|"Real-time<br/>[WebSocket]"| WS
API -.->|"Валидация JWT<br/>[JWKS]"| KC
API -->|"Читает/пишет<br/>[TypeORM]"| DB
WS -->|"Читает<br/>[TypeORM]"| DB
API -->|"Оценка трудозатрат<br/>[HTTPS/REST]"| AI
API -->|"Уведомления<br/>[Events]"| WS
style SPA fill:#438dd5,color:#fff
style API fill:#438dd5,color:#fff
style WS fill:#438dd5,color:#fff
style DB fill:#438dd5,color:#fff
style User fill:#08427b,color:#fff
style Admin fill:#08427b,color:#fff
style AI fill:#999,color:#fff
style KC fill:#c92a2a,color:#fff
```
### 1.3 Level 3: Component Diagram — Backend API
```mermaid
flowchart TB
subgraph API ["Backend API (NestJS)"]
subgraph Controllers ["Controllers"]
IdeasCtrl["IdeasController<br/><i>CRUD идей, reorder</i>"]
CommentsCtrl["CommentsController<br/><i>Комментарии к идеям</i>"]
TeamCtrl["TeamController<br/><i>Члены команды, роли</i>"]
AiCtrl["AiController<br/><i>AI-оценка, генерация ТЗ</i>"]
PermCtrl["PermissionsController<br/><i>Управление правами</i>"]
AuditCtrl["AuditController<br/><i>История действий</i>"]
ExportCtrl["ExportController<br/><i>Экспорт в DOCX</i>"]
end
subgraph Services ["Services"]
IdeasSvc["IdeasService"]
CommentsSvc["CommentsService"]
TeamSvc["TeamService"]
AiSvc["AiService<br/><i>Интеграция с AI Proxy</i>"]
PermSvc["PermissionsService<br/><i>Проверка/управление правами</i>"]
AuditSvc["AuditService<br/><i>Логирование действий</i>"]
ExportSvc["ExportService<br/><i>Генерация DOCX</i>"]
end
subgraph Gateway ["WebSocket Gateway"]
WSGateway["EventsGateway<br/><i>Socket.io</i><br/><i>Real-time события</i>"]
end
subgraph Auth ["Auth Module"]
JwtStrategy["JwtStrategy<br/><i>JWKS валидация</i>"]
JwtGuard["JwtAuthGuard<br/><i>Глобальная защита</i>"]
PermGuard["PermissionsGuard<br/><i>Проверка прав</i>"]
end
subgraph Entities ["Entities (TypeORM)"]
IdeaEntity[("Idea")]
CommentEntity[("Comment")]
TeamMemberEntity[("TeamMember")]
RoleEntity[("Role")]
UserEntity[("User")]
UserPermEntity[("UserPermissions")]
AuditEntity[("AuditLog")]
end
end
KC["🔐 Keycloak"]
AI["🤖 AI Proxy"]
DB[("PostgreSQL")]
IdeasCtrl --> IdeasSvc
CommentsCtrl --> CommentsSvc
TeamCtrl --> TeamSvc
AiCtrl --> AiSvc
PermCtrl --> PermSvc
AuditCtrl --> AuditSvc
ExportCtrl --> ExportSvc
IdeasSvc --> IdeaEntity
IdeasSvc --> AuditSvc
IdeasSvc --> WSGateway
CommentsSvc --> CommentEntity
CommentsSvc --> AuditSvc
TeamSvc --> TeamMemberEntity
TeamSvc --> RoleEntity
AiSvc --> IdeaEntity
AiSvc --> TeamMemberEntity
AiSvc -->|"HTTP"| AI
AiSvc --> AuditSvc
PermSvc --> UserPermEntity
PermSvc --> UserEntity
AuditSvc --> AuditEntity
ExportSvc --> IdeaEntity
ExportSvc --> CommentEntity
IdeaEntity --> DB
CommentEntity --> DB
TeamMemberEntity --> DB
RoleEntity --> DB
UserEntity --> DB
UserPermEntity --> DB
AuditEntity --> DB
JwtStrategy -.->|"JWKS"| KC
JwtGuard --> JwtStrategy
PermGuard --> PermSvc
style IdeasCtrl fill:#85c1e9,color:#000
style CommentsCtrl fill:#85c1e9,color:#000
style TeamCtrl fill:#85c1e9,color:#000
style AiCtrl fill:#85c1e9,color:#000
style PermCtrl fill:#85c1e9,color:#000
style AuditCtrl fill:#85c1e9,color:#000
style ExportCtrl fill:#85c1e9,color:#000
style IdeasSvc fill:#82e0aa,color:#000
style CommentsSvc fill:#82e0aa,color:#000
style TeamSvc fill:#82e0aa,color:#000
style AiSvc fill:#82e0aa,color:#000
style PermSvc fill:#82e0aa,color:#000
style AuditSvc fill:#82e0aa,color:#000
style ExportSvc fill:#82e0aa,color:#000
style WSGateway fill:#f5b7b1,color:#000
style JwtStrategy fill:#f9e79f,color:#000
style JwtGuard fill:#f9e79f,color:#000
style PermGuard fill:#f9e79f,color:#000
style AI fill:#999,color:#fff
style KC fill:#c92a2a,color:#fff
```
### 1.4 Level 3: Component Diagram — Frontend SPA
```mermaid
flowchart TB
subgraph SPA ["Frontend SPA (React)"]
subgraph Pages ["Pages / Views"]
IdeasPage["IdeasPage<br/><i>Главная страница</i>"]
TeamPage["TeamPage<br/><i>Управление командой</i>"]
AdminPage["AdminPage<br/><i>Панель администратора</i>"]
AuditPage["AuditPage<br/><i>История действий</i>"]
LoginPage["LoginPage<br/><i>Страница входа</i>"]
end
subgraph Components ["UI Components"]
IdeasTable["IdeasTable<br/><i>Таблица идей + D&D</i>"]
IdeasFilters["IdeasFilters<br/><i>Фильтры и поиск</i>"]
CreateIdeaModal["CreateIdeaModal"]
AiEstimateModal["AiEstimateModal<br/><i>Результат AI-оценки</i>"]
CommentsPanel["CommentsPanel<br/><i>Комментарии к идее</i>"]
SpecModal["SpecificationModal<br/><i>Просмотр/редакт. ТЗ</i>"]
PermissionsTable["PermissionsTable<br/><i>Таблица прав доступа</i>"]
AuditLogTable["AuditLogTable<br/><i>Таблица истории</i>"]
ThemeToggle["ThemeToggle<br/><i>Переключатель темы</i>"]
OnlineUsers["OnlineUsers<br/><i>Онлайн пользователи</i>"]
end
subgraph State ["State Management"]
IdeasStore["IdeasStore<br/><i>Zustand</i>"]
ThemeStore["ThemeStore<br/><i>Zustand</i>"]
ReactQuery["React Query<br/><i>Кэш, мутации</i>"]
end
subgraph ServicesLayer ["Services"]
IdeasAPI["ideasApi"]
TeamAPI["teamApi"]
AiAPI["aiApi"]
CommentsAPI["commentsApi"]
PermissionsAPI["permissionsApi"]
AuditAPI["auditApi"]
ExportAPI["exportApi"]
end
subgraph AuthLayer ["Auth"]
AuthProvider["AuthProvider<br/><i>Keycloak context</i>"]
ApiClient["api.ts<br/><i>Axios + interceptors</i>"]
end
subgraph WebSocketLayer ["WebSocket"]
WSProvider["WebSocketProvider<br/><i>Socket.io client</i>"]
WSHooks["useWebSocket<br/><i>Real-time хуки</i>"]
end
subgraph ThemeLayer ["Theme"]
ThemeProvider["ThemeProvider<br/><i>MUI dark/light</i>"]
end
end
KC["🔐 Keycloak"]
API["⚙️ Backend API"]
WS["🔌 WebSocket Gateway"]
IdeasPage --> IdeasTable
IdeasPage --> IdeasFilters
IdeasPage --> CreateIdeaModal
IdeasPage --> OnlineUsers
IdeasTable --> AiEstimateModal
IdeasTable --> CommentsPanel
IdeasTable --> SpecModal
TeamPage --> TeamAPI
AdminPage --> PermissionsTable
AuditPage --> AuditLogTable
IdeasTable --> ReactQuery
ReactQuery --> IdeasAPI
ReactQuery --> AiAPI
ReactQuery --> CommentsAPI
ReactQuery --> PermissionsAPI
ReactQuery --> AuditAPI
ReactQuery --> ExportAPI
IdeasFilters --> IdeasStore
ThemeToggle --> ThemeStore
IdeasAPI --> ApiClient
TeamAPI --> ApiClient
AiAPI --> ApiClient
CommentsAPI --> ApiClient
PermissionsAPI --> ApiClient
AuditAPI --> ApiClient
ExportAPI --> ApiClient
ApiClient -->|"REST + JWT"| API
AuthProvider -->|"OIDC"| KC
WSProvider <-->|"WebSocket"| WS
WSHooks --> WSProvider
ThemeProvider --> ThemeStore
style IdeasPage fill:#d4e6f1,color:#000
style TeamPage fill:#d4e6f1,color:#000
style AdminPage fill:#d4e6f1,color:#000
style AuditPage fill:#d4e6f1,color:#000
style LoginPage fill:#d4e6f1,color:#000
style IdeasTable fill:#aed6f1,color:#000
style IdeasFilters fill:#aed6f1,color:#000
style CreateIdeaModal fill:#aed6f1,color:#000
style AiEstimateModal fill:#aed6f1,color:#000
style CommentsPanel fill:#aed6f1,color:#000
style SpecModal fill:#aed6f1,color:#000
style PermissionsTable fill:#aed6f1,color:#000
style AuditLogTable fill:#aed6f1,color:#000
style ThemeToggle fill:#aed6f1,color:#000
style OnlineUsers fill:#aed6f1,color:#000
style IdeasStore fill:#a9dfbf,color:#000
style ThemeStore fill:#a9dfbf,color:#000
style ReactQuery fill:#a9dfbf,color:#000
style AuthProvider fill:#f9e79f,color:#000
style ApiClient fill:#f9e79f,color:#000
style WSProvider fill:#f5b7b1,color:#000
style WSHooks fill:#f5b7b1,color:#000
style ThemeProvider fill:#d7bde2,color:#000
style API fill:#438dd5,color:#fff
style WS fill:#438dd5,color:#fff
style KC fill:#c92a2a,color:#fff
```
---
## 2. Sequence Diagrams
### 2.0 Авторизация (Keycloak OIDC)
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend<br/>(React)
participant KC as Keycloak<br/>(auth.vigdorov.ru)
participant BE as Backend<br/>(NestJS)
User->>FE: Открывает приложение
FE->>FE: keycloak.init({ onLoad: 'login-required' })
FE->>KC: Redirect на /auth (PKCE)
KC-->>User: Форма входа
User->>KC: Вводит логин/пароль
KC->>KC: Проверяет credentials
KC-->>FE: Redirect с authorization code
FE->>KC: POST /token (code + code_verifier)
KC-->>FE: { access_token, refresh_token }
FE->>FE: Сохраняет токены в памяти
FE-->>User: Показывает приложение
Note over FE,BE: Все последующие API запросы
FE->>BE: GET /api/ideas<br/>Authorization: Bearer {token}
BE->>KC: GET /certs (JWKS, кэшируется)
KC-->>BE: Public keys
BE->>BE: Валидация JWT подписи
BE-->>FE: 200 OK { data }
Note over FE,KC: Автообновление токена (каждые 10 сек)
FE->>KC: POST /token (refresh_token)
KC-->>FE: { new_access_token }
```
### 2.1 Создание идеи
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend<br/>(React)
participant BE as Backend<br/>(NestJS)
participant DB as PostgreSQL
User->>FE: Заполняет форму идеи
FE->>FE: Валидация на клиенте
FE->>BE: POST /api/ideas
BE->>BE: Валидация DTO
BE->>DB: INSERT INTO ideas
DB-->>BE: idea record
BE-->>FE: 201 Created { idea }
FE->>FE: Добавляет в store
FE-->>User: Показывает новую идею в списке
```
### 2.2 Inline-редактирование идеи
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend<br/>(React)
participant BE as Backend<br/>(NestJS)
participant DB as PostgreSQL
User->>FE: Double-click на ячейку
FE->>FE: Переключает в режим редактирования
User->>FE: Изменяет значение, blur/Enter
FE->>FE: Оптимистичное обновление store
FE->>BE: PATCH /api/ideas/:id
BE->>BE: Валидация DTO
BE->>DB: UPDATE ideas SET ...
DB-->>BE: updated idea
BE-->>FE: 200 OK { idea }
FE->>FE: Подтверждает изменение в store
alt Ошибка
BE-->>FE: 4xx/5xx error
FE->>FE: Откат оптимистичного обновления
FE-->>User: Показывает ошибку
end
```
### 2.3 Drag & Drop (изменение порядка)
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend<br/>(React)
participant BE as Backend<br/>(NestJS)
participant DB as PostgreSQL
User->>FE: Перетаскивает идею
FE->>FE: dnd-kit обновляет UI
FE->>FE: Оптимистичное обновление порядка
FE->>BE: PATCH /api/ideas/reorder
Note right of FE: { ids: [id1, id2, ...] }
BE->>DB: UPDATE ideas SET position = ...
DB-->>BE: OK
BE-->>FE: 200 OK
FE-->>User: Порядок сохранён
```
### 2.4 AI-оценка трудозатрат
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend<br/>(React)
participant BE as Backend<br/>(NestJS)
participant AI as AI Proxy
participant DB as PostgreSQL
User->>FE: Нажимает "Оценить"
FE->>FE: Показывает loader
FE->>BE: POST /api/ai/estimate
Note right of FE: { ideaId }
BE->>DB: SELECT idea, team_members
DB-->>BE: idea + team data
BE->>BE: Формирует промпт
BE->>AI: POST /chat/completions
Note right of BE: prompt с описанием идеи<br/>и составом команды
AI-->>BE: LLM response
BE->>BE: Парсит ответ
BE->>DB: UPDATE ideas SET estimate = ...
DB-->>BE: OK
BE-->>FE: 200 OK { estimate }
FE->>FE: Обновляет store
FE-->>User: Показывает оценку
```
### 2.5 Генерация мини-ТЗ
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend<br/>(React)
participant BE as Backend<br/>(NestJS)
participant AI as AI Proxy
participant DB as PostgreSQL
User->>FE: Нажимает "ТЗ" (генерация)
FE->>FE: Открывает модалку, показывает loader
FE->>BE: POST /api/ai/generate-specification
Note right of FE: { ideaId }
BE->>DB: SELECT idea
DB-->>BE: idea data
BE->>BE: Формирует промпт для ТЗ
BE->>AI: POST /chat/completions
Note right of BE: prompt с описанием идеи
AI-->>BE: LLM response (ТЗ в markdown)
BE->>BE: Парсит ответ
BE->>DB: UPDATE ideas SET specification = ...
DB-->>BE: OK
BE-->>FE: 200 OK { specification }
FE->>FE: Показывает ТЗ в модалке
FE-->>User: Может просмотреть/редактировать
```
### 2.6 Редактирование ТЗ
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend<br/>(React)
participant BE as Backend<br/>(NestJS)
participant DB as PostgreSQL
User->>FE: Открывает модалку ТЗ
FE-->>User: Показывает сохранённое ТЗ
User->>FE: Нажимает "Редактировать"
FE->>FE: Переключает в режим редактирования
User->>FE: Изменяет текст ТЗ
User->>FE: Нажимает "Сохранить"
FE->>BE: PATCH /api/ideas/:id
Note right of FE: { specification: "..." }
BE->>DB: UPDATE ideas SET specification = ...
DB-->>BE: updated idea
BE-->>FE: 200 OK { idea }
FE->>FE: Обновляет store
FE-->>User: Показывает обновлённое ТЗ
```
### 2.7 Добавление комментария
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend<br/>(React)
participant BE as Backend<br/>(NestJS)
participant DB as PostgreSQL
User->>FE: Пишет комментарий
FE->>BE: POST /api/ideas/:id/comments
Note right of FE: { text, parentId? }
BE->>BE: Валидация
BE->>DB: INSERT INTO comments
DB-->>BE: comment record
BE-->>FE: 201 Created { comment }
FE->>FE: Добавляет в store
FE-->>User: Показывает комментарий
```
### 2.6 Загрузка списка идей с фильтрами
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend<br/>(React)
participant BE as Backend<br/>(NestJS)
participant DB as PostgreSQL
User->>FE: Открывает страницу / меняет фильтры
FE->>FE: Показывает skeleton loader
FE->>BE: GET /api/ideas?status=...&priority=...
BE->>DB: SELECT * FROM ideas WHERE ... ORDER BY ...
DB-->>BE: ideas[]
BE-->>FE: 200 OK { data, total, page }
FE->>FE: Сохраняет в store
FE-->>User: Отображает таблицу
```
### 2.9 Real-time обновления (WebSocket)
```mermaid
sequenceDiagram
autonumber
actor User1 as Пользователь 1
actor User2 as Пользователь 2
participant FE1 as Frontend 1
participant FE2 as Frontend 2
participant WS as WebSocket Gateway
participant BE as Backend
participant DB as PostgreSQL
Note over FE1,FE2: Оба пользователя подключены к WebSocket
FE1->>WS: connect(token)
WS->>WS: Валидация JWT
WS-->>FE1: connected
FE2->>WS: connect(token)
WS-->>FE2: connected
User1->>FE1: Редактирует идею
FE1->>BE: PATCH /api/ideas/:id
BE->>DB: UPDATE ideas
DB-->>BE: OK
BE->>WS: emit('idea:updated', idea)
WS-->>FE1: idea:updated
WS-->>FE2: idea:updated
FE1->>FE1: Обновляет store
FE2->>FE2: Обновляет store
FE2-->>User2: Видит изменения в реальном времени
```
### 2.10 Проверка прав доступа
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend
participant BE as Backend
participant DB as PostgreSQL
User->>FE: Пытается создать идею
FE->>BE: POST /api/ideas
Note right of FE: Authorization: Bearer token
BE->>BE: JwtAuthGuard: валидация JWT
BE->>DB: SELECT * FROM user_permissions WHERE userId = ?
DB-->>BE: permissions
BE->>BE: PermissionsGuard: проверка 'create_ideas'
alt Право есть
BE->>DB: INSERT INTO ideas
BE->>DB: INSERT INTO audit_log
DB-->>BE: OK
BE-->>FE: 201 Created { idea }
else Права нет
BE-->>FE: 403 Forbidden { message: "Недостаточно прав" }
FE-->>User: Показывает ошибку
end
```
### 2.11 Изменение прав пользователя (Админ)
```mermaid
sequenceDiagram
autonumber
actor Admin as Администратор
participant FE as Frontend
participant BE as Backend
participant DB as PostgreSQL
Admin->>FE: Открывает панель администратора
FE->>BE: GET /api/permissions/users
BE->>BE: Проверка: isAdmin(user.email)
BE->>DB: SELECT * FROM users + permissions
DB-->>BE: users with permissions
BE-->>FE: 200 OK { users }
FE-->>Admin: Показывает таблицу прав
Admin->>FE: Изменяет право пользователя
FE->>BE: PATCH /api/permissions/:userId
Note right of FE: { create_ideas: true }
BE->>BE: Проверка: isAdmin
BE->>DB: UPDATE user_permissions
BE->>DB: INSERT INTO audit_log
DB-->>BE: OK
BE-->>FE: 200 OK { permissions }
FE-->>Admin: Обновляет UI
```
### 2.12 Просмотр и восстановление из аудита
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend
participant BE as Backend
participant DB as PostgreSQL
User->>FE: Открывает историю действий
FE->>BE: GET /api/audit?entityType=idea&page=1
BE->>BE: Проверка права 'view_audit_log'
BE->>DB: SELECT * FROM audit_log WHERE ...
DB-->>BE: audit entries
BE-->>FE: 200 OK { data, meta }
FE-->>User: Показывает таблицу истории
User->>FE: Нажимает "Восстановить" на удалённой идее
FE->>BE: POST /api/audit/:id/restore
BE->>DB: SELECT oldValue FROM audit_log
DB-->>BE: { oldValue: {...} }
BE->>DB: INSERT INTO ideas (oldValue data)
BE->>DB: INSERT INTO audit_log (restore action)
DB-->>BE: OK
BE-->>FE: 201 Created { idea }
FE->>FE: Обновляет список идей
FE-->>User: Идея восстановлена
```
### 2.13 Экспорт идеи в DOCX
```mermaid
sequenceDiagram
autonumber
actor User as Пользователь
participant FE as Frontend
participant BE as Backend
participant DB as PostgreSQL
User->>FE: Нажимает "Экспорт" на идее
FE->>BE: GET /api/export/idea/:id
BE->>BE: Проверка права 'export_ideas'
BE->>DB: SELECT idea + comments + estimate
DB-->>BE: full idea data
BE->>BE: Генерирует DOCX (docx library)
BE-->>FE: 200 OK (binary, Content-Type: application/vnd.openxmlformats...)
FE->>FE: Скачивает файл
FE-->>User: Файл скачан
```
---
## 3. API Contracts
### 3.1 Ideas
#### GET /api/ideas
Получение списка идей с пагинацией и фильтрами.
**Query Parameters:**
```typescript
{
page?: number; // default: 1
limit?: number; // default: 50
status?: IdeaStatus; // фильтр по статусу
priority?: Priority; // фильтр по приоритету
module?: Module; // фильтр по модулю
color?: string; // фильтр по цвету
search?: string; // поиск по тексту
sortBy?: string; // поле для сортировки
sortOrder?: 'asc' | 'desc';
}
```
**Response 200:**
```typescript
{
data: Idea[];
meta: {
total: number;
page: number;
limit: number;
totalPages: number;
}
}
```
#### POST /api/ideas
Создание новой идеи.
**Request Body:**
```typescript
{
title: string; // обязательное
description?: string;
status: IdeaStatus; // default: 'new'
priority: Priority; // default: 'medium'
module: Module[];
targetAudience?: string;
painPoint?: string;
aiRole?: string;
validationMethod?: string;
color?: string;
position?: number;
}
```
**Response 201:**
```typescript
{
id: string;
title: string;
description: string | null;
status: IdeaStatus;
priority: Priority;
module: Module[];
targetAudience: string | null;
painPoint: string | null;
aiRole: string | null;
validationMethod: string | null;
color: string | null;
position: number;
estimate: Estimate | null;
createdAt: string;
updatedAt: string;
}
```
#### PATCH /api/ideas/:id
Обновление идеи (partial update).
**Request Body:**
```typescript
Partial<{
title: string;
description: string;
status: IdeaStatus;
priority: Priority;
module: Module[];
targetAudience: string;
painPoint: string;
aiRole: string;
validationMethod: string;
color: string;
}>
```
**Response 200:** `Idea`
#### DELETE /api/ideas/:id
Удаление идеи.
**Response 204:** No Content
#### PATCH /api/ideas/reorder
Изменение порядка идей.
**Request Body:**
```typescript
{
ids: string[]; // ID идей в новом порядке
}
```
**Response 200:**
```typescript
{
success: true;
}
```
### 3.2 Comments
#### GET /api/ideas/:ideaId/comments
Получение комментариев к идее.
**Response 200:**
```typescript
{
data: Comment[];
}
// Comment
{
id: string;
text: string;
ideaId: string;
parentId: string | null; // для тредов
createdAt: string;
updatedAt: string;
replies?: Comment[]; // вложенные ответы
}
```
#### POST /api/ideas/:ideaId/comments
Добавление комментария.
**Request Body:**
```typescript
{
text: string;
parentId?: string; // для ответа на комментарий
}
```
**Response 201:** `Comment`
#### DELETE /api/comments/:id
Удаление комментария.
**Response 204:** No Content
### 3.3 Team
#### GET /api/team/members
Получение списка членов команды.
**Response 200:**
```typescript
{
data: TeamMember[];
}
// TeamMember
{
id: string;
name: string;
role: TeamRole;
productivity: {
trivial: number; // часы
easy: number;
medium: number;
hard: number;
epic: number;
};
createdAt: string;
updatedAt: string;
}
```
#### POST /api/team/members
Добавление члена команды.
**Request Body:**
```typescript
{
name: string;
role: TeamRole;
productivity?: {
trivial?: number;
easy?: number;
medium?: number;
hard?: number;
epic?: number;
};
}
```
**Response 201:** `TeamMember`
#### PATCH /api/team/members/:id
Обновление члена команды.
**Request Body:** `Partial<TeamMember>`
**Response 200:** `TeamMember`
#### DELETE /api/team/members/:id
Удаление члена команды.
**Response 204:** No Content
#### GET /api/team/summary
Сводка по команде.
**Response 200:**
```typescript
{
totalMembers: number;
byRole: Record<TeamRole, number>;
}
```
### 3.4 AI
#### POST /api/ai/estimate
AI-оценка трудозатрат для идеи.
**Request Body:**
```typescript
{
ideaId: string;
}
```
**Response 200:**
```typescript
{
ideaId: string;
estimate: {
totalHours: number;
totalDays: number;
complexity: 'trivial' | 'easy' | 'medium' | 'hard' | 'epic';
breakdown: {
role: TeamRole;
hours: number;
complexity: Complexity;
description: string;
}[];
recommendations?: string[];
};
}
```
#### POST /api/ai/generate-specification
AI-генерация мини-ТЗ для идеи.
**Request Body:**
```typescript
{
ideaId: string;
}
```
**Response 200:**
```typescript
{
ideaId: string;
specification: string; // markdown текст ТЗ
generatedAt: string; // ISO timestamp
}
```
**Структура генерируемого ТЗ:**
```markdown
## Цель
[что должно быть достигнуто]
## Функциональные требования
- [требование 1]
- [требование 2]
...
## Технические требования
[архитектура, интеграции, ограничения]
## Критерии приёмки
- [критерий 1]
- [критерий 2]
...
## Зависимости и риски
[что может повлиять на реализацию]
```
### 3.5 Enums
```typescript
enum IdeaStatus {
NEW = 'new',
DISCUSSING = 'discussing',
APPROVED = 'approved',
IN_PROGRESS = 'in_progress',
DONE = 'done',
REJECTED = 'rejected'
}
enum Priority {
CRITICAL = 'critical',
HIGH = 'high',
MEDIUM = 'medium',
LOW = 'low'
}
enum Module {
FRONTEND = 'frontend',
BACKEND = 'backend',
AI = 'ai',
MOBILE = 'mobile',
INFRASTRUCTURE = 'infrastructure',
OTHER = 'other'
}
enum TeamRole {
BACKEND = 'backend',
FRONTEND = 'frontend',
AI_ML = 'ai_ml',
ANALYST = 'analyst',
QA = 'qa',
DEVOPS = 'devops',
DESIGNER = 'designer',
PM = 'pm'
}
enum Complexity {
TRIVIAL = 'trivial',
EASY = 'easy',
MEDIUM = 'medium',
HARD = 'hard',
EPIC = 'epic'
}
enum Permission {
VIEW_IDEAS = 'view_ideas',
CREATE_IDEAS = 'create_ideas',
EDIT_OWN_IDEAS = 'edit_own_ideas',
EDIT_ANY_IDEAS = 'edit_any_ideas',
DELETE_OWN_IDEAS = 'delete_own_ideas',
DELETE_ANY_IDEAS = 'delete_any_ideas',
REORDER_IDEAS = 'reorder_ideas',
ADD_COMMENTS = 'add_comments',
DELETE_OWN_COMMENTS = 'delete_own_comments',
DELETE_ANY_COMMENTS = 'delete_any_comments',
REQUEST_AI_ESTIMATE = 'request_ai_estimate',
REQUEST_AI_SPECIFICATION = 'request_ai_specification',
EDIT_SPECIFICATION = 'edit_specification',
DELETE_AI_GENERATIONS = 'delete_ai_generations',
MANAGE_TEAM = 'manage_team',
MANAGE_ROLES = 'manage_roles',
EXPORT_IDEAS = 'export_ideas',
VIEW_AUDIT_LOG = 'view_audit_log'
}
enum AuditAction {
CREATE = 'create',
UPDATE = 'update',
DELETE = 'delete',
GENERATE = 'generate',
RESTORE = 'restore'
}
enum EntityType {
IDEA = 'idea',
COMMENT = 'comment',
SPECIFICATION = 'specification',
ESTIMATE = 'estimate',
TEAM_MEMBER = 'team_member',
USER_PERMISSIONS = 'user_permissions'
}
```
### 3.6 Permissions
#### GET /api/permissions/me
Получение прав текущего пользователя.
**Response 200:**
```typescript
{
userId: string;
email: string;
isAdmin: boolean;
permissions: Record<Permission, boolean>;
}
```
#### GET /api/permissions/users
Получение списка пользователей с правами (только для админа).
**Response 200:**
```typescript
{
data: {
userId: string;
email: string;
name: string;
isAdmin: boolean;
permissions: Record<Permission, boolean>;
lastLogin: string;
}[];
}
```
#### PATCH /api/permissions/:userId
Изменение прав пользователя (только для админа).
**Request Body:**
```typescript
Partial<Record<Permission, boolean>>
```
**Response 200:**
```typescript
{
userId: string;
permissions: Record<Permission, boolean>;
}
```
### 3.7 Audit
#### GET /api/audit
Получение истории действий.
**Query Parameters:**
```typescript
{
page?: number; // default: 1
limit?: number; // default: 50
userId?: string; // фильтр по пользователю
action?: AuditAction; // фильтр по действию
entityType?: EntityType; // фильтр по типу сущности
entityId?: string; // фильтр по ID сущности
from?: string; // ISO date - начало периода
to?: string; // ISO date - конец периода
}
```
**Response 200:**
```typescript
{
data: {
id: string;
userId: string;
userName: string;
action: AuditAction;
entityType: EntityType;
entityId: string;
oldValue: object | null;
newValue: object | null;
timestamp: string;
}[];
meta: {
total: number;
page: number;
limit: number;
totalPages: number;
}
}
```
#### POST /api/audit/:id/restore
Восстановление сущности из аудита.
**Response 201:**
```typescript
{
restored: true;
entity: Idea | Comment | TeamMember; // восстановленная сущность
}
```
#### GET /api/audit/settings
Получение настроек аудита (только для админа).
**Response 200:**
```typescript
{
retentionDays: number; // срок хранения в днях
}
```
#### PATCH /api/audit/settings
Изменение настроек аудита (только для админа).
**Request Body:**
```typescript
{
retentionDays: number; // 1-365
}
```
**Response 200:**
```typescript
{
retentionDays: number;
}
```
### 3.8 Export
#### GET /api/export/idea/:id
Экспорт идеи в DOCX.
**Response 200:**
```
Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document
Content-Disposition: attachment; filename="idea-{title}.docx"
Binary DOCX content
```
### 3.9 WebSocket Events
#### События от сервера (server → client)
```typescript
// Идеи
'idea:created' { idea: Idea }
'idea:updated' { idea: Idea }
'idea:deleted' { ideaId: string }
'ideas:reordered' { ids: string[] }
// Комментарии
'comment:created' { comment: Comment, ideaId: string }
'comment:deleted' { commentId: string, ideaId: string }
// AI
'specification:generated' { ideaId: string, specification: string }
'estimate:generated' { ideaId: string, estimate: Estimate }
// Присутствие
'users:online' { users: { id: string, name: string, avatar?: string }[] }
'user:joined' { user: { id: string, name: string } }
'user:left' { userId: string }
// Редактирование
'idea:editing' { ideaId: string, userId: string, userName: string }
'idea:stopEditing' { ideaId: string, userId: string }
```
#### События от клиента (client → server)
```typescript
// Присоединение
'join' { token: string }
// Редактирование
'startEditing' { ideaId: string }
'stopEditing' { ideaId: string }
```
---
## 4. UI Prototypes
### 4.1 Главная страница - Список идей
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 🎯 Team Planner [Команда] [+ Идея] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─ Фильтры ─────────────────────────────────────────────────────────────┐ │
│ │ [Статус ▼] [Приоритет ▼] [Модуль ▼] [Цвет ▼] [🔍 Поиск... ] │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Таблица идей ────────────────────────────────────────────────────────┐ │
│ │ ⋮⋮ │ Статус │ ⚡ │ Модуль │ Идея │ Для кого │ Оценка │ │
│ ├────┼───────────┼────┼──────────┼────────────────┼──────────┼─────────┤ │
│ │ ⋮⋮ │ 🟢 Новая │ 🔴 │ Frontend │ Добавить темну │ Все поль │ 3д │ │
│ │ ⋮⋮ │ 🟡 В обсу │ 🟡 │ Backend │ API кэширован │ Разработ │ 5д │ │
│ │ ⋮⋮ │ 🔵 Одобре │ 🟢 │ AI │ Автоматическа │ Менеджер │ 10д │ │
│ │ ⋮⋮ │ 🟣 В рабо │ 🔴 │ Backend │ Оптимизация з │ Все │ 7д │ │
│ │ │ │ │ │ │ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ Показано 4 из 24 [< Пред] 1 2 3 [След >] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Легенда:
⋮⋮ - drag handle для перетаскивания
⚡ - приоритет (иконка молнии)
🔴🟡🟢 - цветовые индикаторы приоритета
```
### 4.2 Расширенная строка с комментариями
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ ⋮⋮ │ 🟢 Новая │ 🔴 │ Frontend │ Добавить тёмную тему │ Все │ 3д [▼]│
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─ Детали ──────────────────────────────────────────────────────────────┐ │
│ │ Боль: Пользователи жалуются на яркий интерфейс вечером │ │
│ │ AI роль: — │ │
│ │ Проверка: A/B тест с 10% пользователей │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Комментарии (3) ─────────────────────────────────────────────────────┐ │
│ │ 💬 Иван: Нужно согласовать палитру с дизайнером 2ч назад │ │
│ │ └─ 💬 Мария: Уже в процессе, будет готово завтра 1ч назад │ │
│ │ 💬 Петр: Предлагаю использовать CSS variables 30м назад │ │
│ │ │ │
│ │ [Написать комментарий... ] [Отправить] │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ [🤖 Оценить AI] [✏️ Редактировать] [🗑️ Удалить] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.3 Модальное окно создания/редактирования идеи
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ Новая идея [✕] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Суть идеи * │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────┐ ┌─────────────────────┐ ┌──────────────────┐ │
│ │ Статус │ │ Приоритет │ │ Модуль │ │
│ │ [Новая ▼] │ │ [Средний ▼] │ │ [Frontend ▼] │ │
│ └─────────────────────┘ └─────────────────────┘ └──────────────────┘ │
│ │
│ Для кого эта идея │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ Какую боль решает │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ Роль AI (если применимо) │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ Быстрый способ проверить │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
│ Цвет строки │
│ [⬜][🟥][🟧][🟨][🟩][🟦][🟪] │
│ │
│ [Отмена] [💾 Сохранить] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.4 Страница управления командой
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 🎯 Team Planner [Команда] [+ Идея] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ◀ Назад к идеям │
│ │
│ ┌─ Состав команды ──────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 👨‍💻 Backend: 3 👩‍💻 Frontend: 2 🤖 AI/ML: 1 📊 Аналитик: 1 │ │
│ │ 🧪 QA: 2 🔧 DevOps: 1 🎨 Дизайн: 1 📋 PM: 1 │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Участники ───────────────────────────────────────────────────────────┐ │
│ │ Имя │ Роль │ Trivial │ Easy │ Med │ Hard │ Epic │ │
│ ├──────────────────┼────────────┼─────────┼──────┼─────┼──────┼────────┤ │
│ │ Иван Петров │ Backend │ 1ч │ 4ч │ 16ч │ 40ч │ 80ч │ │
│ │ Мария Сидорова │ Frontend │ 1ч │ 4ч │ 16ч │ 40ч │ 80ч │ │
│ │ Алексей Козлов │ AI/ML │ 2ч │ 8ч │ 24ч │ 60ч │ 120ч │ │
│ │ ... │ │ │ │ │ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ [+ Добавить участника] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.5 Модальное окно AI-оценки
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 🤖 AI-оценка трудозатрат [✕] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Идея: Добавить тёмную тему │
│ │
│ ┌─ Общая оценка ────────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ ⏱️ 24 часа (~3 рабочих дня) │ │
│ │ 📊 Сложность: Средняя │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Разбивка по ролям ───────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 👩‍💻 Frontend │ 16ч │ ████████████████░░░░ │ Средняя │ │
│ │ 🎨 Дизайнер │ 4ч │ ████░░░░░░░░░░░░░░░░ │ Лёгкая │ │
│ │ 🧪 QA │ 4ч │ ████░░░░░░░░░░░░░░░░ │ Лёгкая │ │
│ │ │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─ Рекомендации ────────────────────────────────────────────────────────┐ │
│ │ • Использовать CSS custom properties для цветовой схемы │ │
│ │ • Добавить переключатель в настройки пользователя │ │
│ │ • Учесть системные настройки (prefers-color-scheme) │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ [Сохранить оценку] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.6 Модальное окно мини-ТЗ
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 📋 Техническое задание [✕] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Идея: Добавить тёмную тему │
│ Сгенерировано: 15.01.2026, 12:30 │
│ │
│ ┌─ Содержание ТЗ ─────────────────────────────────────────────────────────┐│
│ │ ││
│ │ ## Цель ││
│ │ Реализовать тёмную тему оформления для снижения нагрузки на глаза ││
│ │ пользователей при работе в условиях низкой освещённости. ││
│ │ ││
│ │ ## Функциональные требования ││
│ │ - Переключатель темы в настройках пользователя ││
│ │ - Автоматическое определение системной темы ││
│ │ - Сохранение выбора пользователя ││
│ │ ││
│ │ ## Технические требования ││
│ │ - CSS custom properties для цветовой схемы ││
│ │ - Поддержка prefers-color-scheme ││
│ │ - localStorage для сохранения выбора ││
│ │ ││
│ │ ## Критерии приёмки ││
│ │ - [ ] Все элементы UI корректно отображаются в тёмной теме ││
│ │ - [ ] Переключение работает мгновенно без перезагрузки ││
│ │ - [ ] Выбор сохраняется между сессиями ││
│ │ ││
│ │ ## Зависимости и риски ││
│ │ - Необходимо согласование цветовой палитры с дизайнером ││
│ │ - Возможны проблемы с контрастностью на некоторых элементах ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ [✏️ Редактировать] [Закрыть] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Режим редактирования:
┌─────────────────────────────────────────────────────────────────────────────┐
│ 📋 Редактирование ТЗ [✕] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Идея: Добавить тёмную тему │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐│
│ │ ## Цель ││
│ │ Реализовать тёмную тему оформления для снижения нагрузки... ││
│ │ ││
│ │ ## Функциональные требования ││
│ │ - Переключатель темы в настройках пользователя ││
│ │ ... ││
│ │ [textarea, multiline]││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ [Отмена] [💾 Сохранить] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Режим генерации (loading):
┌─────────────────────────────────────────────────────────────────────────────┐
│ 📋 Техническое задание [✕] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Идея: Добавить тёмную тему │
│ │
│ │
│ Генерируем техническое задание... │
│ │
│ ═══════════════════ │
│ [progress bar] │
│ │
│ │
│ [Отмена] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.7 Панель администратора — Управление правами
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 🎯 Team Planner [☀️/🌙] [👥 2 онлайн] [Админ] [Выход] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ [Идеи] [Команда] [Администрирование] [История] │
│ ───────────────────── │
│ │
│ ┌─ Управление правами пользователей ──────────────────────────────────────┐│
│ │ ││
│ │ ┌─────────────────────────────────────────────────────────────────────┐││
│ │ │ Пользователь │ Послед. вход │ Идеи │ Свои │ Чужие│ AI │ ... │││
│ │ ├───────────────────┼──────────────┼──────┼──────┼──────┼─────┼─────┤││
│ │ │ 👤 Иван Петров │ 10 мин назад │ ✅ │ ✅ │ ❌ │ ✅ │ │││
│ │ │ ivan@mail.ru │ │ │ │ │ │ │││
│ │ │ 👤 Мария Сидорова │ 2 дня назад │ ✅ │ ✅ │ ✅ │ ✅ │ │││
│ │ │ maria@mail.ru │ │ │ │ │ │ │││
│ │ │ 👤 Новый юзер │ Никогда │ ✅ │ ❌ │ ❌ │ ❌ │ │││
│ │ │ new@mail.ru │ (только view)│ │ │ │ │ │││
│ │ └─────────────────────────────────────────────────────────────────────┘││
│ │ ││
│ │ Легенда колонок: ││
│ │ Идеи = create_ideas, Свои = edit_own_ideas, Чужие = edit_any_ideas ││
│ │ AI = request_ai_estimate + request_ai_specification ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ ┌─ Настройки аудита ──────────────────────────────────────────────────────┐│
│ │ ││
│ │ Срок хранения истории: [30] дней [Сохранить] ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.8 История действий (Аудит)
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 🎯 Team Planner [☀️/🌙] [👥 2 онлайн] [Иван] [Выход] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ [Идеи] [Команда] [Администрирование] [История] │
│ ──────── │
│ │
│ ┌─ Фильтры ───────────────────────────────────────────────────────────────┐│
│ │ [Пользователь ▼] [Действие ▼] [Сущность ▼] [С: 📅] [По: 📅] [Поиск...] ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ ┌─ История действий ──────────────────────────────────────────────────────┐│
│ │ ││
│ │ ┌─────────────────────────────────────────────────────────────────────┐││
│ │ │ Дата/Время │ Пользователь │ Действие │ Сущность │ Детали │││
│ │ ├──────────────────┼──────────────┼──────────┼──────────┼───────────┤││
│ │ │ 15.01 14:30 │ Иван │ ✏️ update│ Идея │ [👁️ Diff]│││
│ │ │ 15.01 14:25 │ Мария │ create│ Коммент. │ [👁️] │││
│ │ │ 15.01 14:20 │ Иван │ 🗑️ delete│ Идея │ [🔄 Восст]││
│ │ │ 15.01 14:15 │ AI │ 🤖 gen. │ ТЗ │ [👁️] │││
│ │ │ 15.01 14:10 │ Мария │ create│ Идея │ [👁️] │││
│ │ └─────────────────────────────────────────────────────────────────────┘││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ Показано 5 из 128 [< Пред] 1 2 3 [След >] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Просмотр изменений (diff):
┌─────────────────────────────────────────────────────────────────────────────┐
│ 📋 Детали изменения [✕] │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ Пользователь: Иван Петров │
│ Дата: 15.01.2026, 14:30 │
│ Действие: Обновление идеи │
│ │
│ ┌─ Изменения ─────────────────────────────────────────────────────────────┐│
│ │ ││
│ │ Статус: 🟢 Новая → 🟡 В обсуждении ││
│ │ Приоритет: Средний → Высокий ││
│ │ ││
│ └─────────────────────────────────────────────────────────────────────────┘│
│ │
│ [Закрыть] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
```
### 4.9 Главная страница с онлайн-пользователями и темой
```
┌─────────────────────────────────────────────────────────────────────────────┐
│ 🎯 Team Planner [☀️ Светлая / 🌙 Тёмная] [👥 3] [Иван] [⎋ Выход] │
├─────────────────────────────────────────────────────────────────────────────┤
│ ┌───────────────────┐ │
│ [Идеи] [Команда] [История] Онлайн сейчас:│ 🟢 Иван │ │
│ ─────── │ 🟢 Мария │ │
│ │ 🟢 Алексей │ │
│ ┌─ Фильтры ──────────────────────┐ └───────────────────┘ │
│ │ [Статус ▼] [Приоритет ▼] ... │ │
│ └────────────────────────────────┘ │
│ │
│ ┌─ Таблица идей ───────────────────────────────────────────────────────┐ │
│ │ ⋮⋮│Статус │⚡│Модуль │Идея │Автор │Оценка│ │ │ │
│ ├───┼─────────┼──┼───────┼──────────────┼──────┼──────┼──────┼─────────┤ │
│ │⋮⋮ │🟢 Новая │🔴│Front │Тёмная тема │Иван │3д │[📋][⬇️]│[🗑️] │ │
│ │ │ │ │ │✏️ Мария ред. │ │ │ │ │ │
│ │⋮⋮ │🟡 Обсужд│🟡│Back │API кэш │Мария │5д │[📋][⬇️]│[🗑️] │ │
│ └───────────────────────────────────────────────────────────────────────┘ │
│ │
│ [+ Новая идея] │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
Легенда:
📋 - Кнопка ТЗ
⬇️ - Кнопка экспорта в DOCX
✏️ Мария ред. - индикатор что Мария сейчас редактирует эту идею
```
---
## 5. UI Specification
### 5.1 Цветовая палитра
#### Основные цвета (Светлая тема)
```
Primary: #1976D2 (MUI Blue 700)
Primary Light: #42A5F5 (MUI Blue 400)
Primary Dark: #1565C0 (MUI Blue 800)
Secondary: #9C27B0 (MUI Purple 500)
Background: #FFFFFF
Surface: #F5F5F5 (Grey 100)
Text Primary: #212121 (Grey 900)
Text Secondary: #757575 (Grey 600)
```
#### Основные цвета (Тёмная тема)
```
Primary: #90CAF9 (MUI Blue 200)
Primary Light: #E3F2FD (MUI Blue 50)
Primary Dark: #42A5F5 (MUI Blue 400)
Secondary: #CE93D8 (MUI Purple 200)
Background: #121212
Surface: #1E1E1E
Paper: #2D2D2D
Text Primary: #FFFFFF
Text Secondary: #B0B0B0
```
#### Статусы идей
```
New: #4CAF50 (Green 500) 🟢
Discussing: #FF9800 (Orange 500) 🟡
Approved: #2196F3 (Blue 500) 🔵
In Progress: #9C27B0 (Purple 500) 🟣
Done: #607D8B (Blue Grey 500) ⚫
Rejected: #F44336 (Red 500) 🔴
```
#### Приоритеты
```
Critical: #D32F2F (Red 700) фон: #FFEBEE
High: #F57C00 (Orange 700) фон: #FFF3E0
Medium: #FBC02D (Yellow 700) фон: #FFFDE7
Low: #388E3C (Green 700) фон: #E8F5E9
```
#### Цвета для маркировки строк
```
Без цвета: transparent
Красный: #FFCDD2 (Red 100)
Оранжевый: #FFE0B2 (Orange 100)
Жёлтый: #FFF9C4 (Yellow 100)
Зелёный: #C8E6C9 (Green 100)
Голубой: #BBDEFB (Blue 100)
Фиолетовый: #E1BEE7 (Purple 100)
```
### 5.2 Типографика
```
Font Family: 'Roboto', 'Helvetica', 'Arial', sans-serif
H1: 24px, weight 500, line-height 1.2
H2: 20px, weight 500, line-height 1.3
H3: 16px, weight 500, line-height 1.4
Body1: 14px, weight 400, line-height 1.5
Body2: 12px, weight 400, line-height 1.43
Caption: 12px, weight 400, line-height 1.66, color: #757575
```
### 5.3 Компоненты
#### Кнопки
| Тип | Использование | Стиль |
|-----|---------------|-------|
| Primary | Главное действие (Сохранить, Создать) | Filled, Primary color |
| Secondary | Вторичные действия (Отмена) | Outlined, Grey |
| Text | Третичные действия (Назад) | Text only |
| Icon | Действия в строке таблицы | IconButton, 40x40px |
| Danger | Удаление | Filled, Red |
```
Border Radius: 4px
Height: 36px (medium), 40px (large)
Padding: 8px 16px
```
#### Состояния кнопок
```
Default: opacity 1
Hover: brightness 0.95, shadow elevation 2
Active: brightness 0.9
Disabled: opacity 0.38, cursor not-allowed
Loading: показать CircularProgress (20px), disabled
```
#### Инпуты
```
Height: 40px
Border: 1px solid #E0E0E0
Border Radius: 4px
Padding: 8px 12px
Focus: border-color: Primary, box-shadow: 0 0 0 2px Primary/20%
Error: border-color: #D32F2F, helper text red
Disabled: background: #F5F5F5, opacity 0.6
```
#### Таблица
```
Header:
Background: #FAFAFA
Font: 14px, weight 500
Height: 48px
Border: 1px solid #E0E0E0 (bottom)
Row:
Height: 52px
Border: 1px solid #E0E0E0 (bottom)
Hover: background #F5F5F5
Row (colored):
Background: соответствующий цвет из палитры маркировки
Hover: darken 5%
Cell:
Padding: 16px
Vertical align: middle
```
#### Dropdown/Select
```
Trigger: как Input
Menu:
Background: #FFFFFF
Shadow: 0 2px 8px rgba(0,0,0,0.15)
Border Radius: 4px
Max Height: 300px (scroll)
Item:
Height: 40px
Padding: 8px 16px
Hover: background #F5F5F5
Selected: background Primary/10%, color Primary
```
#### Модальные окна
```
Overlay: rgba(0, 0, 0, 0.5)
Background: #FFFFFF
Border Radius: 8px
Shadow: 0 8px 32px rgba(0,0,0,0.2)
Width: 480px (small), 640px (medium), 800px (large)
Max Height: 90vh
Padding: 24px
Header:
Font: H2
Border: 1px solid #E0E0E0 (bottom)
Padding: 24px 24px 16px
Footer:
Border: 1px solid #E0E0E0 (top)
Padding: 16px 24px
Justify: flex-end
Gap: 12px
```
### 5.4 Состояния загрузки
#### Skeleton Loader
```
Для таблицы:
- Показать 5 строк skeleton
- Анимация: shimmer effect (gradient slide)
- Background: #E0E0E0
- Highlight: #F5F5F5
Для карточек/полей:
- Прямоугольники с закруглением 4px
- Высота соответствует контенту
```
#### Spinner (CircularProgress)
```
Size: 24px (в кнопках), 40px (в контенте)
Color: Primary
Thickness: 3.6
```
#### Inline Loading (в ячейках таблицы)
```
Показать маленький spinner (16px) справа от текста
Текст затемнить (opacity 0.5)
```
### 5.5 Анимации
```
Duration:
Fast: 150ms (hover effects)
Normal: 250ms (transitions)
Slow: 350ms (modals, large elements)
Easing:
Standard: cubic-bezier(0.4, 0, 0.2, 1)
Enter: cubic-bezier(0.0, 0, 0.2, 1)
Exit: cubic-bezier(0.4, 0, 1, 1)
Drag & Drop:
Item lift: scale 1.02, shadow elevation 8
Drop zone: border 2px dashed Primary, background Primary/5%
```
### 5.6 Иконки
Использовать **Material Icons** (MUI Icons).
```
Размеры:
Small: 18px
Medium: 24px (default)
Large: 36px
Основные иконки:
Добавить: Add (+)
Редактировать: Edit (карандаш)
Удалить: Delete (корзина)
Drag: DragIndicator (⋮⋮)
Фильтр: FilterList
Поиск: Search (🔍)
Комментарий: ChatBubbleOutline
AI: AutoAwesome (✨) или SmartToy (🤖)
Развернуть: ExpandMore
Свернуть: ExpandLess
```
### 5.7 Отступы и сетка
```
Spacing unit: 8px
Margins/Paddings:
xs: 4px
sm: 8px
md: 16px
lg: 24px
xl: 32px
Container:
Max width: 1440px
Padding: 24px (desktop), 16px (tablet), 12px (mobile)
Table:
Min width: 1024px
Horizontal scroll на меньших экранах
```
### 5.8 Breakpoints
```
xs: 0px
sm: 600px
md: 900px
lg: 1200px
xl: 1536px
Desktop-first approach:
Основной дизайн для lg+ (1200px+)
Адаптация для md (900-1199px)
Горизонтальный скролл для sm и ниже
```
---
## 6. Error States
### 6.1 Validation Errors
```
Inline под полем:
Color: #D32F2F
Font: 12px
Icon: ErrorOutline (слева от текста)
Margin top: 4px
```
### 6.2 API Errors
```
Toast notification (Snackbar):
Position: bottom-left
Duration: 5000ms (auto-hide)
Background: #D32F2F
Color: #FFFFFF
Action: "Повторить" (если применимо)
```
### 6.3 Empty States
```
Центрированный блок:
Icon: 64px, Grey 400
Title: H2, Grey 700
Description: Body1, Grey 500
Action: Primary Button
Примеры:
Нет идей: "Список пуст. Создайте первую идею!"
Нет команды: "Добавьте членов команды для AI-оценки"
Нет результатов: "По вашему запросу ничего не найдено"
```
---
## 7. Авторизация (Keycloak)
### 7.1 Конфигурация Keycloak
| Параметр | Значение |
|----------|----------|
| URL | https://auth.vigdorov.ru |
| Realm | `team-planner` |
| Client ID | `team-planner-frontend` |
| Client Type | Public (no secret) |
| Authentication Flow | Authorization Code + PKCE |
### 7.2 Настройка Client в Keycloak
```
Client authentication: OFF (public client)
Standard flow: ON
Direct access grants: OFF
Valid redirect URIs: http://localhost:4000/*
Web origins: http://localhost:4000
```
### 7.3 Environment Variables
**Backend (.env):**
```
KEYCLOAK_REALM_URL=https://auth.vigdorov.ru/realms/team-planner
ADMIN_EMAIL=admin@vigdorov.ru # email администратора из K8s Secret
AI_PROXY_BASE_URL=http://ai-proxy:3000 # URL AI Proxy сервиса
AI_PROXY_API_KEY=... # API ключ для AI Proxy
AUDIT_RETENTION_DAYS=30 # срок хранения аудита (по умолчанию)
```
**Frontend (.env):**
```
VITE_KEYCLOAK_URL=https://auth.vigdorov.ru
VITE_KEYCLOAK_REALM=team-planner
VITE_KEYCLOAK_CLIENT_ID=team-planner-frontend
VITE_WS_URL=wss://team-planner.vigdorov.ru # WebSocket URL
```
### 7.4 JWT Validation (Backend)
```typescript
// Валидация через JWKS (публичные ключи)
secretOrKeyProvider: passportJwtSecret({
cache: true,
rateLimit: true,
jwksRequestsPerMinute: 5,
jwksUri: `${realmUrl}/protocol/openid-connect/certs`,
})
// Проверки
issuer: KEYCLOAK_REALM_URL
algorithms: ['RS256']
```
### 7.5 Защищённые и публичные endpoints
| Endpoint | Доступ | Право / Декоратор |
|----------|--------|-------------------|
| `GET /` | Public | `@Public()` |
| `GET /health` | Public | `@Public()` |
| `GET /api/ideas` | Protected | `view_ideas` |
| `POST /api/ideas` | Protected | `create_ideas` |
| `PATCH /api/ideas/:id` | Protected | `edit_own_ideas` / `edit_any_ideas` |
| `DELETE /api/ideas/:id` | Protected | `delete_own_ideas` / `delete_any_ideas` |
| `PATCH /api/ideas/reorder` | Protected | `reorder_ideas` |
| `POST /api/ai/estimate` | Protected | `request_ai_estimate` |
| `POST /api/ai/generate-specification` | Protected | `request_ai_specification` |
| `GET /api/permissions/me` | Protected | — (все пользователи) |
| `GET /api/permissions/users` | Protected | Admin only |
| `PATCH /api/permissions/:userId` | Protected | Admin only |
| `GET /api/audit` | Protected | `view_audit_log` |
| `POST /api/audit/:id/restore` | Protected | Admin only |
| `GET /api/export/idea/:id` | Protected | `export_ideas` |
| WebSocket | Protected | JWT в handshake |