diff --git a/STRATEGY_EXECUTION_API.md b/STRATEGY_EXECUTION_API.md new file mode 100644 index 0000000..2896329 --- /dev/null +++ b/STRATEGY_EXECUTION_API.md @@ -0,0 +1,752 @@ +# API для запуска стратегий продвижения + +## Обзор + +Данный документ описывает API для управления credentials социальных сетей и запуска маркетинговых стратегий с автоматической публикацией постов. + +## Базовый URL + +``` +http://your-server:port/api +``` + +## Аутентификация + +Все endpoints требуют JWT токен в заголовке `Authorization`: + +``` +Authorization: Bearer +``` + +## Управление Credentials социальных сетей + +### 1. Сохранение/обновление credentials + +Сохраняет или обновляет credentials для указанной платформы. Credentials автоматически шифруются перед сохранением. + +**Endpoint:** `POST /api/social-media/credentials` + +**Headers:** + +``` +Authorization: Bearer +Content-Type: application/json +``` + +**Request Body:** + +```json +{ + "platform": "facebook", + "credentials": "your-facebook-access-token" +} +``` + +**Параметры:** + +- `platform` (string, required) - Название платформы (например: "facebook", "instagram") +- `credentials` (string, required) - Access token или другие credentials для платформы + +**Response 200 OK:** + +```json +{ + "success": true, + "message": "Credentials успешно сохранены для платформы facebook", + "data": { + "platform": "facebook", + "hasCredentials": true, + "createdAt": "2024-01-15T10:30:00", + "updatedAt": "2024-01-15T10:30:00" + } +} +``` + +**Response 400 Bad Request:** + +```json +{ + "success": false, + "message": "Ошибка валидации", + "error": { + "code": "VALIDATION_ERROR", + "message": "Platform is required", + "details": { + "platform": "Platform is required" + } + } +} +``` + +**Response 401 Unauthorized:** + +```json +{ + "success": false, + "message": "Не авторизован", + "error": { + "code": "UNAUTHORIZED", + "message": "Требуется аутентификация. Пожалуйста, предоставьте валидный JWT токен." + } +} +``` + +**Пример запроса (JavaScript):** + +```javascript +const saveCredentials = async (platform, accessToken) => { + const response = await fetch('/api/social-media/credentials', { + method: 'POST', + headers: { + Authorization: `Bearer ${jwtToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + platform: platform, + credentials: accessToken, + }), + }); + + const data = await response.json(); + return data; +}; + +// Использование +await saveCredentials('facebook', 'EAABwzLix...'); +``` + +--- + +### 2. Получение информации о credentials + +Проверяет наличие credentials для указанной платформы. + +**Endpoint:** `GET /api/social-media/credentials/{platform}` + +**Headers:** + +``` +Authorization: Bearer +``` + +**Path Parameters:** + +- `platform` (string) - Название платформы + +**Response 200 OK:** + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": { + "platform": "facebook", + "hasCredentials": true + } +} +``` + +**Пример запроса:** + +```javascript +const checkCredentials = async (platform) => { + const response = await fetch(`/api/social-media/credentials/${platform}`, { + method: 'GET', + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + }); + + const data = await response.json(); + return data.data.hasCredentials; +}; +``` + +--- + +### 3. Получение списка всех credentials + +Возвращает список всех платформ, для которых у пользователя настроены credentials. + +**Endpoint:** `GET /api/social-media/credentials` + +**Headers:** + +``` +Authorization: Bearer +``` + +**Response 200 OK:** + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": [ + { + "platform": "facebook", + "hasCredentials": true, + "createdAt": "2024-01-15T10:30:00", + "updatedAt": "2024-01-15T10:30:00" + } + ] +} +``` + +**Пример запроса:** + +```javascript +const getAllCredentials = async () => { + const response = await fetch('/api/social-media/credentials', { + method: 'GET', + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + }); + + const data = await response.json(); + return data.data; +}; +``` + +--- + +### 4. Удаление credentials + +Удаляет credentials для указанной платформы. + +**Endpoint:** `DELETE /api/social-media/credentials/{platform}` + +**Headers:** + +``` +Authorization: Bearer +``` + +**Path Parameters:** + +- `platform` (string) - Название платформы + +**Response 200 OK:** + +```json +{ + "success": true, + "message": "Credentials для платформы facebook успешно удалены", + "data": null +} +``` + +**Response 404 Not Found:** + +```json +{ + "success": false, + "message": "Credentials не найдены", + "error": { + "code": "NOT_FOUND", + "message": "Credentials для платформы facebook не найдены" + } +} +``` + +**Пример запроса:** + +```javascript +const deleteCredentials = async (platform) => { + const response = await fetch(`/api/social-media/credentials/${platform}`, { + method: 'DELETE', + headers: { + Authorization: `Bearer ${jwtToken}`, + }, + }); + + const data = await response.json(); + return data; +}; +``` + +--- + +## Запуск стратегии продвижения + +### Запуск стратегии + +Запускает выполнение маркетинговой стратегии. Система автоматически создает задачи публикации из календаря постов стратегии и добавляет их в очередь для выполнения. + +**Endpoint:** `POST /api/marketing/analysis/strategy/{strategyId}/start` + +**Headers:** + +``` +Authorization: Bearer +Content-Type: application/json +``` + +**Path Parameters:** + +- `strategyId` (string) - ID стратегии для запуска + +**Request Body (опционально):** + +```json +{} +``` + +**Response 200 OK:** + +```json +{ + "success": true, + "message": "Стратегия успешно запущена", + "data": { + "strategyId": "67890abcdef", + "tasksCreated": 12, + "platforms": ["facebook", "instagram"], + "message": "Стратегия успешно запущена. Создано задач: 12" + } +} +``` + +**Response 400 Bad Request (стратегия не завершена):** + +```json +{ + "success": false, + "message": "Стратегия не готова к запуску", + "error": { + "code": "INVALID_STATUS", + "message": "Стратегия еще не завершена. Статус: processing" + } +} +``` + +**Response 400 Bad Request (нет credentials):** + +```json +{ + "success": false, + "message": "Не удалось запустить стратегию", + "error": { + "code": "MISSING_CREDENTIALS", + "message": "Credentials not found for platform: facebook. Please configure credentials first." + } +} +``` + +**Response 404 Not Found:** + +```json +{ + "success": false, + "message": "Стратегия не найдена", + "error": { + "code": "NOT_FOUND", + "message": "Стратегия с указанным ID не найдена" + } +} +``` + +**Response 403 Forbidden:** + +```json +{ + "success": false, + "message": "Доступ запрещен", + "error": { + "code": "FORBIDDEN", + "message": "У вас нет доступа к этой стратегии" + } +} +``` + +**Пример запроса:** + +```javascript +const startStrategy = async (strategyId) => { + const response = await fetch( + `/api/marketing/analysis/strategy/${strategyId}/start`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${jwtToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({}), + } + ); + + const data = await response.json(); + + if (data.success) { + console.log(`Создано задач: ${data.data.tasksCreated}`); + console.log(`Платформы: ${data.data.platforms.join(', ')}`); + } else { + console.error('Ошибка:', data.error.message); + } + + return data; +}; +``` + +--- + +## Полный пример использования + +### Шаг 1: Настройка credentials для Facebook + +```javascript +// Сохраняем Facebook Access Token +const facebookToken = 'EAABwzLix...'; // Получить из Facebook Developer Console + +const result = await saveCredentials('facebook', facebookToken); +if (result.success) { + console.log('Facebook credentials сохранены'); +} +``` + +### Шаг 2: Получение стратегии + +```javascript +// Получаем список стратегий пользователя +const response = await fetch('/api/marketing/analysis/strategy/my', { + headers: { + Authorization: `Bearer ${jwtToken}`, + }, +}); + +const data = await response.json(); +const strategies = data.data; + +// Выбираем завершенную стратегию +const completedStrategy = strategies.find((s) => s.status === 'completed'); +``` + +### Шаг 3: Запуск стратегии + +```javascript +if (completedStrategy) { + // Проверяем наличие credentials для платформ стратегии + const platforms = completedStrategy.priorityPlatforms || []; + + for (const platform of platforms) { + const hasCreds = await checkCredentials(platform); + if (!hasCreds) { + console.warn(`Необходимо настроить credentials для ${platform}`); + // Показать пользователю форму для ввода credentials + } + } + + // Запускаем стратегию + const startResult = await startStrategy(completedStrategy.strategyId); + + if (startResult.success) { + console.log( + `Стратегия запущена! Создано ${startResult.data.tasksCreated} задач` + ); + // Показать уведомление пользователю + } +} +``` + +--- + +## Обработка ошибок + +### Типичные ошибки и их обработка + +1. **UNAUTHORIZED (401)** + + - Причина: Невалидный или отсутствующий JWT токен + - Решение: Обновить токен или перенаправить на страницу входа + +2. **VALIDATION_ERROR (400)** + + - Причина: Невалидные данные в запросе + - Решение: Проверить обязательные поля и их формат + +3. **MISSING_CREDENTIALS (400)** + + - Причина: Не настроены credentials для платформы + - Решение: Предложить пользователю настроить credentials + +4. **INVALID_STATUS (400)** + + - Причина: Стратегия еще не завершена + - Решение: Дождаться завершения генерации стратегии + +5. **NOT_FOUND (404)** + + - Причина: Стратегия или credentials не найдены + - Решение: Проверить правильность ID + +6. **FORBIDDEN (403)** + - Причина: Пользователь не имеет доступа к ресурсу + - Решение: Проверить права доступа + +### Пример обработки ошибок + +```javascript +const handleApiError = (error) => { + switch (error.code) { + case 'UNAUTHORIZED': + // Перенаправить на страницу входа + window.location.href = '/login'; + break; + + case 'MISSING_CREDENTIALS': + // Показать модальное окно для настройки credentials + showCredentialsModal(error.message); + break; + + case 'INVALID_STATUS': + // Показать сообщение о том, что стратегия еще не готова + showNotification( + 'Стратегия еще не завершена. Пожалуйста, подождите.', + 'warning' + ); + break; + + case 'VALIDATION_ERROR': + // Показать ошибки валидации + showValidationErrors(error.details); + break; + + default: + showNotification('Произошла ошибка. Попробуйте позже.', 'error'); + } +}; + +// Использование +try { + const result = await startStrategy(strategyId); + if (!result.success) { + handleApiError(result.error); + } +} catch (error) { + console.error('Network error:', error); + showNotification('Ошибка сети. Проверьте подключение.', 'error'); +} +``` + +--- + +## Статусы задач публикации + +После запуска стратегии создаются задачи со следующими статусами: + +- `pending` - Задача ожидает выполнения (дата публикации еще не наступила) +- `processing` - Задача выполняется в данный момент +- `completed` - Задача успешно выполнена +- `failed` - Задача не выполнена из-за ошибки + +**Примечание:** Задачи с датой публикации в прошлом выполняются сразу после создания. + +--- + +## Планировщик задач + +Система автоматически проверяет очередь задач каждую минуту и выполняет задачи, у которых наступило время публикации. + +- Планировщик включен по умолчанию +- Можно отключить через настройку `posting.scheduler.enabled=false` +- Задачи выполняются асинхронно + +--- + +## Поддерживаемые платформы + +На данный момент поддерживается: + +- **Facebook** - через Facebook Graph API v18.0 + +В будущем планируется поддержка: + +- Instagram +- LinkedIn +- Telegram +- TikTok +- YouTube + +--- + +## Получение Facebook Access Token + +Для получения Facebook Access Token: + +1. Перейдите на [Facebook Developers](https://developers.facebook.com/) +2. Создайте приложение +3. Добавьте продукт "Facebook Login" +4. Настройте OAuth и получите Access Token +5. Используйте полученный токен в API + +**Важно:** + +- Access Token имеет срок действия +- Для долгосрочного использования рекомендуется использовать Long-Lived Token +- Токен должен иметь разрешения `pages_manage_posts` для публикации + +--- + +## Примеры React компонентов + +### Компонент для настройки credentials + +```jsx +import React, { useState } from 'react'; + +const CredentialsForm = ({ platform, onSave }) => { + const [token, setToken] = useState(''); + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const handleSubmit = async (e) => { + e.preventDefault(); + setLoading(true); + setError(null); + + try { + const response = await fetch('/api/social-media/credentials', { + method: 'POST', + headers: { + Authorization: `Bearer ${jwtToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + platform: platform, + credentials: token, + }), + }); + + const data = await response.json(); + + if (data.success) { + onSave(); + setToken(''); + } else { + setError(data.error.message); + } + } catch (err) { + setError('Ошибка сети'); + } finally { + setLoading(false); + } + }; + + return ( +
+
+ + setToken(e.target.value)} + required + /> +
+ {error &&
{error}
} + +
+ ); +}; + +export default CredentialsForm; +``` + +### Компонент для запуска стратегии + +```jsx +import React, { useState } from 'react'; + +const StartStrategyButton = ({ strategyId, onStart }) => { + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + const handleStart = async () => { + setLoading(true); + setError(null); + + try { + const response = await fetch( + `/api/marketing/analysis/strategy/${strategyId}/start`, + { + method: 'POST', + headers: { + Authorization: `Bearer ${jwtToken}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({}), + } + ); + + const data = await response.json(); + + if (data.success) { + onStart(data.data); + } else { + setError(data.error.message); + } + } catch (err) { + setError('Ошибка сети'); + } finally { + setLoading(false); + } + }; + + return ( +
+ + {error &&
{error}
} +
+ ); +}; + +export default StartStrategyButton; +``` + +--- + +## Часто задаваемые вопросы + +### Q: Как часто проверяются задачи на выполнение? + +A: Планировщик проверяет очередь каждую минуту. + +### Q: Что происходит, если credentials истекли? + +A: Задача получит статус `failed` с сообщением об ошибке. Необходимо обновить credentials и перезапустить стратегию. + +### Q: Можно ли отменить выполнение стратегии? + +A: На данный момент нет, но можно удалить credentials для платформы, что предотвратит выполнение будущих задач. + +### Q: Как узнать статус выполнения задач? + +A: Статусы задач можно получить через API (будет добавлено в будущих версиях). + +### Q: Поддерживается ли публикация с изображениями? + +A: На данный момент поддерживается только текстовая публикация. Поддержка изображений планируется в будущем. + +--- + +## Версионирование API + +Текущая версия: **v1** + +Все endpoints могут изменяться в будущих версиях. При изменении API будет указана новая версия. + +--- + +## Поддержка + +При возникновении проблем: + +1. Проверьте логи в консоли браузера +2. Убедитесь, что JWT токен валиден +3. Проверьте формат запросов согласно документации +4. Обратитесь к разработчикам с описанием проблемы diff --git a/docs/marketing-api-with-jwt-frontend.md b/docs/marketing-api-with-jwt-frontend.md index 10ce258..9f9f3fe 100644 --- a/docs/marketing-api-with-jwt-frontend.md +++ b/docs/marketing-api-with-jwt-frontend.md @@ -12,10 +12,11 @@ API для генерации маркетингового анализа и с **Важные изменения:** -- ✅ Все эндпоинты теперь требуют JWT токен в заголовке `Authorization` -- ✅ Пользователи могут видеть только свои анализы и стратегии -- ✅ Добавлена детальная история статусов для каждого анализа и стратегии -- ✅ Новые эндпоинты для получения списка всех анализов/стратегий пользователя +- ✅ Все эндпоинты теперь требуют JWT токен в заголовке `Authorization` +- ✅ Пользователи могут видеть только свои анализы и стратегии +- ✅ Добавлена детальная история статусов для каждого анализа и стратегии +- ✅ Новые эндпоинты для получения списка всех анализов/стратегий пользователя +- ✅ **НОВОЕ**: Добавлена поддержка типов анализов (РЫНОК, КОНКУРЕНТЫ, ЦА, КАНАЛЫ, SWOT) --- @@ -31,9 +32,9 @@ Authorization: Bearer JWT токен содержит следующую информацию: -- **sub**: Email пользователя -- **uid**: ID пользователя (Long) - используется для связи данных -- **roles**: Роли пользователя (String, разделённые запятыми) +- **sub**: Email пользователя +- **uid**: ID пользователя (Long) - используется для связи данных +- **roles**: Роли пользователя (String, разделённые запятыми) ### Ошибки аутентификации @@ -41,12 +42,12 @@ JWT токен содержит следующую информацию: ```json { - "success": false, - "message": "Не авторизован", - "error": { - "code": "UNAUTHORIZED", - "message": "Требуется аутентификация. Пожалуйста, предоставьте валидный JWT токен." - } + "success": false, + "message": "Не авторизован", + "error": { + "code": "UNAUTHORIZED", + "message": "Требуется аутентификация. Пожалуйста, предоставьте валидный JWT токен." + } } ``` @@ -77,66 +78,74 @@ Authorization: Bearer | `location` | string | ✅ | Географическая локация работы | "Алматы, Казахстан" | | `client` | string | ✅ | Тип целевой аудитории | "B2B клиенты" | | `differentiator` | string | ✅ | Уникальные особенности бизнеса | "Быстрая разработка за 2 недели" | +| `analysisType` | string | ✅ | Тип анализа для генерации | "РЫНОК" | #### Валидация полей **`product`** (string, обязательное) -- Минимальная длина: 3 символа -- Максимальная длина: 200 символов +- Минимальная длина: 3 символа +- Максимальная длина: 200 символов **`location`** (string, обязательное) -- Минимальная длина: 2 символа -- Максимальная длина: 150 символов +- Минимальная длина: 2 символа +- Максимальная длина: 150 символов **`client`** (string, обязательное) -- Допустимые значения: - - `"B2B клиенты"` - - `"B2C клиенты"` - - `"Частные лица"` - - `"Корпорации"` - - `"Малый бизнес"` +- Допустимые значения: + - `"B2B клиенты"` + - `"B2C клиенты"` + - `"Частные лица"` + - `"Корпорации"` + - `"Малый бизнес"` **`differentiator`** (string, обязательное) -- Минимальная длина: 10 символов -- Максимальная длина: 500 символов +- Минимальная длина: 10 символов +- Максимальная длина: 500 символов + +**`analysisType`** (string, обязательное) + +- Допустимые значения (регистр не важен, но рекомендуется использовать заглавные буквы): + - `"РЫНОК"` - Анализ рынка (размер рынка, динамика роста, сегменты, тренды) + - `"КОНКУРЕНТЫ"` - Анализ конкурентов (основные конкуренты, их сильные/слабые стороны, позиционирование) + - `"ЦА"` - Анализ целевой аудитории (демография, психография, потребности, поведение) + - `"КАНАЛЫ"` - Анализ маркетинговых каналов (эффективность каналов, рекомендации по выбору) + - `"SWOT"` - SWOT-анализ (сильные стороны, слабые стороны, возможности, угрозы) #### Пример запроса ```javascript -const response = await fetch( - 'https://api.konturai.kz/api/marketing/analysis/start', - { +const response = await fetch('https://api.konturai.kz/api/marketing/analysis/start', { method: 'POST', headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${jwtToken}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${jwtToken}` }, body: JSON.stringify({ - product: 'Разработка мобильных приложений', - location: 'Нур-Султан, Казахстан', - client: 'B2B клиенты', - differentiator: 'Специализируемся на быстрой разработке MVP за 4 недели', - }), - } -); + product: 'Разработка мобильных приложений', + location: 'Нур-Султан, Казахстан', + client: 'B2B клиенты', + differentiator: 'Специализируемся на быстрой разработке MVP за 4 недели', + analysisType: 'РЫНОК' + }) +}); ``` #### Пример успешного ответа (200 OK) ```json { - "success": true, - "message": "Анализ запущен успешно", - "data": { - "analysisId": "507f1f77bcf86cd799439011", - "status": "processing", - "estimatedCompletionTime": "2025-01-20T15:38:00", - "message": "Анализ запущен успешно. Результаты будут готовы в течение 5-10 минут." - } + "success": true, + "message": "Анализ запущен успешно", + "data": { + "analysisId": "507f1f77bcf86cd799439011", + "status": "processing", + "estimatedCompletionTime": "2025-01-20T15:38:00", + "message": "Анализ запущен успешно. Результаты будут готовы в течение 5-10 минут." + } } ``` @@ -163,42 +172,39 @@ Authorization: Bearer #### Пример запроса ```javascript -const response = await fetch( - `https://api.konturai.kz/api/marketing/analysis/${analysisId}`, - { +const response = await fetch(`https://api.konturai.kz/api/marketing/analysis/${analysisId}`, { headers: { - Authorization: `Bearer ${jwtToken}`, - }, - } -); + 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" + "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" + } } - } } ``` @@ -217,12 +223,12 @@ const response = await fetch( ```json { - "success": false, - "message": "Доступ запрещен", - "error": { - "code": "FORBIDDEN", - "message": "У вас нет доступа к этому анализу" - } + "success": false, + "message": "Доступ запрещен", + "error": { + "code": "FORBIDDEN", + "message": "У вас нет доступа к этому анализу" + } } ``` @@ -245,75 +251,72 @@ Authorization: Bearer #### Пример запроса ```javascript -const response = await fetch( - 'https://api.konturai.kz/api/marketing/analysis/my', - { +const response = await fetch('https://api.konturai.kz/api/marketing/analysis/my', { headers: { - Authorization: `Bearer ${jwtToken}`, - }, - } -); + 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": [ + "success": true, + "message": "Операция выполнена успешно", + "data": [ { - "status": "queued", - "timestamp": "2025-01-20T15:30:00", - "message": "Анализ создан и добавлен в очередь" + "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": "Анализ успешно завершен" + } + ] }, { - "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": "Начата обработка анализа" + } + ] } - ] - }, - { - "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": "Начата обработка анализа" - } - ] - } - ] + ] } ``` @@ -358,50 +361,47 @@ Authorization: Bearer #### Пример запроса ```javascript -const response = await fetch( - `https://api.konturai.kz/api/marketing/analysis/${analysisId}/history`, - { +const response = await fetch(`https://api.konturai.kz/api/marketing/analysis/${analysisId}/history`, { headers: { - Authorization: `Bearer ${jwtToken}`, - }, - } -); + 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": "Начата обработка анализа" - }, - { + "success": true, + "message": "Операция выполнена успешно", + "data": { + "analysisId": "507f1f77bcf86cd799439011", + "product": "Разработка мобильных приложений", + "location": "Нур-Султан, Казахстан", + "clientType": "B2B клиенты", + "differentiator": "Быстрая разработка MVP за 4 недели", "status": "completed", - "timestamp": "2025-01-20T15:38:00", - "message": "Анализ успешно завершен" - } - ] - } + "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": "Анализ успешно завершен" + } + ] + } } ``` @@ -428,30 +428,27 @@ Authorization: Bearer #### Пример запроса ```javascript -const response = await fetch( - `https://api.konturai.kz/api/marketing/analysis/${analysisId}/download`, - { +const response = await fetch(`https://api.konturai.kz/api/marketing/analysis/${analysisId}/download`, { headers: { - Authorization: `Bearer ${jwtToken}`, - }, - } -); + 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(); + 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 файла +- **Content-Type**: `application/pdf` +- **Content-Disposition**: `attachment; filename="marketing_analysis_{analysisId}_{timestamp}.pdf"` +- **Body**: Бинарные данные PDF файла --- @@ -480,45 +477,42 @@ Authorization: Bearer ```json { - "durationWeeks": 4, - "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"] + "durationWeeks": 4, + "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"] } ``` #### Пример запроса ```javascript -const response = await fetch( - `https://api.konturai.kz/api/marketing/analysis/strategy/generate?analysisId=${analysisId}`, - { +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}`, + 'Content-Type': 'application/json', + Authorization: `Bearer ${jwtToken}` }, body: JSON.stringify({ - durationWeeks: 4, - priorityPlatforms: ['Instagram', 'LinkedIn', 'Telegram'], - }), - } -); + 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"] - } + "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"] + } } ``` @@ -546,38 +540,38 @@ Authorization: Bearer ```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"] + "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" + } + ] } - ], - "postCalendar": [ - { - "publishDate": "2025-01-21T10:00:00", - "platform": "Instagram", - "contentType": "пост", - "theme": "Презентация продукта", - "postText": "Полный текст поста для публикации...", - "hashtags": ["#маркетинг", "#бизнес"], - "publishTime": "10:00" - } - ] } - } } ``` @@ -619,37 +613,37 @@ Authorization: Bearer ```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": [ + "success": true, + "message": "Операция выполнена успешно", + "data": [ { - "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": "Стратегия успешно сгенерирована" + "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": "Стратегия успешно сгенерирована" + } + ] } - ] - } - ] + ] } ``` @@ -677,35 +671,35 @@ Authorization: Bearer ```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": "Начата генерация стратегии" - }, - { + "success": true, + "message": "Операция выполнена успешно", + "data": { + "strategyId": "507f1f77bcf86cd799439020", + "analysisId": "507f1f77bcf86cd799439011", "status": "completed", - "timestamp": "2025-01-20T15:43:00", - "message": "Стратегия успешно сгенерирована" - } - ] - } + "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": "Стратегия успешно сгенерирована" + } + ] + } } ``` @@ -729,15 +723,15 @@ Authorization: Bearer ```json { - "success": false, - "message": "Описание ошибки", - "error": { - "code": "ERROR_CODE", - "message": "Детальное сообщение об ошибке", - "details": { - "field1": "Сообщение об ошибке для поля 1" + "success": false, + "message": "Описание ошибки", + "error": { + "code": "ERROR_CODE", + "message": "Детальное сообщение об ошибке", + "details": { + "field1": "Сообщение об ошибке для поля 1" + } } - } } ``` @@ -758,28 +752,25 @@ const jwtToken = localStorage.getItem('jwtToken'); ```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), - } - ); + 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('Требуется аутентификация'); + if (!response.ok) { + if (response.status === 401) { + throw new Error('Требуется аутентификация'); + } + const error = await response.json(); + throw new Error(error.error?.message || 'Ошибка при запуске анализа'); } - const error = await response.json(); - throw new Error(error.error?.message || 'Ошибка при запуске анализа'); - } - const result = await response.json(); - return result.data.analysisId; + const result = await response.json(); + return result.data.analysisId; } ``` @@ -787,21 +778,18 @@ async function startMarketingAnalysis(data, jwtToken) { ```javascript async function getMyAnalyses(jwtToken) { - const response = await fetch( - 'https://api.konturai.kz/api/marketing/analysis/my', - { - headers: { - Authorization: `Bearer ${jwtToken}`, - }, + const response = await fetch('https://api.konturai.kz/api/marketing/analysis/my', { + headers: { + Authorization: `Bearer ${jwtToken}` + } + }); + + if (!response.ok) { + throw new Error('Ошибка при получении списка анализов'); } - ); - if (!response.ok) { - throw new Error('Ошибка при получении списка анализов'); - } - - const result = await response.json(); - return result.data; // Массив анализов + const result = await response.json(); + return result.data; // Массив анализов } ``` @@ -809,88 +797,81 @@ async function getMyAnalyses(jwtToken) { ```javascript async function getAnalysisHistory(analysisId, jwtToken) { - const response = await fetch( - `https://api.konturai.kz/api/marketing/analysis/${analysisId}/history`, - { - headers: { - Authorization: `Bearer ${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('Нет доступа к этому анализу'); + if (!response.ok) { + if (response.status === 403) { + throw new Error('Нет доступа к этому анализу'); + } + throw new Error('Ошибка при получении истории'); } - throw new Error('Ошибка при получении истории'); - } - const result = await response.json(); - return result.data; + 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 - ); +async function createAndTrackAnalysis(product, location, client, differentiator, jwtToken) { + try { + // 1. Запускаем анализ + const analysisId = await startMarketingAnalysis( + { + product, + location, + client, + differentiator + }, + jwtToken + ); - console.log(`Анализ запущен: ${analysisId}`); + console.log(`Анализ запущен: ${analysisId}`); - // 2. Получаем историю для отслеживания статуса - const checkStatus = async () => { - const history = await getAnalysisHistory(analysisId, jwtToken); + // 2. Получаем историю для отслеживания статуса + const checkStatus = async () => { + const history = await getAnalysisHistory(analysisId, jwtToken); - // Показываем последний статус - const lastStatus = - history.statusHistory[history.statusHistory.length - 1]; - console.log(`Статус: ${lastStatus.status} - ${lastStatus.message}`); + // Показываем последний статус + const lastStatus = history.statusHistory[history.statusHistory.length - 1]; + console.log(`Статус: ${lastStatus.status} - ${lastStatus.message}`); - return history.status; - }; + return history.status; + }; - // 3. Polling: проверяем статус каждые 10 секунд - const pollInterval = setInterval(async () => { - const status = await checkStatus(); + // 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); + 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; - } + // Останавливаем polling через 15 минут + setTimeout( + () => { + clearInterval(pollInterval); + console.log('Превышено время ожидания'); + }, + 15 * 60 * 1000 + ); + } catch (error) { + console.error('Ошибка:', error); + throw error; + } } ``` @@ -898,21 +879,18 @@ async function createAndTrackAnalysis( ```javascript async function getMyStrategies(jwtToken) { - const response = await fetch( - 'https://api.konturai.kz/api/marketing/analysis/strategy/my', - { - headers: { - Authorization: `Bearer ${jwtToken}`, - }, + const response = await fetch('https://api.konturai.kz/api/marketing/analysis/strategy/my', { + headers: { + Authorization: `Bearer ${jwtToken}` + } + }); + + if (!response.ok) { + throw new Error('Ошибка при получении списка стратегий'); } - ); - if (!response.ok) { - throw new Error('Ошибка при получении списка стратегий'); - } - - const result = await response.json(); - return result.data; // Массив стратегий + const result = await response.json(); + return result.data; // Массив стратегий } ``` @@ -922,46 +900,46 @@ async function getMyStrategies(jwtToken) { ### 1. Обработка JWT токена -- Сохраняйте токен в безопасном месте (например, `localStorage` или `sessionStorage`) -- Проверяйте срок действия токена перед запросами -- Реализуйте механизм обновления токена при истечении +- Сохраняйте токен в безопасном месте (например, `localStorage` или `sessionStorage`) +- Проверяйте срок действия токена перед запросами +- Реализуйте механизм обновления токена при истечении ### 2. Обработка ошибок аутентификации При получении `401 Unauthorized`: -- Перенаправляйте пользователя на страницу входа -- Очищайте сохраненный токен -- Показывайте понятное сообщение пользователю +- Перенаправляйте пользователя на страницу входа +- Очищайте сохраненный токен +- Показывайте понятное сообщение пользователю ### 3. Обработка ошибок доступа При получении `403 Forbidden`: -- Показывайте сообщение о том, что ресурс недоступен -- Не пытайтесь повторять запрос с теми же параметрами +- Показывайте сообщение о том, что ресурс недоступен +- Не пытайтесь повторять запрос с теми же параметрами ### 4. Polling стратегия Для отслеживания статуса анализа/стратегии: -- Используйте интервал 10-15 секунд -- Максимальное время ожидания: 15 минут -- Показывайте прогресс пользователю на основе `statusHistory` +- Используйте интервал 10-15 секунд +- Максимальное время ожидания: 15 минут +- Показывайте прогресс пользователю на основе `statusHistory` ### 5. Отображение истории статусов Используйте `statusHistory` для: -- Показывать временную шкалу изменений статуса -- Отображать детальную информацию о каждом этапе -- Информировать пользователя о прогрессе +- Показывать временную шкалу изменений статуса +- Отображать детальную информацию о каждом этапе +- Информировать пользователя о прогрессе ### 6. Кэширование -- Кэшируйте список анализов/стратегий пользователя -- Обновляйте кэш при создании новых записей -- Используйте `analysisId`/`strategyId` как ключи кэша +- Кэшируйте список анализов/стратегий пользователя +- Обновляйте кэш при создании новых записей +- Используйте `analysisId`/`strategyId` как ключи кэша --- @@ -976,12 +954,125 @@ async function getMyStrategies(jwtToken) { --- +## Изменения: Поддержка типов анализов + +### Обзор изменений + +В API добавлена поддержка различных типов маркетинговых анализов. Теперь при создании анализа можно указать тип анализа, который определяет фокус и содержание генерируемого отчета. + +### Новое поле в запросе + +**Поле**: `analysisType` (обязательное) + +**Тип**: `string` + +**Допустимые значения**: + +- `"РЫНОК"` - Анализ рынка +- `"КОНКУРЕНТЫ"` - Анализ конкурентов +- `"ЦА"` - Анализ целевой аудитории +- `"КАНАЛЫ"` - Анализ маркетинговых каналов +- `"SWOT"` - SWOT-анализ + +### Описание типов анализов + +#### 1. РЫНОК + +Генерирует анализ рынка, включающий: + +- Размер рынка +- Динамику роста +- Основные сегменты +- Тренды и перспективы развития + +#### 2. КОНКУРЕНТЫ + +Генерирует анализ конкурентов, включающий: + +- Основных конкурентов +- Их сильные и слабые стороны +- Позиционирование +- Ценовую политику +- Маркетинговые стратегии + +#### 3. ЦА (Целевая аудитория) + +Генерирует анализ целевой аудитории, включающий: + +- Демографические характеристики +- Психографический профиль +- Потребности и боли +- Поведенческие паттерны +- Предпочтения + +#### 4. КАНАЛЫ + +Генерирует анализ маркетинговых каналов, включающий: + +- Оценку эффективности различных каналов коммуникации +- Рекомендации по выбору каналов +- Особенности использования каждого канала +- Бюджетные рекомендации + +#### 5. SWOT + +Генерирует SWOT-анализ, включающий: + +- Сильные стороны (Strengths) +- Слабые стороны (Weaknesses) +- Возможности (Opportunities) +- Угрозы (Threats) + +### Изменения в ответе + +В ответе анализа теперь присутствует поле `analysisType` в объекте `reportData`, которое содержит название типа анализа. + +### Пример использования + +```javascript +// Запрос на создание SWOT-анализа +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 недели', + analysisType: 'SWOT' // Указываем тип анализа + }) +}); +``` + +### Рекомендации для фронтенда + +1. **UI для выбора типа анализа**: Добавьте выпадающий список или радиокнопки для выбора типа анализа перед отправкой запроса. + +2. **Валидация на фронтенде**: Убедитесь, что отправляется только один из допустимых значений. + +3. **Отображение типа анализа**: При показе результатов анализа отображайте тип анализа для контекста. + +4. **Обратная совместимость**: Если поле `analysisType` не указано, API вернет ошибку валидации. Это обязательное поле. + +### Миграция существующих интеграций + +Если у вас есть существующие интеграции, которые не используют поле `analysisType`, необходимо: + +1. Добавить поле `analysisType` в запрос +2. Выбрать подходящий тип анализа по умолчанию или позволить пользователю выбрать +3. Обновить UI для отображения выбора типа анализа + +--- + ## Поддержка При возникновении проблем с API обращайтесь в техническую поддержку с указанием: -- `analysisId` или `strategyId` (если есть) -- Время запроса -- Описание проблемы -- Код ошибки (если есть) -- JWT токен (только для отладки, не в продакшене!) +- `analysisId` или `strategyId` (если есть) +- Время запроса +- Описание проблемы +- Код ошибки (если есть) +- JWT токен (только для отладки, не в продакшене!) diff --git a/marketing-analysis-types-update-frontend.md b/marketing-analysis-types-update-frontend.md new file mode 100644 index 0000000..5b91438 --- /dev/null +++ b/marketing-analysis-types-update-frontend.md @@ -0,0 +1,411 @@ +# Обновление API: Виды анализа для маркетингового анализа (Frontend/AI Agent) + +## Обзор изменений + +В API маркетингового анализа добавлена поддержка **опциональных видов анализа**, которые могут быть переданы от фронтенда и будут включены в промпт для AI-генерации отчета. + +**Дата обновления**: 2025-01-20 + +--- + +## Что изменилось + +### Новые опциональные поля в запросе + +В эндпоинт `POST /api/marketing/analysis/start` добавлены 5 новых опциональных полей для видов анализа: + +1. **`market`** - Анализ рынка +2. **`competitors`** - Анализ конкурентов +3. **`targetAudienceAnalysis`** - Анализ целевой аудитории +4. **`channels`** - Анализ каналов +5. **`swot`** - SWOT анализ + +Эти данные будут: + +- ✅ Включены в контекст промпта для AI-генерации +- ✅ Сохранены в отчете +- ✅ Отображены в PDF-отчете в разделе "Виды анализа" + +--- + +## Обновленная структура запроса + +### Эндпоинт + +**POST** `/api/marketing/analysis/start` + +### Тело запроса (JSON) + +#### Обязательные поля (без изменений) + +| Поле | Тип | Обязательный | Описание | Пример значения | +| ---------------- | ------ | ------------ | ------------------------------ | -------------------------------- | +| `product` | string | ✅ | Название продукта или услуги | "Веб-разработка" | +| `location` | string | ✅ | Географическая локация работы | "Алматы, Казахстан" | +| `client` | string | ✅ | Тип целевой аудитории | "B2B клиенты" | +| `differentiator` | string | ✅ | Уникальные особенности бизнеса | "Быстрая разработка за 2 недели" | + +#### Новые опциональные поля + +| Поле | Тип | Обязательный | Описание | Максимальная длина | Пример значения | +| ------------------------ | ------ | ------------ | ----------------------------------------------------------- | ------------------ | ------------------------------------------------------------------------------- | +| `market` | string | ❌ | Анализ рынка (размер, тренды, возможности) | 2000 символов | "Рынок веб-разработки в Казахстане растет на 15% ежегодно..." | +| `competitors` | string | ❌ | Анализ конкурентов (основные игроки, их преимущества) | 2000 символов | "Основные конкуренты: Компания X, Компания Y..." | +| `targetAudienceAnalysis` | string | ❌ | Детальный анализ целевой аудитории | 2000 символов | "Целевая аудитория: IT-директора средних компаний..." | +| `channels` | string | ❌ | Анализ маркетинговых каналов | 2000 символов | "Рекомендуемые каналы: LinkedIn для B2B, Instagram для визуального контента..." | +| `swot` | string | ❌ | SWOT анализ (Strengths, Weaknesses, Opportunities, Threats) | 2000 символов | "Strengths: Быстрая разработка... Weaknesses: Ограниченный бюджет..." | + +### Валидация новых полей + +Все новые поля имеют одинаковые правила валидации: + +- **Тип**: `string` +- **Обязательность**: ❌ Опциональное (можно не передавать) +- **Максимальная длина**: 2000 символов +- **Минимальная длина**: Нет ограничений (может быть пустой строкой) + +--- + +## Примеры использования + +### Пример 1: Запрос только с обязательными полями (как раньше) + +```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 недели', + }), + } +); +``` + +**Результат**: Работает как раньше, без изменений в функциональности. + +--- + +### Пример 2: Запрос с одним видом анализа + +```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 недели', + market: + 'Рынок мобильной разработки в Казахстане показывает стабильный рост на 20% в год. Основные драйверы: цифровизация бизнеса, рост числа стартапов, увеличение инвестиций в IT-сектор.', + }), + } +); +``` + +**Результат**: Данные об анализе рынка будут включены в промпт и отображены в отчете. + +--- + +### Пример 3: Запрос со всеми видами анализа + +```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 недели', + + // Виды анализа + market: + 'Рынок мобильной разработки в Казахстане растет на 20% ежегодно. Основные сегменты: корпоративные приложения, e-commerce, финтех.', + + competitors: + 'Основные конкуренты: TechCorp (лидер рынка, 30% доля), DevStudio (средний сегмент, 15% доля), StartupDev (нишевый игрок, 5% доля). Их преимущества: большая команда, долгосрочные контракты.', + + targetAudienceAnalysis: + 'Целевая аудитория: IT-директора средних и крупных компаний (50-500 сотрудников), возраст 35-50 лет, техническое образование. Боли: долгие сроки разработки, высокие цены, отсутствие гибкости.', + + channels: + 'Рекомендуемые каналы: LinkedIn (основной для B2B), Telegram-каналы для IT-сообщества, отраслевые конференции, контент-маркетинг через блог.', + + swot: 'Strengths: Быстрая разработка MVP, опытная команда, гибкие методологии. Weaknesses: Ограниченный бюджет на маркетинг, небольшая команда. Opportunities: Рост спроса на мобильные решения, цифровизация госсектора. Threats: Конкуренция с крупными игроками, экономическая нестабильность.', + }), + } +); +``` + +**Результат**: Все виды анализа будут включены в промпт для более точной генерации отчета и отображены в PDF. + +--- + +## Как это влияет на генерацию отчета + +### Включение в промпт + +Когда вы передаете виды анализа, они автоматически добавляются в контекст промпта для AI: + +``` +Продукт/услуга: Разработка мобильных приложений +Локация: Нур-Султан, Казахстан +Тип клиентов: B2B клиенты +Уникальные особенности: Специализируемся на быстрой разработке MVP за 4 недели + +Анализ рынка: +Рынок мобильной разработки в Казахстане растет на 20% ежегодно... + +Анализ конкурентов: +Основные конкуренты: TechCorp... + +... +``` + +Это позволяет AI генерировать более точные и релевантные рекомендации, учитывая предоставленную аналитику. + +### Отображение в PDF-отчете + +Если виды анализа были переданы, они будут отображены в PDF-отчете в отдельном разделе: + +```markdown +## Виды анализа + +### Анализ рынка + +Рынок мобильной разработки в Казахстане растет на 20% ежегодно... + +### Анализ конкурентов + +Основные конкуренты: TechCorp... + +### Анализ целевой аудитории + +Целевая аудитория: IT-директора средних и крупных компаний... + +### Анализ каналов + +Рекомендуемые каналы: LinkedIn (основной для B2B)... + +### SWOT анализ + +Strengths: Быстрая разработка MVP... +``` + +--- + +## Обратная совместимость + +✅ **Полная обратная совместимость**: Старые запросы без новых полей продолжают работать без изменений. + +✅ **Опциональные поля**: Все новые поля опциональны, их можно не передавать. + +✅ **Валидация**: Если поля переданы, они валидируются (максимум 2000 символов). + +--- + +## Рекомендации для фронтенда + +### 1. UI/UX + +Рекомендуется добавить в форму создания анализа: + +- **Опциональные секции** для каждого вида анализа +- **Текстовые поля** (textarea) с ограничением в 2000 символов +- **Подсказки** о том, какую информацию следует включить в каждый вид анализа +- **Индикатор прогресса** заполнения (опционально) + +### 2. Валидация на фронтенде + +```javascript +// Пример валидации на фронтенде +const validateAnalysisTypes = (data) => { + const errors = {}; + + const analysisTypes = [ + 'market', + 'competitors', + 'targetAudienceAnalysis', + 'channels', + 'swot', + ]; + + analysisTypes.forEach((field) => { + if (data[field] && data[field].length > 2000) { + errors[field] = `Поле "${field}" не должно превышать 2000 символов`; + } + }); + + return errors; +}; +``` + +### 3. Структура данных + +```typescript +// TypeScript интерфейс для запроса +interface MarketingAnalysisRequest { + // Обязательные поля + product: string; // 3-200 символов + location: string; // 2-150 символов + client: string; // Одно из допустимых значений + differentiator: string; // 10-500 символов + + // Опциональные виды анализа + market?: string; // до 2000 символов + competitors?: string; // до 2000 символов + targetAudienceAnalysis?: string; // до 2000 символов + channels?: string; // до 2000 символов + swot?: string; // до 2000 символов +} +``` + +--- + +## Примеры ответов API + +### Успешный ответ (без изменений) + +```json +{ + "success": true, + "message": "Анализ запущен успешно", + "data": { + "analysisId": "507f1f77bcf86cd799439011", + "status": "processing", + "estimatedCompletionTime": "2025-01-20T15:38:00", + "message": "Анализ запущен успешно. Результаты будут готовы в течение 5-10 минут." + } +} +``` + +### Ошибка валидации (если поле превышает лимит) + +```json +{ + "success": false, + "message": "Ошибка валидации", + "error": { + "code": "VALIDATION_ERROR", + "message": "Ошибка валидации входных данных", + "details": { + "market": "Поле 'market' должно содержать не более 2000 символов" + } + } +} +``` + +**HTTP статус**: `400 Bad Request` + +--- + +## Часто задаваемые вопросы (FAQ) + +### Q: Обязательно ли передавать все виды анализа? + +**A**: Нет, все поля опциональны. Вы можете передать только те, которые у вас есть. + +### Q: Что произойдет, если я передам пустую строку? + +**A**: Пустые строки игнорируются, они не будут включены в промпт и отчет. + +### Q: Можно ли передать только часть видов анализа? + +**A**: Да, вы можете передать любое количество видов анализа (от 0 до 5). + +### Q: Влияет ли это на время генерации отчета? + +**A**: Нет, время генерации остается прежним (5-10 минут). Дополнительные данные могут улучшить качество отчета. + +### Q: Будут ли виды анализа отображаться в JSON-ответе? + +**A**: Виды анализа сохраняются в отчете и могут быть доступны через структуру `reportData`, но в текущей версии API они не возвращаются в стандартном JSON-ответе. Они включены в PDF-отчет. + +--- + +## Миграция для существующих клиентов + +### Для существующих интеграций + +**Никаких изменений не требуется!** Старые запросы продолжают работать без изменений. + +### Для новых интеграций + +Если вы хотите использовать новые возможности: + +1. Добавьте новые поля в форму запроса (опционально) +2. Соблюдайте лимит в 2000 символов для каждого поля +3. Передавайте только те виды анализа, которые у вас есть + +--- + +## Технические детали + +### Структура хранения + +Виды анализа сохраняются в MongoDB в поле `reportData.analysisTypes`: + +```json +{ + "reportData": { + "summary": "...", + "targetAudience": {...}, + "recommendations": [...], + "strategy": {...}, + "analysisTypes": { + "market": "Рынок...", + "competitors": "Конкуренты...", + "targetAudienceAnalysis": "ЦА...", + "channels": "Каналы...", + "swot": "SWOT..." + } + } +} +``` + +### Включение в промпт + +Виды анализа добавляются в контекст промпта в следующем формате: + +``` +Анализ рынка: +[содержимое поля market] + +Анализ конкурентов: +[содержимое поля competitors] + +... +``` + +Это позволяет AI учитывать предоставленную аналитику при генерации резюме, рекомендаций и стратегии. + +--- + +## Поддержка + +Если у вас возникли вопросы или проблемы с использованием новых полей, обратитесь к документации API или свяжитесь с командой разработки. + +--- + +**Версия документа**: 1.0 +**Дата обновления**: 2025-01-20 +**Статус**: ✅ Актуально diff --git a/src/config/api.js b/src/config/api.js index 517bd40..8810401 100644 --- a/src/config/api.js +++ b/src/config/api.js @@ -62,7 +62,12 @@ export const API_CONFIG = { MARKETING_STRATEGY_GET: '/api/marketing/analysis/strategy', MARKETING_STRATEGY_BY_ANALYSIS: '/api/marketing/analysis', MARKETING_STRATEGY_MY: '/api/marketing/analysis/strategy/my', - MARKETING_STRATEGY_HISTORY: '/api/marketing/analysis/strategy' + MARKETING_STRATEGY_HISTORY: '/api/marketing/analysis/strategy', + MARKETING_STRATEGY_START: '/api/marketing/analysis/strategy', + + // SocialMediaCredentialsController - Управление credentials социальных сетей + SOCIAL_MEDIA_CREDENTIALS: '/api/social-media/credentials', + SOCIAL_MEDIA_CREDENTIALS_BY_PLATFORM: '/api/social-media/credentials' } }; diff --git a/src/router/index.js b/src/router/index.js index cb37075..4eb1c88 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -248,11 +248,16 @@ const router = createRouter({ 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: '/marketing-analysis/strategies', + name: 'marketing-strategies-list', + component: () => import('@/views/pages/marketing/MarketingStrategiesList.vue') + }, + { + path: '/marketing-analysis/credentials', + name: 'marketing-credentials', + component: () => import('@/views/pages/marketing/MarketingCredentials.vue') + }, { path: '/pages/notfound', name: 'notfound', diff --git a/src/service/MarketingService.js b/src/service/MarketingService.js index 3490920..985db3b 100644 --- a/src/service/MarketingService.js +++ b/src/service/MarketingService.js @@ -12,6 +12,7 @@ class MarketingService { * @param {string} data.location - Географическая локация работы * @param {string} data.client - Тип целевой аудитории * @param {string} data.differentiator - Уникальные особенности бизнеса + * @param {string} data.analysisType - Тип анализа (РЫНОК, КОНКУРЕНТЫ, ЦА, КАНАЛЫ, SWOT) * @returns {Promise} Объект с analysisId и статусом */ async startAnalysis(data) { @@ -23,7 +24,8 @@ class MarketingService { product: data.product, location: data.location, client: data.client, - differentiator: data.differentiator + differentiator: data.differentiator, + analysisType: data.analysisType }) }); @@ -318,6 +320,184 @@ class MarketingService { throw error; } } + + /** + * Запуск стратегии продвижения + * POST /api/marketing/analysis/strategy/{strategyId}/start + * @param {string} strategyId - Идентификатор стратегии для запуска + * @returns {Promise} Объект с информацией о запуске (tasksCreated, platforms) + */ + async startStrategy(strategyId) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_STRATEGY_START}/${strategyId}/start`, { + method: 'POST', + ...DEFAULT_REQUEST_CONFIG, + body: JSON.stringify({}) + }); + + const result = await response.json(); + + if (!response.ok) { + const error = { + message: result.message || result.error?.message || 'Ошибка при запуске стратегии', + code: result.error?.code, + details: result.error?.details + }; + throw error; + } + + if (!result.success) { + const error = { + message: result.message || 'Ошибка при запуске стратегии', + code: result.error?.code, + details: result.error?.details + }; + throw error; + } + + return result.data; + } catch (error) { + console.error('Ошибка при запуске стратегии:', error); + throw error; + } + } + + /** + * Сохранение/обновление credentials для социальной сети + * POST /api/social-media/credentials + * @param {string} platform - Название платформы (facebook, instagram, etc.) + * @param {string} credentials - Access token или другие credentials + * @returns {Promise} Объект с информацией о сохраненных credentials + */ + async saveCredentials(platform, credentials) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.SOCIAL_MEDIA_CREDENTIALS}`, { + method: 'POST', + ...DEFAULT_REQUEST_CONFIG, + body: JSON.stringify({ + platform: platform, + credentials: credentials + }) + }); + + const result = await response.json(); + + if (!response.ok) { + const error = { + message: result.message || result.error?.message || 'Ошибка при сохранении credentials', + code: result.error?.code, + details: result.error?.details + }; + throw error; + } + + if (!result.success) { + const error = { + message: result.message || 'Ошибка при сохранении credentials', + code: result.error?.code, + details: result.error?.details + }; + throw error; + } + + return result.data; + } catch (error) { + console.error('Ошибка при сохранении credentials:', error); + throw error; + } + } + + /** + * Получение информации о credentials для платформы + * GET /api/social-media/credentials/{platform} + * @param {string} platform - Название платформы + * @returns {Promise} Объект с информацией о наличии credentials + */ + async getCredentials(platform) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.SOCIAL_MEDIA_CREDENTIALS_BY_PLATFORM}/${platform}`); + + const result = await response.json(); + + if (!response.ok) { + throw new Error(result.message || result.error?.message || 'Ошибка при получении credentials'); + } + + if (!result.success) { + throw new Error(result.message || 'Ошибка при получении credentials'); + } + + return result.data; + } catch (error) { + console.error('Ошибка при получении credentials:', error); + throw error; + } + } + + /** + * Получение списка всех credentials + * GET /api/social-media/credentials + * @returns {Promise} Массив объектов с информацией о credentials для каждой платформы + */ + async getAllCredentials() { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.SOCIAL_MEDIA_CREDENTIALS}`); + + const result = await response.json(); + + if (!response.ok) { + throw new Error(result.message || result.error?.message || 'Ошибка при получении списка credentials'); + } + + if (!result.success) { + throw new Error(result.message || 'Ошибка при получении списка credentials'); + } + + return result.data; + } catch (error) { + console.error('Ошибка при получении списка credentials:', error); + throw error; + } + } + + /** + * Удаление credentials для платформы + * DELETE /api/social-media/credentials/{platform} + * @param {string} platform - Название платформы + * @returns {Promise} + */ + async deleteCredentials(platform) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.SOCIAL_MEDIA_CREDENTIALS_BY_PLATFORM}/${platform}`, { + method: 'DELETE' + }); + + const result = await response.json(); + + if (!response.ok) { + const error = { + message: result.message || result.error?.message || 'Ошибка при удалении credentials', + code: result.error?.code, + details: result.error?.details + }; + throw error; + } + + if (!result.success) { + const error = { + message: result.message || 'Ошибка при удалении credentials', + code: result.error?.code, + details: result.error?.details + }; + throw error; + } + + return result.data; + } catch (error) { + console.error('Ошибка при удалении credentials:', error); + throw error; + } + } } export default new MarketingService(); diff --git a/src/views/pages/marketing/MarketingAnalysesList.vue b/src/views/pages/marketing/MarketingAnalysesList.vue index 732003b..b55d32f 100644 --- a/src/views/pages/marketing/MarketingAnalysesList.vue +++ b/src/views/pages/marketing/MarketingAnalysesList.vue @@ -21,7 +21,7 @@ :sortField="'createdAt'" :sortOrder="-1" filterDisplay="row" - :globalFilterFields="['product', 'location', 'clientType', 'status']" + :globalFilterFields="['product', 'location', 'clientType', 'status', 'analysisType']" v-model:filters="filters" :filters="filters" dataKey="analysisId" @@ -54,6 +54,13 @@ + + + +