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

88 KiB
Raw Permalink Blame History

Архитектура Team Planner


1. C4 Model

1.1 Level 1: System Context

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

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

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

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)

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 Создание идеи

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-редактирование идеи

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 (изменение порядка)

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-оценка трудозатрат

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 Генерация мини-ТЗ

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 Редактирование ТЗ

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 Добавление комментария

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 Загрузка списка идей с фильтрами

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)

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 Проверка прав доступа

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 Изменение прав пользователя (Админ)

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 Просмотр и восстановление из аудита

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

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:

{
  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:

{
  data: Idea[];
  meta: {
    total: number;
    page: number;
    limit: number;
    totalPages: number;
  }
}

POST /api/ideas

Создание новой идеи.

Request Body:

{
  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:

{
  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:

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:

{
  ids: string[];  // ID идей в новом порядке
}

Response 200:

{
  success: true;
}

3.2 Comments

GET /api/ideas/:ideaId/comments

Получение комментариев к идее.

Response 200:

{
  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:

{
  text: string;
  parentId?: string;  // для ответа на комментарий
}

Response 201: Comment

DELETE /api/comments/:id

Удаление комментария.

Response 204: No Content

3.3 Team

GET /api/team/members

Получение списка членов команды.

Response 200:

{
  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:

{
  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:

{
  totalMembers: number;
  byRole: Record<TeamRole, number>;
}

3.4 AI

POST /api/ai/estimate

AI-оценка трудозатрат для идеи.

Request Body:

{
  ideaId: string;
}

Response 200:

{
  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:

{
  ideaId: string;
}

Response 200:

{
  ideaId: string;
  specification: string;      // markdown текст ТЗ
  generatedAt: string;        // ISO timestamp
}

Структура генерируемого ТЗ:

## Цель
[что должно быть достигнуто]

## Функциональные требования
- [требование 1]
- [требование 2]
...

## Технические требования
[архитектура, интеграции, ограничения]

## Критерии приёмки
- [критерий 1]
- [критерий 2]
...

## Зависимости и риски
[что может повлиять на реализацию]

3.5 Enums

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:

{
  userId: string;
  email: string;
  isAdmin: boolean;
  permissions: Record<Permission, boolean>;
}

GET /api/permissions/users

Получение списка пользователей с правами (только для админа).

Response 200:

{
  data: {
    userId: string;
    email: string;
    name: string;
    isAdmin: boolean;
    permissions: Record<Permission, boolean>;
    lastLogin: string;
  }[];
}

PATCH /api/permissions/:userId

Изменение прав пользователя (только для админа).

Request Body:

Partial<Record<Permission, boolean>>

Response 200:

{
  userId: string;
  permissions: Record<Permission, boolean>;
}

3.7 Audit

GET /api/audit

Получение истории действий.

Query Parameters:

{
  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:

{
  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:

{
  restored: true;
  entity: Idea | Comment | TeamMember;  // восстановленная сущность
}

GET /api/audit/settings

Получение настроек аудита (только для админа).

Response 200:

{
  retentionDays: number;  // срок хранения в днях
}

PATCH /api/audit/settings

Изменение настроек аудита (только для админа).

Request Body:

{
  retentionDays: number;  // 1-365
}

Response 200:

{
  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)

// Идеи
'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)

// Присоединение
'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)

// Валидация через 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