# Архитектура Team Planner
---
## 1. C4 Model
### 1.1 Level 1: System Context
```mermaid
flowchart TB
subgraph external [" "]
User["👤 Пользователь
Член команды разработки"]
AI["🤖 AI Proxy Service
LLM для оценки задач"]
KC["🔐 Keycloak
auth.vigdorov.ru
Identity Provider"]
end
subgraph system ["Team Planner"]
TP["🎯 Team Planner
Приложение для управления
бэклогом идей команды"]
end
User -->|"Управляет идеями,
командой, комментариями
[HTTPS]"| TP
User -->|"Авторизация
[OIDC/PKCE]"| KC
KC -->|"JWT токены"| TP
TP -->|"Запросы на оценку
трудозатрат
[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["👤 Пользователь
Член команды разработки"]
Admin["👤 Администратор
email из K8s Secret"]
KC["🔐 Keycloak
auth.vigdorov.ru"]
subgraph TeamPlanner ["Team Planner"]
SPA["📱 Frontend SPA
React, TypeScript, MUI
Веб-интерфейс для
работы с идеями"]
API["⚙️ Backend API
NestJS, TypeScript
REST API"]
WS["🔌 WebSocket Gateway
Socket.io
Real-time обновления"]
DB[("🗄️ Database
PostgreSQL
Идеи, команда,
права, аудит")]
end
AI["🤖 AI Proxy Service
LLM для оценки задач"]
User -->|"Использует
[HTTPS]"| SPA
Admin -->|"Управляет правами
[HTTPS]"| SPA
User <-->|"OIDC Login
[Redirect]"| KC
SPA -->|"API запросы
[REST + Bearer JWT]"| API
SPA <-->|"Real-time
[WebSocket]"| WS
API -.->|"Валидация JWT
[JWKS]"| KC
API -->|"Читает/пишет
[TypeORM]"| DB
WS -->|"Читает
[TypeORM]"| DB
API -->|"Оценка трудозатрат
[HTTPS/REST]"| AI
API -->|"Уведомления
[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
CRUD идей, reorder"]
CommentsCtrl["CommentsController
Комментарии к идеям"]
TeamCtrl["TeamController
Члены команды, роли"]
AiCtrl["AiController
AI-оценка, генерация ТЗ"]
PermCtrl["PermissionsController
Управление правами"]
AuditCtrl["AuditController
История действий"]
ExportCtrl["ExportController
Экспорт в DOCX"]
end
subgraph Services ["Services"]
IdeasSvc["IdeasService"]
CommentsSvc["CommentsService"]
TeamSvc["TeamService"]
AiSvc["AiService
Интеграция с AI Proxy"]
PermSvc["PermissionsService
Проверка/управление правами"]
AuditSvc["AuditService
Логирование действий"]
ExportSvc["ExportService
Генерация DOCX"]
end
subgraph Gateway ["WebSocket Gateway"]
WSGateway["EventsGateway
Socket.io
Real-time события"]
end
subgraph Auth ["Auth Module"]
JwtStrategy["JwtStrategy
JWKS валидация"]
JwtGuard["JwtAuthGuard
Глобальная защита"]
PermGuard["PermissionsGuard
Проверка прав"]
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
Главная страница"]
TeamPage["TeamPage
Управление командой"]
AdminPage["AdminPage
Панель администратора"]
AuditPage["AuditPage
История действий"]
LoginPage["LoginPage
Страница входа"]
end
subgraph Components ["UI Components"]
IdeasTable["IdeasTable
Таблица идей + D&D"]
IdeasFilters["IdeasFilters
Фильтры и поиск"]
CreateIdeaModal["CreateIdeaModal"]
AiEstimateModal["AiEstimateModal
Результат AI-оценки"]
CommentsPanel["CommentsPanel
Комментарии к идее"]
SpecModal["SpecificationModal
Просмотр/редакт. ТЗ"]
PermissionsTable["PermissionsTable
Таблица прав доступа"]
AuditLogTable["AuditLogTable
Таблица истории"]
ThemeToggle["ThemeToggle
Переключатель темы"]
OnlineUsers["OnlineUsers
Онлайн пользователи"]
end
subgraph State ["State Management"]
IdeasStore["IdeasStore
Zustand"]
ThemeStore["ThemeStore
Zustand"]
ReactQuery["React Query
Кэш, мутации"]
end
subgraph ServicesLayer ["Services"]
IdeasAPI["ideasApi"]
TeamAPI["teamApi"]
AiAPI["aiApi"]
CommentsAPI["commentsApi"]
PermissionsAPI["permissionsApi"]
AuditAPI["auditApi"]
ExportAPI["exportApi"]
end
subgraph AuthLayer ["Auth"]
AuthProvider["AuthProvider
Keycloak context"]
ApiClient["api.ts
Axios + interceptors"]
end
subgraph WebSocketLayer ["WebSocket"]
WSProvider["WebSocketProvider
Socket.io client"]
WSHooks["useWebSocket
Real-time хуки"]
end
subgraph ThemeLayer ["Theme"]
ThemeProvider["ThemeProvider
MUI dark/light"]
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
(React)
participant KC as Keycloak
(auth.vigdorov.ru)
participant BE as Backend
(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
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
(React)
participant BE as Backend
(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
(React)
participant BE as Backend
(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
(React)
participant BE as Backend
(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
(React)
participant BE as Backend
(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 с описанием идеи
и составом команды
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
(React)
participant BE as Backend
(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
(React)
participant BE as Backend
(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
(React)
participant BE as Backend
(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
(React)
participant BE as Backend
(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`
**Response 200:** `TeamMember`
#### DELETE /api/team/members/:id
Удаление члена команды.
**Response 204:** No Content
#### GET /api/team/summary
Сводка по команде.
**Response 200:**
```typescript
{
totalMembers: number;
byRole: Record;
}
```
### 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;
}
```
#### GET /api/permissions/users
Получение списка пользователей с правами (только для админа).
**Response 200:**
```typescript
{
data: {
userId: string;
email: string;
name: string;
isAdmin: boolean;
permissions: Record;
lastLogin: string;
}[];
}
```
#### PATCH /api/permissions/:userId
Изменение прав пользователя (только для админа).
**Request Body:**
```typescript
Partial>
```
**Response 200:**
```typescript
{
userId: string;
permissions: Record;
}
```
### 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 |