# Архитектура 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>"]
    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 + WebSocket"]
        DB[("🗄️ Database<br/><i>PostgreSQL</i><br/><br/>Хранение идей,<br/>команды, комментариев")]
    end

    AI["🤖 AI Proxy Service<br/><i>LLM для оценки задач</i>"]

    User -->|"Использует<br/>[HTTPS]"| SPA
    User <-->|"OIDC Login<br/>[Redirect]"| KC
    SPA -->|"API запросы<br/>[REST + Bearer JWT]"| API
    API -.->|"Валидация JWT<br/>[JWKS]"| KC
    API -->|"Читает/пишет<br/>[TypeORM]"| DB
    API -->|"Оценка трудозатрат<br/>[HTTPS/REST]"| AI

    style SPA fill:#438dd5,color:#fff
    style API fill:#438dd5,color:#fff
    style DB fill:#438dd5,color:#fff
    style User fill:#08427b,color:#fff
    style AI fill:#999,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 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: Отображает таблицу
```

---

## 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[];
  };
}
```

### 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'
}
```

---

## 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)                  │ │
│  └───────────────────────────────────────────────────────────────────────┘ │
│                                                                             │
│                                              [Сохранить оценку]            │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
```

---

## 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)
```

#### Статусы идей
```
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
```

**Frontend (.env):**
```
VITE_KEYCLOAK_URL=https://auth.vigdorov.ru
VITE_KEYCLOAK_REALM=team-planner
VITE_KEYCLOAK_CLIENT_ID=team-planner-frontend
```

### 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 | — |
| `POST /api/ideas` | Protected | — |
| `PATCH /api/ideas/:id` | Protected | — |
| `DELETE /api/ideas/:id` | Protected | — |
| Все остальные | Protected | — |
