diff --git a/docs/marketing-api-with-jwt-frontend.md b/docs/marketing-api-with-jwt-frontend.md new file mode 100644 index 0000000..10ce258 --- /dev/null +++ b/docs/marketing-api-with-jwt-frontend.md @@ -0,0 +1,987 @@ +# API Документация: Маркетинговый анализ и стратегии (Frontend/AI Agent) + +## Базовый URL + +``` +https://api.konturai.kz +``` + +## Обзор + +API для генерации маркетингового анализа и стратегий на основе данных о бизнесе. Все эндпоинты требуют JWT аутентификации для связи данных с пользователем. + +**Важные изменения:** + +- ✅ Все эндпоинты теперь требуют JWT токен в заголовке `Authorization` +- ✅ Пользователи могут видеть только свои анализы и стратегии +- ✅ Добавлена детальная история статусов для каждого анализа и стратегии +- ✅ Новые эндпоинты для получения списка всех анализов/стратегий пользователя + +--- + +## Аутентификация + +Все запросы должны включать JWT токен в заголовке `Authorization`: + +``` +Authorization: Bearer +``` + +### Структура JWT токена + +JWT токен содержит следующую информацию: + +- **sub**: Email пользователя +- **uid**: ID пользователя (Long) - используется для связи данных +- **roles**: Роли пользователя (String, разделённые запятыми) + +### Ошибки аутентификации + +Если токен отсутствует или невалиден, API вернет: + +```json +{ + "success": false, + "message": "Не авторизован", + "error": { + "code": "UNAUTHORIZED", + "message": "Требуется аутентификация. Пожалуйста, предоставьте валидный JWT токен." + } +} +``` + +**HTTP статус**: `401 Unauthorized` + +--- + +## Эндпоинты + +### 1. Запуск маркетингового анализа + +**POST** `/api/marketing/analysis/start` + +Создает новую задачу на генерацию маркетингового анализа и запускает асинхронную обработку. Анализ автоматически связывается с пользователем из JWT токена. + +#### Заголовки запроса + +``` +Content-Type: application/json +Authorization: Bearer +``` + +#### Тело запроса (JSON) + +| Поле | Тип | Обязательный | Описание | Пример значения | +| ---------------- | ------ | ------------ | ------------------------------ | -------------------------------- | +| `product` | string | ✅ | Название продукта или услуги | "Веб-разработка" | +| `location` | string | ✅ | Географическая локация работы | "Алматы, Казахстан" | +| `client` | string | ✅ | Тип целевой аудитории | "B2B клиенты" | +| `differentiator` | string | ✅ | Уникальные особенности бизнеса | "Быстрая разработка за 2 недели" | + +#### Валидация полей + +**`product`** (string, обязательное) + +- Минимальная длина: 3 символа +- Максимальная длина: 200 символов + +**`location`** (string, обязательное) + +- Минимальная длина: 2 символа +- Максимальная длина: 150 символов + +**`client`** (string, обязательное) + +- Допустимые значения: + - `"B2B клиенты"` + - `"B2C клиенты"` + - `"Частные лица"` + - `"Корпорации"` + - `"Малый бизнес"` + +**`differentiator`** (string, обязательное) + +- Минимальная длина: 10 символов +- Максимальная длина: 500 символов + +#### Пример запроса + +```javascript +const response = await fetch( + 'https://api.konturai.kz/api/marketing/analysis/start', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${jwtToken}`, + }, + body: JSON.stringify({ + product: 'Разработка мобильных приложений', + location: 'Нур-Султан, Казахстан', + client: 'B2B клиенты', + differentiator: 'Специализируемся на быстрой разработке MVP за 4 недели', + }), + } +); +``` + +#### Пример успешного ответа (200 OK) + +```json +{ + "success": true, + "message": "Анализ запущен успешно", + "data": { + "analysisId": "507f1f77bcf86cd799439011", + "status": "processing", + "estimatedCompletionTime": "2025-01-20T15:38:00", + "message": "Анализ запущен успешно. Результаты будут готовы в течение 5-10 минут." + } +} +``` + +--- + +### 2. Получение результата анализа + +**GET** `/api/marketing/analysis/{analysisId}` + +Возвращает статус и результаты анализа по идентификатору. Пользователь может получить только свои анализы. + +#### Заголовки запроса + +``` +Authorization: Bearer +``` + +#### Параметры пути + +| Параметр | Тип | Описание | +| ------------ | ------ | --------------------- | +| `analysisId` | string | Идентификатор анализа | + +#### Пример запроса + +```javascript +const response = await fetch( + `https://api.konturai.kz/api/marketing/analysis/${analysisId}`, + { + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + } +); +``` + +#### Пример ответа (когда анализ завершен - 200 OK) + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": { + "analysisId": "507f1f77bcf86cd799439011", + "status": "completed", + "createdAt": "2025-01-20T15:30:00", + "completedAt": "2025-01-20T15:38:00", + "report": { + "summary": "Краткое резюме анализа...", + "targetAudience": { + "description": "Описание целевой аудитории...", + "channels": ["Instagram", "LinkedIn", "Telegram"] + }, + "recommendations": ["Рекомендация 1", "Рекомендация 2"], + "strategy": { + "duration": "2 недели", + "channels": ["Instagram", "Telegram", "21MC"], + "contentTypes": ["посты", "сторис", "баннеры"] + }, + "pdfUrl": "/api/marketing/analysis/507f1f77bcf86cd799439011/download" + } + } +} +``` + +#### Статусы анализа + +| Статус | Описание | +| ------------ | ----------------------------- | +| `queued` | Запрос в очереди на обработку | +| `processing` | Анализ выполняется | +| `completed` | Анализ завершен успешно | +| `failed` | Анализ завершился с ошибкой | + +#### Ошибки доступа + +Если пользователь пытается получить доступ к анализу другого пользователя: + +```json +{ + "success": false, + "message": "Доступ запрещен", + "error": { + "code": "FORBIDDEN", + "message": "У вас нет доступа к этому анализу" + } +} +``` + +**HTTP статус**: `403 Forbidden` + +--- + +### 3. Получение списка всех анализов пользователя + +**GET** `/api/marketing/analysis/my` + +Возвращает список всех анализов текущего пользователя, отсортированных по дате создания (новые первыми). + +#### Заголовки запроса + +``` +Authorization: Bearer +``` + +#### Пример запроса + +```javascript +const response = await fetch( + 'https://api.konturai.kz/api/marketing/analysis/my', + { + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + } +); +``` + +#### Пример успешного ответа (200 OK) + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": [ + { + "analysisId": "507f1f77bcf86cd799439011", + "product": "Разработка мобильных приложений", + "location": "Нур-Султан, Казахстан", + "clientType": "B2B клиенты", + "differentiator": "Быстрая разработка MVP за 4 недели", + "status": "completed", + "userId": "12345", + "createdAt": "2025-01-20T15:30:00", + "completedAt": "2025-01-20T15:38:00", + "statusHistory": [ + { + "status": "queued", + "timestamp": "2025-01-20T15:30:00", + "message": "Анализ создан и добавлен в очередь" + }, + { + "status": "processing", + "timestamp": "2025-01-20T15:30:05", + "message": "Начата обработка анализа" + }, + { + "status": "completed", + "timestamp": "2025-01-20T15:38:00", + "message": "Анализ успешно завершен" + } + ] + }, + { + "analysisId": "507f1f77bcf86cd799439012", + "product": "Веб-разработка", + "location": "Алматы, Казахстан", + "clientType": "B2C клиенты", + "differentiator": "Современные технологии", + "status": "processing", + "userId": "12345", + "createdAt": "2025-01-20T14:00:00", + "completedAt": null, + "statusHistory": [ + { + "status": "queued", + "timestamp": "2025-01-20T14:00:00", + "message": "Анализ создан и добавлен в очередь" + }, + { + "status": "processing", + "timestamp": "2025-01-20T14:00:05", + "message": "Начата обработка анализа" + } + ] + } + ] +} +``` + +#### Структура ответа + +| Поле | Тип | Описание | +| ---------------------------------- | ------ | ------------------------------------------------------ | +| `data[].analysisId` | string | Уникальный идентификатор анализа | +| `data[].product` | string | Название продукта или услуги | +| `data[].location` | string | Географическая локация | +| `data[].clientType` | string | Тип целевой аудитории | +| `data[].differentiator` | string | Уникальные особенности бизнеса | +| `data[].status` | string | Текущий статус анализа | +| `data[].userId` | string | ID пользователя (из JWT) | +| `data[].createdAt` | string | ISO 8601 дата/время создания | +| `data[].completedAt` | string | ISO 8601 дата/время завершения (null если не завершен) | +| `data[].statusHistory` | array | Детальная история изменений статуса | +| `data[].statusHistory[].status` | string | Статус на момент изменения | +| `data[].statusHistory[].timestamp` | string | ISO 8601 дата/время изменения статуса | +| `data[].statusHistory[].message` | string | Описание изменения статуса | + +--- + +### 4. Получение детальной истории анализа + +**GET** `/api/marketing/analysis/{analysisId}/history` + +Возвращает детальную информацию об анализе, включая полную историю изменений статуса. + +#### Заголовки запроса + +``` +Authorization: Bearer +``` + +#### Параметры пути + +| Параметр | Тип | Описание | +| ------------ | ------ | --------------------- | +| `analysisId` | string | Идентификатор анализа | + +#### Пример запроса + +```javascript +const response = await fetch( + `https://api.konturai.kz/api/marketing/analysis/${analysisId}/history`, + { + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + } +); +``` + +#### Пример успешного ответа (200 OK) + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": { + "analysisId": "507f1f77bcf86cd799439011", + "product": "Разработка мобильных приложений", + "location": "Нур-Султан, Казахстан", + "clientType": "B2B клиенты", + "differentiator": "Быстрая разработка MVP за 4 недели", + "status": "completed", + "userId": "12345", + "createdAt": "2025-01-20T15:30:00", + "completedAt": "2025-01-20T15:38:00", + "statusHistory": [ + { + "status": "queued", + "timestamp": "2025-01-20T15:30:00", + "message": "Анализ создан и добавлен в очередь" + }, + { + "status": "processing", + "timestamp": "2025-01-20T15:30:05", + "message": "Начата обработка анализа" + }, + { + "status": "completed", + "timestamp": "2025-01-20T15:38:00", + "message": "Анализ успешно завершен" + } + ] + } +} +``` + +--- + +### 5. Скачивание PDF отчета + +**GET** `/api/marketing/analysis/{analysisId}/download` + +Возвращает PDF файл с полным маркетинговым отчетом. Пользователь может скачать только свои отчеты. + +#### Заголовки запроса + +``` +Authorization: Bearer +``` + +#### Параметры пути + +| Параметр | Тип | Описание | +| ------------ | ------ | --------------------- | +| `analysisId` | string | Идентификатор анализа | + +#### Пример запроса + +```javascript +const response = await fetch( + `https://api.konturai.kz/api/marketing/analysis/${analysisId}/download`, + { + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + } +); + +if (response.ok) { + const blob = await response.blob(); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `marketing_analysis_${analysisId}.pdf`; + a.click(); +} +``` + +#### Успешный ответ (200 OK) + +- **Content-Type**: `application/pdf` +- **Content-Disposition**: `attachment; filename="marketing_analysis_{analysisId}_{timestamp}.pdf"` +- **Body**: Бинарные данные PDF файла + +--- + +### 6. Генерация маркетинговой стратегии + +**POST** `/api/marketing/analysis/strategy/generate` + +Создает маркетинговую стратегию на основе завершенного анализа. Стратегия автоматически связывается с пользователем из JWT токена. + +#### Заголовки запроса + +``` +Content-Type: application/json +Authorization: Bearer +``` + +#### Параметры запроса + +| Параметр | Тип | Обязательный | Описание | +| ------------------- | ------- | ------------ | --------------------------------------------- | +| `analysisId` | string | ✅ | ID завершенного анализа (query parameter) | +| `durationWeeks` | integer | ❌ | Длительность стратегии в неделях (default: 4) | +| `priorityPlatforms` | array | ❌ | Приоритетные платформы (массив строк) | + +#### Тело запроса (JSON, опционально) + +```json +{ + "durationWeeks": 4, + "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"] +} +``` + +#### Пример запроса + +```javascript +const response = await fetch( + `https://api.konturai.kz/api/marketing/analysis/strategy/generate?analysisId=${analysisId}`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${jwtToken}`, + }, + body: JSON.stringify({ + durationWeeks: 4, + priorityPlatforms: ['Instagram', 'LinkedIn', 'Telegram'], + }), + } +); +``` + +#### Пример успешного ответа (200 OK) + +```json +{ + "success": true, + "message": "Генерация стратегии запущена успешно. Результаты будут готовы в течение 3-5 минут.", + "data": { + "strategyId": "507f1f77bcf86cd799439020", + "analysisId": "507f1f77bcf86cd799439011", + "status": "queued", + "createdAt": "2025-01-20T15:40:00", + "completedAt": null, + "durationWeeks": 4, + "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"] + } +} +``` + +--- + +### 7. Получение результата стратегии + +**GET** `/api/marketing/analysis/strategy/{strategyId}` + +Возвращает статус и результаты стратегии. Пользователь может получить только свои стратегии. + +#### Заголовки запроса + +``` +Authorization: Bearer +``` + +#### Параметры пути + +| Параметр | Тип | Описание | +| ------------ | ------ | ----------------------- | +| `strategyId` | string | Идентификатор стратегии | + +#### Пример ответа (когда стратегия завершена - 200 OK) + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": { + "strategyId": "507f1f77bcf86cd799439020", + "analysisId": "507f1f77bcf86cd799439011", + "status": "completed", + "createdAt": "2025-01-20T15:40:00", + "completedAt": "2025-01-20T15:43:00", + "durationWeeks": 4, + "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"], + "strategy": { + "weeklyPlans": [ + { + "weekNumber": 1, + "mainThemes": ["Презентация продукта", "Преимущества"], + "contentRecommendations": "Создавайте контент, который демонстрирует ценность продукта", + "priorityPlatforms": ["Instagram", "LinkedIn"] + } + ], + "postCalendar": [ + { + "publishDate": "2025-01-21T10:00:00", + "platform": "Instagram", + "contentType": "пост", + "theme": "Презентация продукта", + "postText": "Полный текст поста для публикации...", + "hashtags": ["#маркетинг", "#бизнес"], + "publishTime": "10:00" + } + ] + } + } +} +``` + +--- + +### 8. Получение стратегии по ID анализа + +**GET** `/api/marketing/analysis/{analysisId}/strategy` + +Возвращает стратегию, связанную с указанным анализом. Пользователь может получить только стратегии для своих анализов. + +#### Заголовки запроса + +``` +Authorization: Bearer +``` + +#### Параметры пути + +| Параметр | Тип | Описание | +| ------------ | ------ | --------------------- | +| `analysisId` | string | Идентификатор анализа | + +--- + +### 9. Получение списка всех стратегий пользователя + +**GET** `/api/marketing/analysis/strategy/my` + +Возвращает список всех стратегий текущего пользователя, отсортированных по дате создания (новые первыми). + +#### Заголовки запроса + +``` +Authorization: Bearer +``` + +#### Пример успешного ответа (200 OK) + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": [ + { + "strategyId": "507f1f77bcf86cd799439020", + "analysisId": "507f1f77bcf86cd799439011", + "status": "completed", + "userId": "12345", + "durationWeeks": 4, + "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"], + "createdAt": "2025-01-20T15:40:00", + "completedAt": "2025-01-20T15:43:00", + "statusHistory": [ + { + "status": "queued", + "timestamp": "2025-01-20T15:40:00", + "message": "Стратегия создана и добавлена в очередь" + }, + { + "status": "processing", + "timestamp": "2025-01-20T15:40:05", + "message": "Начата генерация стратегии" + }, + { + "status": "completed", + "timestamp": "2025-01-20T15:43:00", + "message": "Стратегия успешно сгенерирована" + } + ] + } + ] +} +``` + +--- + +### 10. Получение детальной истории стратегии + +**GET** `/api/marketing/analysis/strategy/{strategyId}/history` + +Возвращает детальную информацию о стратегии, включая полную историю изменений статуса. + +#### Заголовки запроса + +``` +Authorization: Bearer +``` + +#### Параметры пути + +| Параметр | Тип | Описание | +| ------------ | ------ | ----------------------- | +| `strategyId` | string | Идентификатор стратегии | + +#### Пример успешного ответа (200 OK) + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": { + "strategyId": "507f1f77bcf86cd799439020", + "analysisId": "507f1f77bcf86cd799439011", + "status": "completed", + "userId": "12345", + "durationWeeks": 4, + "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"], + "createdAt": "2025-01-20T15:40:00", + "completedAt": "2025-01-20T15:43:00", + "statusHistory": [ + { + "status": "queued", + "timestamp": "2025-01-20T15:40:00", + "message": "Стратегия создана и добавлена в очередь" + }, + { + "status": "processing", + "timestamp": "2025-01-20T15:40:05", + "message": "Начата генерация стратегии" + }, + { + "status": "completed", + "timestamp": "2025-01-20T15:43:00", + "message": "Стратегия успешно сгенерирована" + } + ] + } +} +``` + +--- + +## Обработка ошибок + +### Коды ошибок + +| Код | HTTP статус | Описание | +| ------------------------ | ----------- | ------------------------------- | +| `UNAUTHORIZED` | 401 | Требуется аутентификация | +| `FORBIDDEN` | 403 | Нет доступа к ресурсу | +| `VALIDATION_ERROR` | 400 | Ошибка валидации входных данных | +| `NOT_FOUND` | 404 | Ресурс не найден | +| `INVALID_ANALYSIS` | 404 | Анализ не найден | +| `ANALYSIS_NOT_COMPLETED` | 400 | Анализ еще не завершен | +| `INTERNAL_SERVER_ERROR` | 500 | Внутренняя ошибка сервера | + +### Формат ошибки + +```json +{ + "success": false, + "message": "Описание ошибки", + "error": { + "code": "ERROR_CODE", + "message": "Детальное сообщение об ошибке", + "details": { + "field1": "Сообщение об ошибке для поля 1" + } + } +} +``` + +--- + +## Примеры использования + +### JavaScript/TypeScript (Fetch API) + +#### Получение JWT токена + +```javascript +// Предполагается, что токен получен при логине +const jwtToken = localStorage.getItem('jwtToken'); +``` + +#### Запуск анализа с JWT + +```javascript +async function startMarketingAnalysis(data, jwtToken) { + const response = await fetch( + 'https://api.konturai.kz/api/marketing/analysis/start', + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${jwtToken}`, + }, + body: JSON.stringify(data), + } + ); + + if (!response.ok) { + if (response.status === 401) { + throw new Error('Требуется аутентификация'); + } + const error = await response.json(); + throw new Error(error.error?.message || 'Ошибка при запуске анализа'); + } + + const result = await response.json(); + return result.data.analysisId; +} +``` + +#### Получение списка всех анализов пользователя + +```javascript +async function getMyAnalyses(jwtToken) { + const response = await fetch( + 'https://api.konturai.kz/api/marketing/analysis/my', + { + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + } + ); + + if (!response.ok) { + throw new Error('Ошибка при получении списка анализов'); + } + + const result = await response.json(); + return result.data; // Массив анализов +} +``` + +#### Получение детальной истории анализа + +```javascript +async function getAnalysisHistory(analysisId, jwtToken) { + const response = await fetch( + `https://api.konturai.kz/api/marketing/analysis/${analysisId}/history`, + { + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + } + ); + + if (!response.ok) { + if (response.status === 403) { + throw new Error('Нет доступа к этому анализу'); + } + throw new Error('Ошибка при получении истории'); + } + + const result = await response.json(); + return result.data; +} +``` + +#### Полный пример: создание анализа и отслеживание статуса + +```javascript +async function createAndTrackAnalysis( + product, + location, + client, + differentiator, + jwtToken +) { + try { + // 1. Запускаем анализ + const analysisId = await startMarketingAnalysis( + { + product, + location, + client, + differentiator, + }, + jwtToken + ); + + console.log(`Анализ запущен: ${analysisId}`); + + // 2. Получаем историю для отслеживания статуса + const checkStatus = async () => { + const history = await getAnalysisHistory(analysisId, jwtToken); + + // Показываем последний статус + const lastStatus = + history.statusHistory[history.statusHistory.length - 1]; + console.log(`Статус: ${lastStatus.status} - ${lastStatus.message}`); + + return history.status; + }; + + // 3. Polling: проверяем статус каждые 10 секунд + const pollInterval = setInterval(async () => { + const status = await checkStatus(); + + if (status === 'completed') { + clearInterval(pollInterval); + console.log('Анализ завершен!'); + // Получаем полный результат + const fullResult = await getAnalysisResult(analysisId, jwtToken); + return fullResult; + } else if (status === 'failed') { + clearInterval(pollInterval); + throw new Error('Анализ завершился с ошибкой'); + } + }, 10000); + + // Останавливаем polling через 15 минут + setTimeout(() => { + clearInterval(pollInterval); + console.log('Превышено время ожидания'); + }, 15 * 60 * 1000); + } catch (error) { + console.error('Ошибка:', error); + throw error; + } +} +``` + +#### Получение списка стратегий пользователя + +```javascript +async function getMyStrategies(jwtToken) { + const response = await fetch( + 'https://api.konturai.kz/api/marketing/analysis/strategy/my', + { + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + } + ); + + if (!response.ok) { + throw new Error('Ошибка при получении списка стратегий'); + } + + const result = await response.json(); + return result.data; // Массив стратегий +} +``` + +--- + +## Рекомендации по интеграции + +### 1. Обработка JWT токена + +- Сохраняйте токен в безопасном месте (например, `localStorage` или `sessionStorage`) +- Проверяйте срок действия токена перед запросами +- Реализуйте механизм обновления токена при истечении + +### 2. Обработка ошибок аутентификации + +При получении `401 Unauthorized`: + +- Перенаправляйте пользователя на страницу входа +- Очищайте сохраненный токен +- Показывайте понятное сообщение пользователю + +### 3. Обработка ошибок доступа + +При получении `403 Forbidden`: + +- Показывайте сообщение о том, что ресурс недоступен +- Не пытайтесь повторять запрос с теми же параметрами + +### 4. Polling стратегия + +Для отслеживания статуса анализа/стратегии: + +- Используйте интервал 10-15 секунд +- Максимальное время ожидания: 15 минут +- Показывайте прогресс пользователю на основе `statusHistory` + +### 5. Отображение истории статусов + +Используйте `statusHistory` для: + +- Показывать временную шкалу изменений статуса +- Отображать детальную информацию о каждом этапе +- Информировать пользователя о прогрессе + +### 6. Кэширование + +- Кэшируйте список анализов/стратегий пользователя +- Обновляйте кэш при создании новых записей +- Используйте `analysisId`/`strategyId` как ключи кэша + +--- + +## Примечания + +1. **Формат даты**: Все даты возвращаются в формате ISO 8601 без timezone (LocalDateTime) +2. **Идентификаторы**: Используются MongoDB ObjectId (24 символа hex) +3. **Асинхронность**: Анализ и стратегия выполняются асинхронно +4. **Безопасность**: Все эндпоинты требуют валидный JWT токен +5. **Изоляция данных**: Пользователи видят только свои данные +6. **История статусов**: Детальная история доступна для всех анализов и стратегий + +--- + +## Поддержка + +При возникновении проблем с API обращайтесь в техническую поддержку с указанием: + +- `analysisId` или `strategyId` (если есть) +- Время запроса +- Описание проблемы +- Код ошибки (если есть) +- JWT токен (только для отладки, не в продакшене!) diff --git a/src/config/api.js b/src/config/api.js index 40adb0f..517bd40 100644 --- a/src/config/api.js +++ b/src/config/api.js @@ -54,11 +54,15 @@ export const API_CONFIG = { MARKETING_ANALYSIS_START: '/api/marketing/analysis/start', MARKETING_ANALYSIS_GET: '/api/marketing/analysis', MARKETING_ANALYSIS_DOWNLOAD: '/api/marketing/analysis', + MARKETING_ANALYSIS_MY: '/api/marketing/analysis/my', + MARKETING_ANALYSIS_HISTORY: '/api/marketing/analysis', // MarketingStrategyController - Стратегия продвижения MARKETING_STRATEGY_GENERATE: '/api/marketing/analysis/strategy/generate', MARKETING_STRATEGY_GET: '/api/marketing/analysis/strategy', - MARKETING_STRATEGY_BY_ANALYSIS: '/api/marketing/analysis' + MARKETING_STRATEGY_BY_ANALYSIS: '/api/marketing/analysis', + MARKETING_STRATEGY_MY: '/api/marketing/analysis/strategy/my', + MARKETING_STRATEGY_HISTORY: '/api/marketing/analysis/strategy' } }; diff --git a/src/router/index.js b/src/router/index.js index 8a4e284..cb37075 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -243,6 +243,16 @@ const router = createRouter({ name: 'marketing-results', component: () => import('@/views/pages/marketing/MarketingResults.vue') }, + { + path: '/marketing-analysis/analyses', + name: 'marketing-analyses-list', + component: () => import('@/views/pages/marketing/MarketingAnalysesList.vue') + }, + { + path: '/marketing-analysis/strategies', + name: 'marketing-strategies-list', + component: () => import('@/views/pages/marketing/MarketingStrategiesList.vue') + }, { path: '/pages/notfound', name: 'notfound', diff --git a/src/service/MarketingService.js b/src/service/MarketingService.js index 4443b14..3490920 100644 --- a/src/service/MarketingService.js +++ b/src/service/MarketingService.js @@ -71,6 +71,59 @@ class MarketingService { } } + /** + * Получение списка всех анализов текущего пользователя + * GET /api/marketing/analysis/my + * @returns {Promise} Массив анализов с полями analysisId, product, location, clientType, differentiator, status, userId, createdAt, completedAt, statusHistory + */ + async getMyAnalyses() { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_ANALYSIS_MY}`); + + const result = await response.json(); + + if (!response.ok) { + throw new Error(result.message || result.error?.message || 'Ошибка при получении списка анализов'); + } + + if (!result.success) { + throw new Error(result.message || 'Ошибка при получении списка анализов'); + } + + return result.data; + } catch (error) { + console.error('Ошибка при получении списка анализов:', error); + throw error; + } + } + + /** + * Получение детальной истории анализа + * GET /api/marketing/analysis/{analysisId}/history + * @param {string} analysisId - Идентификатор анализа + * @returns {Promise} Объект анализа с полной историей статусов + */ + async getAnalysisHistory(analysisId) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_ANALYSIS_HISTORY}/${analysisId}/history`); + + const result = await response.json(); + + if (!response.ok) { + throw new Error(result.message || result.error?.message || 'Ошибка при получении истории анализа'); + } + + if (!result.success) { + throw new Error(result.message || 'Ошибка при получении истории анализа'); + } + + return result.data; + } catch (error) { + console.error('Ошибка при получении истории анализа:', error); + throw error; + } + } + /** * Скачивание PDF отчета * GET /api/marketing/analysis/{analysisId}/download @@ -212,6 +265,59 @@ class MarketingService { throw error; } } + + /** + * Получение списка всех стратегий текущего пользователя + * GET /api/marketing/analysis/strategy/my + * @returns {Promise} Массив стратегий с полями strategyId, analysisId, status, userId, durationWeeks, priorityPlatforms, createdAt, completedAt, statusHistory + */ + async getMyStrategies() { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_STRATEGY_MY}`); + + const result = await response.json(); + + if (!response.ok) { + throw new Error(result.message || result.error?.message || 'Ошибка при получении списка стратегий'); + } + + if (!result.success) { + throw new Error(result.message || 'Ошибка при получении списка стратегий'); + } + + return result.data; + } catch (error) { + console.error('Ошибка при получении списка стратегий:', error); + throw error; + } + } + + /** + * Получение детальной истории стратегии + * GET /api/marketing/analysis/strategy/{strategyId}/history + * @param {string} strategyId - Идентификатор стратегии + * @returns {Promise} Объект стратегии с полной историей статусов + */ + async getStrategyHistory(strategyId) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_STRATEGY_HISTORY}/${strategyId}/history`); + + const result = await response.json(); + + if (!response.ok) { + throw new Error(result.message || result.error?.message || 'Ошибка при получении истории стратегии'); + } + + if (!result.success) { + throw new Error(result.message || 'Ошибка при получении истории стратегии'); + } + + return result.data; + } catch (error) { + console.error('Ошибка при получении истории стратегии:', error); + throw error; + } + } } export default new MarketingService(); diff --git a/src/views/pages/marketing/MarketingAnalysesList.vue b/src/views/pages/marketing/MarketingAnalysesList.vue new file mode 100644 index 0000000..732003b --- /dev/null +++ b/src/views/pages/marketing/MarketingAnalysesList.vue @@ -0,0 +1,346 @@ + + + + + diff --git a/src/views/pages/marketing/MarketingMain.vue b/src/views/pages/marketing/MarketingMain.vue index d414e7c..1b12b45 100644 --- a/src/views/pages/marketing/MarketingMain.vue +++ b/src/views/pages/marketing/MarketingMain.vue @@ -51,6 +51,13 @@ const menuItems = [ iconColor: 'text-primary-500', route: '/marketing-analysis/analysis' }, + { + id: 'analyses-list', + label: 'Мои анализы', + icon: 'pi pi-list', + iconColor: 'text-primary-500', + route: '/marketing-analysis/analyses' + }, { id: 'promotion', label: 'Продвижение', @@ -58,6 +65,13 @@ const menuItems = [ iconColor: 'text-primary-500', route: '/marketing-analysis/promotion' }, + { + id: 'strategies-list', + label: 'Мои стратегии', + icon: 'pi pi-briefcase', + iconColor: 'text-primary-500', + route: '/marketing-analysis/strategies' + }, { id: 'results', label: 'Результаты', diff --git a/src/views/pages/marketing/MarketingStrategiesList.vue b/src/views/pages/marketing/MarketingStrategiesList.vue new file mode 100644 index 0000000..bbf4319 --- /dev/null +++ b/src/views/pages/marketing/MarketingStrategiesList.vue @@ -0,0 +1,328 @@ + + + + +