# Архитектура Team Planner --- ## 1. C4 Model ### 1.1 Level 1: System Context ```mermaid flowchart TB subgraph external [" "] User["👤 Пользователь
Член команды разработки"] AI["🤖 AI Proxy Service
LLM для оценки задач"] KC["🔐 Keycloak
auth.vigdorov.ru
Identity Provider
"] end subgraph system ["Team Planner"] TP["🎯 Team Planner
Приложение для управления
бэклогом идей команды
"] end User -->|"Управляет идеями,
командой, комментариями
[HTTPS]"| TP User -->|"Авторизация
[OIDC/PKCE]"| KC KC -->|"JWT токены"| TP TP -->|"Запросы на оценку
трудозатрат
[HTTPS/REST]"| AI style TP fill:#1168bd,color:#fff style User fill:#08427b,color:#fff style AI fill:#999,color:#fff style KC fill:#c92a2a,color:#fff ``` ### 1.2 Level 2: Container Diagram ```mermaid flowchart TB User["👤 Пользователь
Член команды разработки"] Admin["👤 Администратор
email из K8s Secret"] KC["🔐 Keycloak
auth.vigdorov.ru"] subgraph TeamPlanner ["Team Planner"] SPA["📱 Frontend SPA
React, TypeScript, MUI

Веб-интерфейс для
работы с идеями"] API["⚙️ Backend API
NestJS, TypeScript

REST API"] WS["🔌 WebSocket Gateway
Socket.io

Real-time обновления"] DB[("🗄️ Database
PostgreSQL

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