diff --git a/docs/marketing-analysis-api-frontend.md b/docs/marketing-analysis-api-frontend.md new file mode 100644 index 0000000..ec07f97 --- /dev/null +++ b/docs/marketing-analysis-api-frontend.md @@ -0,0 +1,539 @@ +# API Документация: Маркетинговый анализ (Frontend/AI Agent) + +## Базовый URL + +``` +https://api.konturai.kz +``` + +## Обзор + +API для генерации маркетингового анализа на основе данных о бизнесе. Процесс состоит из двух этапов: + +1. **Запуск анализа** - создание задачи и начало асинхронной обработки +2. **Получение результатов** - проверка статуса и получение готового отчета + +Анализ выполняется асинхронно и занимает примерно 5-10 минут. + +--- + +## Эндпоинты + +### 1. Запуск маркетингового анализа + +**POST** `/api/marketing/analysis/start` + +Создает новую задачу на генерацию маркетингового анализа и запускает асинхронную обработку. + +#### Заголовки запроса + +``` +Content-Type: application/json +``` + +#### Тело запроса (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 символов +- Разрешены любые символы + +#### Пример запроса + +```json +{ + "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 минут." + } +} +``` + +#### Структура ответа + +| Поле | Тип | Описание | +| ------------------------------ | ------- | --------------------------------------------------------- | +| `success` | boolean | Флаг успешности операции | +| `message` | string | Сообщение о результате операции | +| `data.analysisId` | string | Уникальный идентификатор анализа (MongoDB ObjectId) | +| `data.status` | string | Статус анализа: `"processing"` | +| `data.estimatedCompletionTime` | string | ISO 8601 дата/время ожидаемого завершения (LocalDateTime) | +| `data.message` | string | Информационное сообщение для пользователя | + +#### Пример ошибки валидации (400 Bad Request) + +```json +{ + "success": false, + "message": "Ошибка валидации", + "error": { + "code": "VALIDATION_ERROR", + "message": "Ошибка валидации входных данных", + "details": { + "product": "Поле 'product' должно содержать от 3 до 200 символов", + "client": "Поле 'client' должно быть одним из: B2B клиенты, B2C клиенты, Частные лица, Корпорации, Малый бизнес" + } + } +} +``` + +--- + +### 2. Получение результата анализа + +**GET** `/api/marketing/analysis/{analysisId}` + +Возвращает статус и результаты анализа по идентификатору. + +#### Параметры пути + +| Параметр | Тип | Описание | +| ------------ | ------ | --------------------- | +| `analysisId` | string | Идентификатор анализа | + +#### Пример запроса + +``` +GET /api/marketing/analysis/507f1f77bcf86cd799439011 +``` + +#### Пример ответа (когда анализ завершен - 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", "Рекомендация 3"], + "strategy": { + "duration": "2 недели", + "channels": ["Instagram", "Telegram", "21MC"], + "contentTypes": ["посты", "сторис", "баннеры"] + }, + "pdfUrl": "/api/marketing/analysis/507f1f77bcf86cd799439011/download" + } + } +} +``` + +#### Пример ответа (когда анализ еще обрабатывается - 200 OK) + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": { + "analysisId": "507f1f77bcf86cd799439011", + "status": "processing", + "createdAt": "2025-01-20T15:30:00", + "completedAt": null, + "report": null + } +} +``` + +#### Статусы анализа + +| Статус | Описание | +| ------------ | ----------------------------- | +| `queued` | Запрос в очереди на обработку | +| `processing` | Анализ выполняется | +| `completed` | Анализ завершен успешно | +| `failed` | Анализ завершился с ошибкой | + +#### Структура ответа + +| Поле | Тип | Описание | +| ---------------------------------------- | ------- | ------------------------------------------------------ | +| `success` | boolean | Флаг успешности операции | +| `message` | string | Сообщение о результате операции | +| `data.analysisId` | string | Уникальный идентификатор анализа | +| `data.status` | string | Статус анализа | +| `data.createdAt` | string | ISO 8601 дата/время создания | +| `data.completedAt` | string | ISO 8601 дата/время завершения (null если не завершен) | +| `data.report` | object | Объект с результатами (null если не завершен) | +| `data.report.summary` | string | Краткое резюме анализа | +| `data.report.targetAudience` | object | Информация о целевой аудитории | +| `data.report.targetAudience.description` | string | Описание целевой аудитории | +| `data.report.targetAudience.channels` | array | Список рекомендуемых каналов | +| `data.report.recommendations` | array | Список рекомендаций (массив строк) | +| `data.report.strategy` | object | Маркетинговая стратегия | +| `data.report.strategy.duration` | string | Длительность кампании (например, "2 недели") | +| `data.report.strategy.channels` | array | Каналы коммуникации (массив строк) | +| `data.report.strategy.contentTypes` | array | Типы контента (массив строк) | +| `data.report.pdfUrl` | string | URL для скачивания PDF отчета | + +#### Пример ошибки (404 Not Found) + +```json +{ + "success": false, + "message": "Анализ не найден", + "error": { + "code": "NOT_FOUND", + "message": "Анализ с указанным ID не найден" + } +} +``` + +--- + +### 3. Скачивание PDF отчета + +**GET** `/api/marketing/analysis/{analysisId}/download` + +Возвращает PDF файл с полным маркетинговым отчетом. + +#### Параметры пути + +| Параметр | Тип | Описание | +| ------------ | ------ | --------------------- | +| `analysisId` | string | Идентификатор анализа | + +#### Пример запроса + +``` +GET /api/marketing/analysis/507f1f77bcf86cd799439011/download +``` + +#### Успешный ответ (200 OK) + +- **Content-Type**: `application/pdf` +- **Content-Disposition**: `attachment; filename="marketing_analysis_507f1f77bcf86cd799439011_1234567890.pdf"` +- **Body**: Бинарные данные PDF файла + +#### Ошибки + +- **404 Not Found** - Анализ не найден или PDF еще не сгенерирован +- **500 Internal Server Error** - Ошибка при получении файла + +--- + +## Обработка ошибок + +### Коды ошибок + +| Код | HTTP статус | Описание | +| ----------------------- | ----------- | ------------------------------- | +| `VALIDATION_ERROR` | 400 | Ошибка валидации входных данных | +| `NOT_FOUND` | 404 | Ресурс не найден | +| `INTERNAL_SERVER_ERROR` | 500 | Внутренняя ошибка сервера | + +### Формат ошибки + +```json +{ + "success": false, + "message": "Описание ошибки", + "error": { + "code": "ERROR_CODE", + "message": "Детальное сообщение об ошибке", + "details": { + "field1": "Сообщение об ошибке для поля 1", + "field2": "Сообщение об ошибке для поля 2" + } + } +} +``` + +**Примечание**: Поле `details` присутствует только для ошибок валидации (`VALIDATION_ERROR`). + +--- + +## Примеры использования + +### JavaScript/TypeScript (Fetch API) + +#### Запуск анализа + +```javascript +async function startMarketingAnalysis(data) { + const response = await fetch('https://api.konturai.kz/api/marketing/analysis/start', { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + product: 'Разработка мобильных приложений', + location: 'Нур-Султан, Казахстан', + client: 'B2B клиенты', + differentiator: 'Специализируемся на быстрой разработке MVP за 4 недели' + }) + }); + + const result = await response.json(); + + if (result.success) { + console.log('Analysis ID:', result.data.analysisId); + return result.data.analysisId; + } else { + console.error('Error:', result.error); + throw new Error(result.error.message); + } +} +``` + +#### Проверка статуса и получение результата + +```javascript +async function getAnalysisResult(analysisId) { + const response = await fetch(`https://api.konturai.kz/api/marketing/analysis/${analysisId}`); + + const result = await response.json(); + + if (result.success) { + const { status, report } = result.data; + + if (status === 'completed' && report) { + console.log('Analysis completed!'); + console.log('Summary:', report.summary); + console.log('Recommendations:', report.recommendations); + return report; + } else if (status === 'processing') { + console.log('Analysis is still processing...'); + return null; // Повторить запрос позже + } else if (status === 'failed') { + throw new Error('Analysis failed'); + } + } else { + throw new Error(result.error.message); + } +} +``` + +#### Полный цикл с polling + +```javascript +async function waitForAnalysisCompletion(analysisId, maxAttempts = 60, intervalMs = 10000) { + for (let i = 0; i < maxAttempts; i++) { + const result = await getAnalysisResult(analysisId); + + if (result) { + return result; // Анализ завершен + } + + // Ждем перед следующей проверкой + await new Promise((resolve) => setTimeout(resolve, intervalMs)); + } + + throw new Error('Analysis timeout'); +} + +// Использование +async function runFullAnalysis() { + try { + // 1. Запускаем анализ + const analysisId = await startMarketingAnalysis({ + product: 'Веб-разработка', + location: 'Алматы, Казахстан', + client: 'B2B клиенты', + differentiator: 'Быстрая разработка за 2 недели' + }); + + console.log(`Analysis started: ${analysisId}`); + + // 2. Ждем завершения (проверяем каждые 10 секунд, максимум 10 минут) + const report = await waitForAnalysisCompletion(analysisId, 60, 10000); + + // 3. Используем результаты + console.log('Report summary:', report.summary); + console.log('Channels:', report.targetAudience.channels); + console.log('PDF URL:', report.pdfUrl); + + return report; + } catch (error) { + console.error('Error:', error); + } +} +``` + +#### Скачивание PDF + +```javascript +async function downloadPdf(analysisId) { + const response = await fetch(`https://api.konturai.kz/api/marketing/analysis/${analysisId}/download`); + + if (!response.ok) { + throw new Error('Failed to download PDF'); + } + + 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`; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); +} +``` + +### Python + +```python +import requests +import time + +BASE_URL = "https://api.konturai.kz" + +def start_analysis(product, location, client, differentiator): + response = requests.post( + f"{BASE_URL}/api/marketing/analysis/start", + json={ + "product": product, + "location": location, + "client": client, + "differentiator": differentiator + } + ) + response.raise_for_status() + data = response.json() + + if data["success"]: + return data["data"]["analysisId"] + else: + raise Exception(data["error"]["message"]) + +def get_analysis_result(analysis_id): + response = requests.get( + f"{BASE_URL}/api/marketing/analysis/{analysis_id}" + ) + response.raise_for_status() + return response.json()["data"] + +def wait_for_completion(analysis_id, max_attempts=60, interval=10): + for _ in range(max_attempts): + result = get_analysis_result(analysis_id) + + if result["status"] == "completed": + return result["report"] + elif result["status"] == "failed": + raise Exception("Analysis failed") + + time.sleep(interval) + + raise Exception("Analysis timeout") + +# Использование +analysis_id = start_analysis( + product="Разработка мобильных приложений", + location="Нур-Султан, Казахстан", + client="B2B клиенты", + differentiator="Быстрая разработка MVP за 4 недели" +) + +print(f"Analysis started: {analysis_id}") + +report = wait_for_completion(analysis_id) +print(f"Summary: {report['summary']}") +print(f"Channels: {report['targetAudience']['channels']}") +``` + +--- + +## Рекомендации по интеграции + +### 1. Polling стратегия + +Рекомендуется проверять статус анализа каждые 10-15 секунд. Максимальное время ожидания - 10-15 минут. + +### 2. Обработка ошибок + +Всегда проверяйте поле `success` в ответе и обрабатывайте ошибки соответствующим образом. + +### 3. Валидация на клиенте + +Перед отправкой запроса рекомендуется валидировать данные на клиенте: + +- Проверка длины полей +- Проверка допустимых значений для `client` +- Проверка обязательных полей + +### 4. UX рекомендации + +- Показывайте индикатор загрузки во время обработки +- Отображайте примерное время завершения +- Предоставьте возможность отменить ожидание и проверить результат позже +- Сохраняйте `analysisId` для последующей проверки статуса + +### 5. Кэширование + +После получения результатов можно кэшировать их локально, используя `analysisId` как ключ. + +--- + +## Примечания + +1. **Формат даты**: Все даты возвращаются в формате ISO 8601 без timezone (LocalDateTime) +2. **Идентификаторы**: Используются MongoDB ObjectId (24 символа hex) +3. **Асинхронность**: Анализ выполняется асинхронно, не блокируя запрос +4. **Таймауты**: Рекомендуется устанавливать таймаут на запросы (минимум 30 секунд для запуска анализа) +5. **Rate Limiting**: В будущем может быть добавлено ограничение на количество запросов + +--- + +## Поддержка + +При возникновении проблем с API обращайтесь в техническую поддержку с указанием: + +- `analysisId` (если есть) +- Время запроса +- Описание проблемы +- Код ошибки (если есть) diff --git a/docs/marketing-analysis-api.md b/docs/marketing-analysis-api.md new file mode 100644 index 0000000..5583777 --- /dev/null +++ b/docs/marketing-analysis-api.md @@ -0,0 +1,358 @@ +# API Документация: Маркетинговый анализ + +## Обзор + +API для запуска маркетингового анализа на основе данных о бизнесе пользователя. Эндпоинт принимает информацию о продукте, локации, типе клиентов и уникальных особенностях бизнеса, затем генерирует маркетинговый отчет. + +## Эндпоинт + +**POST** `/api/marketing/analysis/start` + +### Базовый URL + +``` +https://api.konturai.kz/api/marketing/analysis/start +``` + +## Запрос + +### Заголовки + +``` +Content-Type: application/json +Authorization: Bearer {access_token} // Опционально, если требуется аутентификация +``` + +### Тело запроса (JSON) + +| Поле | Тип | Обязательный | Описание | Пример значения | +| ---------------- | ------ | ------------ | ------------------------------ | -------------------------------- | +| `product` | string | ✅ | Название продукта или услуги | "Веб-разработка" | +| `location` | string | ✅ | Географическая локация работы | "Алматы, Казахстан" | +| `client` | string | ✅ | Тип целевой аудитории | "B2B клиенты" | +| `differentiator` | string | ✅ | Уникальные особенности бизнеса | "Быстрая разработка за 2 недели" | + +### Валидация полей + +#### `product` (string, обязательное) + +- **Минимальная длина**: 3 символа +- **Максимальная длина**: 200 символов +- **Паттерн**: Разрешены буквы, цифры, пробелы, дефисы, запятые +- **Ошибка валидации**: `"product": "Поле 'product' должно содержать от 3 до 200 символов"` + +#### `location` (string, обязательное) + +- **Минимальная длина**: 2 символа +- **Максимальная длина**: 150 символов +- **Паттерн**: Разрешены буквы, цифры, пробелы, запятые, дефисы +- **Ошибка валидации**: `"location": "Поле 'location' должно содержать от 2 до 150 символов"` + +#### `client` (string, обязательное) + +- **Допустимые значения**: + - `"B2B клиенты"` + - `"B2C клиенты"` + - `"Частные лица"` + - `"Корпорации"` + - `"Малый бизнес"` +- **Ошибка валидации**: `"client": "Поле 'client' должно быть одним из: B2B клиенты, B2C клиенты, Частные лица, Корпорации, Малый бизнес"` + +#### `differentiator` (string, обязательное) + +- **Минимальная длина**: 10 символов +- **Максимальная длина**: 500 символов +- **Паттерн**: Разрешены любые символы +- **Ошибка валидации**: `"differentiator": "Поле 'differentiator' должно содержать от 10 до 500 символов"` + +### Пример запроса + +```json +{ + "product": "Разработка мобильных приложений", + "location": "Нур-Султан, Казахстан", + "client": "B2B клиенты", + "differentiator": "Специализируемся на быстрой разработке MVP за 4 недели с использованием современных технологий" +} +``` + +## Ответ + +### Успешный ответ (200 OK) + +```json +{ + "success": true, + "data": { + "analysisId": "550e8400-e29b-41d4-a716-446655440000", + "status": "processing", + "estimatedCompletionTime": "2025-01-20T15:30:00Z", + "message": "Анализ запущен успешно. Результаты будут готовы в течение 5-10 минут." + } +} +``` + +#### Поля ответа + +| Поле | Тип | Описание | +| ------------------------------ | ------- | --------------------------------------------------------- | +| `success` | boolean | Флаг успешности операции | +| `data.analysisId` | string | Уникальный идентификатор анализа (UUID) | +| `data.status` | string | Статус анализа: `"processing"`, `"completed"`, `"failed"` | +| `data.estimatedCompletionTime` | string | ISO 8601 дата/время ожидаемого завершения анализа | +| `data.message` | string | Информационное сообщение для пользователя | + +### Асинхронная обработка (202 Accepted) + +Если анализ требует длительной обработки, сервер может вернуть статус 202: + +```json +{ + "success": true, + "data": { + "analysisId": "550e8400-e29b-41d4-a716-446655440000", + "status": "queued", + "queuePosition": 3, + "estimatedWaitTime": 300, + "message": "Запрос добавлен в очередь. Примерное время ожидания: 5 минут." + } +} +``` + +## Обработка ошибок + +### Ошибки валидации (400 Bad Request) + +```json +{ + "success": false, + "error": { + "code": "VALIDATION_ERROR", + "message": "Ошибка валидации входных данных", + "details": { + "product": "Поле 'product' обязательно для заполнения", + "client": "Недопустимое значение поля 'client'" + } + } +} +``` + +### Ошибка аутентификации (401 Unauthorized) + +```json +{ + "success": false, + "error": { + "code": "UNAUTHORIZED", + "message": "Требуется аутентификация" + } +} +``` + +### Ошибка сервера (500 Internal Server Error) + +```json +{ + "success": false, + "error": { + "code": "INTERNAL_SERVER_ERROR", + "message": "Произошла внутренняя ошибка сервера. Попробуйте позже." + } +} +``` + +### Ошибка таймаута (504 Gateway Timeout) + +```json +{ + "success": false, + "error": { + "code": "TIMEOUT", + "message": "Превышено время ожидания ответа от сервиса анализа" + } +} +``` + +## Получение результатов анализа + +После успешного запуска анализа, результаты можно получить по идентификатору: + +**GET** `/api/marketing/analysis/{analysisId}` + +### Пример запроса + +``` +GET /api/marketing/analysis/550e8400-e29b-41d4-a716-446655440000 +``` + +### Пример ответа (когда анализ завершен) + +```json +{ + "success": true, + "data": { + "analysisId": "550e8400-e29b-41d4-a716-446655440000", + "status": "completed", + "createdAt": "2025-01-20T15:00:00Z", + "completedAt": "2025-01-20T15:08:00Z", + "report": { + "summary": "Краткое резюме анализа...", + "targetAudience": { + "description": "Описание целевой аудитории...", + "channels": ["Instagram", "LinkedIn", "Telegram"] + }, + "recommendations": ["Рекомендация 1", "Рекомендация 2"], + "strategy": { + "duration": "2 недели", + "channels": ["Instagram", "Telegram", "21MC"], + "contentTypes": ["посты", "сторис", "баннеры"] + }, + "pdfUrl": "/api/marketing/analysis/550e8400-e29b-41d4-a716-446655440000/download" + } + } +} +``` + +### Статусы анализа + +- `queued` - Запрос в очереди на обработку +- `processing` - Анализ выполняется +- `completed` - Анализ завершен успешно +- `failed` - Анализ завершился с ошибкой + +## Рекомендации по реализации + +### 1. Валидация на бэкенде + +```java +// Пример валидации (Java/Spring Boot) +@PostMapping("/api/marketing/analysis/start") +public ResponseEntity startAnalysis(@Valid @RequestBody MarketingAnalysisRequest request) { + // Валидация выполняется автоматически через @Valid + // Дополнительная бизнес-логика валидации + if (!isValidClientType(request.getClient())) { + return ResponseEntity.badRequest() + .body(new ErrorResponse("VALIDATION_ERROR", "Недопустимый тип клиента")); + } + // Обработка запроса +} +``` + +### 2. Асинхронная обработка + +Рекомендуется использовать асинхронную обработку для длительных операций: + +```java +@Async +public CompletableFuture processAnalysis(MarketingAnalysisRequest request) { + // Длительная обработка + // Генерация отчета + // Сохранение результатов + return CompletableFuture.completedFuture(result); +} +``` + +### 3. Хранение данных + +Рекомендуемая структура таблицы в БД: + +```sql +CREATE TABLE marketing_analysis ( + id UUID PRIMARY KEY, + product VARCHAR(200) NOT NULL, + location VARCHAR(150) NOT NULL, + client_type VARCHAR(50) NOT NULL, + differentiator TEXT NOT NULL, + status VARCHAR(20) NOT NULL, + created_at TIMESTAMP NOT NULL, + completed_at TIMESTAMP, + user_id UUID, -- Если требуется аутентификация + report_data JSONB, -- JSON с результатами анализа + CONSTRAINT valid_client_type CHECK (client_type IN ( + 'B2B клиенты', 'B2C клиенты', 'Частные лица', 'Корпорации', 'Малый бизнес' + )), + CONSTRAINT valid_status CHECK (status IN ( + 'queued', 'processing', 'completed', 'failed' + )) +); +``` + +### 4. Интеграция с AI сервисом + +Если используется внешний AI сервис для генерации анализа: + +```java +public AnalysisResult generateAnalysis(MarketingAnalysisRequest request) { + // Подготовка промпта для AI + String prompt = String.format( + "Проанализируй бизнес:\n" + + "Продукт: %s\n" + + "Локация: %s\n" + + "Клиенты: %s\n" + + "Уникальность: %s\n" + + "Создай маркетинговую стратегию...", + request.getProduct(), + request.getLocation(), + request.getClient(), + request.getDifferentiator() + ); + + // Вызов AI API + return aiService.generateReport(prompt); +} +``` + +### 5. Обработка ошибок + +```java +@ExceptionHandler(ValidationException.class) +public ResponseEntity handleValidationException(ValidationException e) { + return ResponseEntity.badRequest() + .body(new ErrorResponse("VALIDATION_ERROR", e.getMessage(), e.getDetails())); +} + +@ExceptionHandler(Exception.class) +public ResponseEntity handleGenericException(Exception e) { + log.error("Unexpected error", e); + return ResponseEntity.status(500) + .body(new ErrorResponse("INTERNAL_SERVER_ERROR", "Внутренняя ошибка сервера")); +} +``` + +## Тестирование + +### Примеры тестовых запросов + +#### Успешный запрос + +```bash +curl -X POST https://api.konturai.kz/api/marketing/analysis/start \ + -H "Content-Type: application/json" \ + -d '{ + "product": "Разработка мобильных приложений", + "location": "Алматы, Казахстан", + "client": "B2B клиенты", + "differentiator": "Специализируемся на быстрой разработке MVP за 4 недели" + }' +``` + +#### Запрос с ошибкой валидации + +```bash +curl -X POST https://api.konturai.kz/api/marketing/analysis/start \ + -H "Content-Type: application/json" \ + -d '{ + "product": "AB", + "location": "Алматы", + "client": "Неверный тип", + "differentiator": "Коротко" + }' +``` + +## Примечания + +1. **Аутентификация**: Если требуется аутентификация, используйте JWT токен в заголовке `Authorization` +2. **Rate Limiting**: Рекомендуется ограничить количество запросов на пользователя (например, 10 запросов в час) +3. **Кэширование**: Можно кэшировать результаты для одинаковых запросов +4. **Логирование**: Все запросы должны логироваться для отладки и аналитики +5. **Мониторинг**: Отслеживайте время выполнения анализа и процент успешных завершений diff --git a/docs/marketing-strategy-api-frontend.md b/docs/marketing-strategy-api-frontend.md new file mode 100644 index 0000000..b16fbe7 --- /dev/null +++ b/docs/marketing-strategy-api-frontend.md @@ -0,0 +1,922 @@ +# API Документация: Генерация стратегии продвижения (Frontend/AI Agent) + +## Базовый URL + +``` +https://api.konturai.kz +``` + +## Обзор + +API для генерации детальной стратегии продвижения продукта на основе маркетингового анализа. Стратегия включает: + +1. **Недельный план** - темы и рекомендации по контенту для каждой недели +2. **Календарь постов** - детальный план публикаций с датами, платформами, текстами и хештегами + +Процесс состоит из двух этапов: + +1. **Запуск генерации стратегии** - создание задачи и начало асинхронной обработки +2. **Получение результатов** - проверка статуса и получение готовой стратегии + +Генерация стратегии выполняется асинхронно и занимает примерно 3-5 минут. + +**Важно**: Для генерации стратегии требуется завершенный маркетинговый анализ. Сначала необходимо получить `analysisId` из завершенного анализа. + +--- + +## Эндпоинты + +### 1. Запуск генерации стратегии продвижения + +**POST** `/api/marketing/strategy/generate` + +Создает новую задачу на генерацию стратегии продвижения и запускает асинхронную обработку. + +#### Параметры запроса + +| Параметр | Тип | Расположение | Обязательный | Описание | +| ------------------- | ------- | ------------ | ------------ | --------------------------------------- | +| `analysisId` | string | Query | ✅ | ID завершенного маркетингового анализа | +| `durationWeeks` | integer | Body | ❌ | Длительность стратегии в неделях (1-12) | +| `priorityPlatforms` | array | Body | ❌ | Приоритетные платформы для продвижения | + +#### Заголовки запроса + +``` +Content-Type: application/json +``` + +#### Тело запроса (JSON, опционально) + +| Поле | Тип | Обязательный | Описание | Пример значения | +| ------------------- | ------- | ------------ | --------------------------------------- | ------------------------------------- | +| `durationWeeks` | integer | ❌ | Длительность стратегии в неделях (1-12) | 4 | +| `priorityPlatforms` | array | ❌ | Список приоритетных платформ | ["Instagram", "LinkedIn", "Telegram"] | + +#### Валидация полей + +**`durationWeeks`** (integer, опциональное) + +- Минимальное значение: 1 +- Максимальное значение: 12 +- По умолчанию: 4 (если не указано) + +**`priorityPlatforms`** (array, опциональное) + +- Допустимые платформы: `Instagram`, `Facebook`, `LinkedIn`, `Telegram`, `TikTok`, `YouTube`, `21MC` и другие +- Если не указано, используются все популярные платформы + +#### Пример запроса + +```http +POST /api/marketing/strategy/generate?analysisId=507f1f77bcf86cd799439011 +Content-Type: application/json + +{ + "durationWeeks": 4, + "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"] +} +``` + +Или без тела запроса (используются значения по умолчанию): + +```http +POST /api/marketing/strategy/generate?analysisId=507f1f77bcf86cd799439011 +``` + +#### Пример успешного ответа (200 OK) + +```json +{ + "success": true, + "message": "Генерация стратегии запущена успешно. Результаты будут готовы в течение 3-5 минут.", + "data": { + "strategyId": "507f1f77bcf86cd799439012", + "analysisId": "507f1f77bcf86cd799439011", + "status": "queued", + "createdAt": "2025-01-20T15:40:00", + "durationWeeks": 4, + "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"] + } +} +``` + +#### Структура ответа + +| Поле | Тип | Описание | +| ------------------------ | ------- | ----------------------------------------------------------------------- | +| `success` | boolean | Флаг успешности операции | +| `message` | string | Сообщение о результате операции | +| `data.strategyId` | string | Уникальный идентификатор стратегии (MongoDB ObjectId) | +| `data.analysisId` | string | ID маркетингового анализа | +| `data.status` | string | Статус стратегии: `"queued"`, `"processing"`, `"completed"`, `"failed"` | +| `data.createdAt` | string | ISO 8601 дата/время создания | +| `data.durationWeeks` | integer | Длительность стратегии в неделях | +| `data.priorityPlatforms` | array | Список приоритетных платформ | + +#### Пример ошибки (404 Not Found - анализ не найден) + +```json +{ + "success": false, + "message": "Анализ не найден", + "error": { + "code": "INVALID_ANALYSIS", + "message": "Анализ с ID 507f1f77bcf86cd799439011 не найден" + } +} +``` + +#### Пример ошибки (400 Bad Request - анализ не завершен) + +```json +{ + "success": false, + "message": "Анализ еще не завершен", + "error": { + "code": "ANALYSIS_NOT_COMPLETED", + "message": "Анализ еще не завершен. Статус: processing" + } +} +``` + +#### Пример ошибки валидации (400 Bad Request) + +```json +{ + "success": false, + "message": "Ошибка валидации", + "error": { + "code": "VALIDATION_ERROR", + "message": "Ошибка валидации входных данных", + "details": { + "durationWeeks": "Длительность стратегии должна быть не менее 1 недели" + } + } +} +``` + +--- + +### 2. Получение стратегии по ID + +**GET** `/api/marketing/strategy/{strategyId}` + +Возвращает статус и результаты стратегии по идентификатору. + +#### Параметры пути + +| Параметр | Тип | Описание | +| ------------ | ------ | ----------------------- | +| `strategyId` | string | Идентификатор стратегии | + +#### Пример запроса + +``` +GET /api/marketing/strategy/507f1f77bcf86cd799439012 +``` + +#### Пример ответа (когда стратегия завершена - 200 OK) + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": { + "strategyId": "507f1f77bcf86cd799439012", + "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"] + }, + { + "weekNumber": 2, + "mainThemes": [ + "Кейсы успешных клиентов", + "Отзывы и рекомендации", + "Демонстрация результатов" + ], + "contentRecommendations": "Публикуйте реальные истории успеха ваших клиентов. Используйте отзывы и рекомендации для повышения доверия. Покажите конкретные результаты и достижения.", + "priorityPlatforms": ["Instagram", "Telegram"] + }, + { + "weekNumber": 3, + "mainThemes": [ + "Образовательный контент", + "Советы и рекомендации", + "Индустриальные инсайты" + ], + "contentRecommendations": "Создавайте образовательный контент, который помогает вашей целевой аудитории. Делитесь экспертными знаниями и инсайтами индустрии. Позиционируйте себя как эксперта в области.", + "priorityPlatforms": ["LinkedIn", "Telegram"] + }, + { + "weekNumber": 4, + "mainThemes": [ + "Призыв к действию", + "Специальные предложения", + "Завершение кампании" + ], + "contentRecommendations": "Активно призывайте к действию. Предлагайте специальные условия или бонусы. Подводите итоги кампании и демонстрируйте достигнутые результаты.", + "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"] + } + ], + "postCalendar": [ + { + "publishDate": "2025-01-21T10:00:00", + "platform": "Instagram", + "contentType": "пост", + "theme": "Презентация продукта", + "postText": "🚀 Представляем наш новый продукт! Мы создали решение, которое поможет вашему бизнесу достичь новых высот. Узнайте больше о ключевых преимуществах в нашем профиле. #бизнес #инновации #продукт", + "hashtags": [ + "#бизнес", + "#инновации", + "#продукт", + "#маркетинг", + "#развитие" + ], + "publishTime": "10:00" + }, + { + "publishDate": "2025-01-21T14:00:00", + "platform": "LinkedIn", + "contentType": "пост", + "theme": "Ключевые преимущества", + "postText": "Наш продукт предлагает уникальные преимущества для B2B клиентов: быстрая интеграция, масштабируемость и надежная поддержка. Свяжитесь с нами для консультации. #B2B #технологии #бизнес", + "hashtags": [ + "#B2B", + "#технологии", + "#бизнес", + "#решения", + "#консультация" + ], + "publishTime": "14:00" + }, + { + "publishDate": "2025-01-22T18:00:00", + "platform": "Instagram", + "contentType": "сторис", + "theme": "Решение проблем клиентов", + "postText": "Знаете ли вы, что 80% компаний сталкиваются с проблемой X? Наш продукт решает эту проблему эффективно и быстро. Swipe up для деталей! 👆", + "hashtags": ["#решение", "#проблемы", "#эффективность"], + "publishTime": "18:00" + }, + { + "publishDate": "2025-01-23T10:00:00", + "platform": "Telegram", + "contentType": "пост", + "theme": "Кейс успешного клиента", + "postText": "📊 Кейс: Как компания X увеличила эффективность на 150% с помощью нашего продукта. Читайте полную историю в нашем канале. #кейс #успех #результаты", + "hashtags": ["#кейс", "#успех", "#результаты", "#бизнес"], + "publishTime": "10:00" + } + ] + } + } +} +``` + +#### Пример ответа (когда стратегия еще обрабатывается - 200 OK) + +```json +{ + "success": true, + "message": "Операция выполнена успешно", + "data": { + "strategyId": "507f1f77bcf86cd799439012", + "analysisId": "507f1f77bcf86cd799439011", + "status": "processing", + "createdAt": "2025-01-20T15:40:00", + "completedAt": null, + "durationWeeks": 4, + "priorityPlatforms": ["Instagram", "LinkedIn", "Telegram"], + "strategy": null + } +} +``` + +#### Статусы стратегии + +| Статус | Описание | +| ------------ | ------------------------------- | +| `queued` | Запрос в очереди на обработку | +| `processing` | Стратегия генерируется | +| `completed` | Стратегия завершена успешно | +| `failed` | Стратегия завершилась с ошибкой | + +#### Структура ответа + +| Поле | Тип | Описание | +| ---------------------------------------------------- | ------- | ------------------------------------------------------ | +| `success` | boolean | Флаг успешности операции | +| `message` | string | Сообщение о результате операции | +| `data.strategyId` | string | Уникальный идентификатор стратегии | +| `data.analysisId` | string | ID маркетингового анализа | +| `data.status` | string | Статус стратегии | +| `data.createdAt` | string | ISO 8601 дата/время создания | +| `data.completedAt` | string | ISO 8601 дата/время завершения (null если не завершен) | +| `data.durationWeeks` | integer | Длительность стратегии в неделях | +| `data.priorityPlatforms` | array | Список приоритетных платформ | +| `data.strategy` | object | Объект со стратегией (null если не завершен) | +| `data.strategy.weeklyPlans` | array | Список недельных планов | +| `data.strategy.weeklyPlans[].weekNumber` | integer | Номер недели (1, 2, 3, ...) | +| `data.strategy.weeklyPlans[].mainThemes` | array | Основные темы недели (массив строк) | +| `data.strategy.weeklyPlans[].contentRecommendations` | string | Рекомендации по контенту для недели | +| `data.strategy.weeklyPlans[].priorityPlatforms` | array | Приоритетные платформы для недели | +| `data.strategy.postCalendar` | array | Календарь постов | +| `data.strategy.postCalendar[].publishDate` | string | ISO 8601 дата/время публикации | +| `data.strategy.postCalendar[].platform` | string | Платформа для публикации | +| `data.strategy.postCalendar[].contentType` | string | Тип контента (пост, сторис, видео, баннер) | +| `data.strategy.postCalendar[].theme` | string | Тема поста | +| `data.strategy.postCalendar[].postText` | string | Полный текст поста (готовый к публикации) | +| `data.strategy.postCalendar[].hashtags` | array | Список хештегов (массив строк) | +| `data.strategy.postCalendar[].publishTime` | string | Время публикации в формате HH:mm | + +#### Пример ошибки (404 Not Found) + +```json +{ + "success": false, + "message": "Стратегия не найдена", + "error": { + "code": "NOT_FOUND", + "message": "Стратегия с указанным ID не найдена" + } +} +``` + +--- + +### 3. Получение стратегии по ID анализа + +**GET** `/api/marketing/analysis/{analysisId}/strategy` + +Возвращает стратегию, связанную с указанным маркетинговым анализом. + +#### Параметры пути + +| Параметр | Тип | Описание | +| ------------ | ------ | --------------------- | +| `analysisId` | string | Идентификатор анализа | + +#### Пример запроса + +``` +GET /api/marketing/analysis/507f1f77bcf86cd799439011/strategy +``` + +#### Пример ответа + +Структура ответа идентична эндпоинту `GET /api/marketing/strategy/{strategyId}` (см. выше). + +#### Пример ошибки (404 Not Found) + +```json +{ + "success": false, + "message": "Стратегия не найдена", + "error": { + "code": "NOT_FOUND", + "message": "Стратегия для указанного анализа не найдена" + } +} +``` + +--- + +## Обработка ошибок + +### Коды ошибок + +| Код | HTTP статус | Описание | +| ------------------------ | ----------- | ------------------------------- | +| `VALIDATION_ERROR` | 400 | Ошибка валидации входных данных | +| `INVALID_ANALYSIS` | 404 | Анализ не найден | +| `ANALYSIS_NOT_COMPLETED` | 400 | Анализ еще не завершен | +| `NOT_FOUND` | 404 | Стратегия не найдена | +| `INTERNAL_SERVER_ERROR` | 500 | Внутренняя ошибка сервера | + +### Формат ошибки + +```json +{ + "success": false, + "message": "Описание ошибки", + "error": { + "code": "ERROR_CODE", + "message": "Детальное сообщение об ошибке", + "details": { + "field1": "Сообщение об ошибке для поля 1", + "field2": "Сообщение об ошибке для поля 2" + } + } +} +``` + +**Примечание**: Поле `details` присутствует только для ошибок валидации (`VALIDATION_ERROR`). + +--- + +## Примеры использования + +### JavaScript/TypeScript (Fetch API) + +#### Запуск генерации стратегии + +```javascript +async function generateStrategy(analysisId, options = {}) { + const params = new URLSearchParams(); + params.append('analysisId', analysisId); + + const response = await fetch( + `https://api.konturai.kz/api/marketing/strategy/generate?${params}`, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + durationWeeks: options.durationWeeks || 4, + priorityPlatforms: options.priorityPlatforms || [], + }), + } + ); + + const result = await response.json(); + + if (result.success) { + console.log('Strategy ID:', result.data.strategyId); + return result.data.strategyId; + } else { + console.error('Error:', result.error); + throw new Error(result.error.message); + } +} +``` + +#### Проверка статуса и получение результата + +```javascript +async function getStrategyResult(strategyId) { + const response = await fetch( + `https://api.konturai.kz/api/marketing/strategy/${strategyId}` + ); + + const result = await response.json(); + + if (result.success) { + const { status, strategy } = result.data; + + if (status === 'completed' && strategy) { + console.log('Strategy completed!'); + console.log('Weekly plans:', strategy.weeklyPlans); + console.log('Post calendar:', strategy.postCalendar); + return strategy; + } else if (status === 'processing') { + console.log('Strategy is still generating...'); + return null; // Повторить запрос позже + } else if (status === 'failed') { + throw new Error('Strategy generation failed'); + } + } else { + throw new Error(result.error.message); + } +} +``` + +#### Получение стратегии по ID анализа + +```javascript +async function getStrategyByAnalysis(analysisId) { + const response = await fetch( + `https://api.konturai.kz/api/marketing/analysis/${analysisId}/strategy` + ); + + const result = await response.json(); + + if (result.success) { + return result.data; + } else { + throw new Error(result.error.message); + } +} +``` + +#### Полный цикл с polling + +```javascript +async function waitForStrategyCompletion( + strategyId, + maxAttempts = 60, + intervalMs = 10000 +) { + for (let i = 0; i < maxAttempts; i++) { + const result = await getStrategyResult(strategyId); + + if (result) { + return result; // Стратегия завершена + } + + // Ждем перед следующей проверкой + await new Promise((resolve) => setTimeout(resolve, intervalMs)); + } + + throw new Error('Strategy generation timeout'); +} + +// Использование +async function runFullStrategyGeneration() { + try { + // 1. Получаем завершенный анализ (предполагается, что analysisId уже есть) + const analysisId = '507f1f77bcf86cd799439011'; + + // 2. Запускаем генерацию стратегии + const strategyId = await generateStrategy(analysisId, { + durationWeeks: 4, + priorityPlatforms: ['Instagram', 'LinkedIn', 'Telegram'], + }); + + console.log(`Strategy generation started: ${strategyId}`); + + // 3. Ждем завершения (проверяем каждые 10 секунд, максимум 10 минут) + const strategy = await waitForStrategyCompletion(strategyId, 60, 10000); + + // 4. Используем результаты + console.log('Weekly plans:', strategy.weeklyPlans); + console.log('Post calendar:', strategy.postCalendar); + + // Отображаем календарь постов + strategy.postCalendar.forEach((post) => { + console.log(`${post.publishDate} - ${post.platform}: ${post.theme}`); + }); + + return strategy; + } catch (error) { + console.error('Error:', error); + } +} +``` + +### React примеры + +#### Компонент для отображения стратегии + +```javascript +import React, { useState, useEffect } from 'react'; + +function StrategyView({ analysisId }) { + const [strategy, setStrategy] = useState(null); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + + useEffect(() => { + async function loadStrategy() { + try { + // Сначала пытаемся получить существующую стратегию + let response = await fetch( + `/api/marketing/analysis/${analysisId}/strategy` + ); + let result = await response.json(); + + if (result.success && result.data.status === 'completed') { + setStrategy(result.data); + setLoading(false); + return; + } + + // Если стратегии нет или она еще обрабатывается, запускаем генерацию + if (!result.success || result.data.status === 'processing') { + // Запускаем генерацию + response = await fetch( + `/api/marketing/strategy/generate?analysisId=${analysisId}`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + durationWeeks: 4, + priorityPlatforms: ['Instagram', 'LinkedIn', 'Telegram'], + }), + } + ); + result = await response.json(); + + if (result.success) { + // Polling для получения результата + pollStrategy(result.data.strategyId); + } else { + setError(result.error.message); + setLoading(false); + } + } + } catch (err) { + setError(err.message); + setLoading(false); + } + } + + async function pollStrategy(strategyId) { + const maxAttempts = 60; + let attempts = 0; + + const interval = setInterval(async () => { + attempts++; + try { + const response = await fetch(`/api/marketing/strategy/${strategyId}`); + const result = await response.json(); + + if (result.success) { + if (result.data.status === 'completed') { + setStrategy(result.data); + setLoading(false); + clearInterval(interval); + } else if (result.data.status === 'failed') { + setError('Strategy generation failed'); + setLoading(false); + clearInterval(interval); + } + } + + if (attempts >= maxAttempts) { + setError('Strategy generation timeout'); + setLoading(false); + clearInterval(interval); + } + } catch (err) { + setError(err.message); + setLoading(false); + clearInterval(interval); + } + }, 10000); // Проверяем каждые 10 секунд + } + + if (analysisId) { + loadStrategy(); + } + }, [analysisId]); + + if (loading) { + return
Генерация стратегии...
; + } + + if (error) { + return
Ошибка: {error}
; + } + + if (!strategy || !strategy.strategy) { + return
Стратегия не найдена
; + } + + return ( +
+

Стратегия продвижения

+ + {/* Недельный план */} +
+

Недельный план

+ {strategy.strategy.weeklyPlans.map((plan) => ( +
+

Неделя {plan.weekNumber}

+
+ Темы: +
    + {plan.mainThemes.map((theme, idx) => ( +
  • {theme}
  • + ))} +
+
+
+ Рекомендации: +

{plan.contentRecommendations}

+
+
+ Платформы: + {plan.priorityPlatforms.join(', ')} +
+
+ ))} +
+ + {/* Календарь постов */} +
+

Календарь постов

+
+ {strategy.strategy.postCalendar.map((post, idx) => ( +
+
+ + {new Date(post.publishDate).toLocaleDateString('ru-RU')} + + {post.publishTime} + {post.platform} + {post.contentType} +
+
+ Тема: {post.theme} +
+
{post.postText}
+
+ {post.hashtags.map((tag, tagIdx) => ( + + {tag} + + ))} +
+
+ ))} +
+
+
+ ); +} + +export default StrategyView; +``` + +#### Компонент для отображения календаря постов + +```javascript +import React from 'react'; + +function PostCalendar({ postCalendar }) { + // Группируем посты по датам + const postsByDate = postCalendar.reduce((acc, post) => { + const date = new Date(post.publishDate).toLocaleDateString('ru-RU'); + if (!acc[date]) { + acc[date] = []; + } + acc[date].push(post); + return acc; + }, {}); + + return ( +
+

Календарь публикаций

+ {Object.entries(postsByDate).map(([date, posts]) => ( +
+

{date}

+ {posts.map((post, idx) => ( +
+
+ {post.platform} + {post.contentType} + {post.publishTime} +
+
+
{post.theme}
+

{post.postText}

+
+ {post.hashtags.map((tag, tagIdx) => ( + + {tag} + + ))} +
+
+
+ ))} +
+ ))} +
+ ); +} + +export default PostCalendar; +``` + +### Vue.js примеры + +```javascript +// composable для работы со стратегией +export function useMarketingStrategy() { + const baseUrl = ''; + + const generateStrategy = async (analysisId, options = {}) => { + const params = new URLSearchParams(); + params.append('analysisId', analysisId); + + const response = await fetch( + `${baseUrl}/api/marketing/strategy/generate?${params}`, + { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ + durationWeeks: options.durationWeeks || 4, + priorityPlatforms: options.priorityPlatforms || [], + }), + } + ); + + const result = await response.json(); + if (!result.success) { + throw new Error(result.error.message); + } + + return result.data; + }; + + const getStrategy = async (strategyId) => { + const response = await fetch( + `${baseUrl}/api/marketing/strategy/${strategyId}` + ); + const result = await response.json(); + if (!result.success) { + throw new Error(result.error.message); + } + return result.data; + }; + + const getStrategyByAnalysis = async (analysisId) => { + const response = await fetch( + `${baseUrl}/api/marketing/analysis/${analysisId}/strategy` + ); + const result = await response.json(); + if (!result.success) { + throw new Error(result.error.message); + } + return result.data; + }; + + return { + generateStrategy, + getStrategy, + getStrategyByAnalysis, + }; +} +``` + +--- + +## Рекомендации по интеграции + +### 1. Polling стратегия + +Рекомендуется проверять статус стратегии каждые 10-15 секунд. Максимальное время ожидания - 5-7 минут. + +### 2. Обработка ошибок + +Всегда проверяйте поле `success` в ответе и обрабатывайте ошибки соответствующим образом. Особое внимание уделите случаям, когда анализ еще не завершен. + +### 3. Валидация на клиенте + +Перед отправкой запроса рекомендуется валидировать данные на клиенте: + +- Проверка наличия `analysisId` +- Проверка диапазона `durationWeeks` (1-12) +- Проверка формата массива `priorityPlatforms` + +### 4. UX рекомендации + +- Показывайте индикатор загрузки во время генерации стратегии +- Отображайте примерное время завершения (3-5 минут) +- Предоставьте возможность отменить ожидание и проверить результат позже +- Сохраняйте `strategyId` для последующей проверки статуса +- Отображайте календарь постов в удобном формате (календарь, список, таблица) +- Позвольте пользователю копировать текст постов и хештеги + +### 5. Кэширование + +После получения результатов можно кэшировать их локально, используя `strategyId` или `analysisId` как ключ. + +### 6. Экспорт данных + +Рассмотрите возможность экспорта стратегии в различных форматах: + +- CSV для календаря постов +- PDF для полной стратегии +- iCal для импорта в календарные приложения + +--- + +## Примечания + +1. **Формат даты**: Все даты возвращаются в формате ISO 8601 без timezone (LocalDateTime) +2. **Идентификаторы**: Используются MongoDB ObjectId (24 символа hex) +3. **Асинхронность**: Генерация стратегии выполняется асинхронно, не блокируя запрос +4. **Таймауты**: Рекомендуется устанавливать таймаут на запросы (минимум 30 секунд для запуска генерации) +5. **Зависимость от анализа**: Стратегия может быть сгенерирована только для завершенного анализа +6. **Повторная генерация**: Если стратегия уже существует для анализа, возвращается существующая стратегия +7. **Платформы**: Поддерживаются все популярные платформы: Instagram, Facebook, LinkedIn, Telegram, TikTok, YouTube, 21MC и другие + +--- + +## Поддержка + +При возникновении проблем с API обращайтесь в техническую поддержку с указанием: + +- `strategyId` (если есть) +- `analysisId` +- Время запроса +- Описание проблемы +- Код ошибки (если есть) diff --git a/package-lock.json b/package-lock.json index 65756f7..878fd2b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@primeuix/themes": "^1.0.0", "chart.js": "3.3.2", + "marked": "^17.0.1", "primeicons": "^7.0.0", "primevue": "^4.3.1", "tailwindcss-primeui": "^0.5.0", @@ -2361,6 +2362,18 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/marked": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/marked/-/marked-17.0.1.tgz", + "integrity": "sha512-boeBdiS0ghpWcSwoNm/jJBwdpFaMnZWRzjA6SkUMYb40SVaN1x7mmfGKp0jvexGcx+7y2La5zRZsYFZI6Qpypg==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", diff --git a/package.json b/package.json index 0118fda..86e982d 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "dependencies": { "@primeuix/themes": "^1.0.0", "chart.js": "3.3.2", + "marked": "^17.0.1", "primeicons": "^7.0.0", "primevue": "^4.3.1", "tailwindcss-primeui": "^0.5.0", diff --git a/src/config/api.js b/src/config/api.js index fdd5bec..40adb0f 100644 --- a/src/config/api.js +++ b/src/config/api.js @@ -48,7 +48,17 @@ export const API_CONFIG = { PUBLISHING_POST: '/publishing/post', // AnalyticsController - Аналитика - ANALYTICS_COLLECT: '/analytics/collect-now' + ANALYTICS_COLLECT: '/analytics/collect-now', + + // MarketingAnalysisController - Маркетинговый анализ + MARKETING_ANALYSIS_START: '/api/marketing/analysis/start', + MARKETING_ANALYSIS_GET: '/api/marketing/analysis', + MARKETING_ANALYSIS_DOWNLOAD: '/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' } }; diff --git a/src/router/index.js b/src/router/index.js index 2f7d25e..8a4e284 100644 --- a/src/router/index.js +++ b/src/router/index.js @@ -223,6 +223,26 @@ const router = createRouter({ name: 'landing', component: () => import('@/views/pages/Landing.vue') }, + { + path: '/marketing-analysis', + name: 'marketing-main', + component: () => import('@/views/pages/marketing/MarketingMain.vue') + }, + { + path: '/marketing-analysis/analysis', + name: 'marketing-analysis', + component: () => import('@/views/pages/marketing/MarketingAnalysis.vue') + }, + { + path: '/marketing-analysis/promotion', + name: 'marketing-promotion', + component: () => import('@/views/pages/marketing/MarketingPromotion.vue') + }, + { + path: '/marketing-analysis/results', + name: 'marketing-results', + component: () => import('@/views/pages/marketing/MarketingResults.vue') + }, { path: '/pages/notfound', name: 'notfound', diff --git a/src/service/MarketingService.js b/src/service/MarketingService.js new file mode 100644 index 0000000..4443b14 --- /dev/null +++ b/src/service/MarketingService.js @@ -0,0 +1,217 @@ +import { API_CONFIG, DEFAULT_REQUEST_CONFIG } from '@/config/api'; +import AuthService from './AuthService'; + +const API_BASE_URL = API_CONFIG.BASE_URL; + +class MarketingService { + /** + * Запуск маркетингового анализа + * POST /api/marketing/analysis/start + * @param {Object} data - Данные для анализа + * @param {string} data.product - Название продукта или услуги + * @param {string} data.location - Географическая локация работы + * @param {string} data.client - Тип целевой аудитории + * @param {string} data.differentiator - Уникальные особенности бизнеса + * @returns {Promise} Объект с analysisId и статусом + */ + async startAnalysis(data) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_ANALYSIS_START}`, { + method: 'POST', + ...DEFAULT_REQUEST_CONFIG, + body: JSON.stringify({ + product: data.product, + location: data.location, + client: data.client, + differentiator: data.differentiator + }) + }); + + 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} + * @param {string} analysisId - Идентификатор анализа + * @returns {Promise} Объект с статусом и результатами анализа + */ + async getAnalysisResult(analysisId) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_ANALYSIS_GET}/${analysisId}`); + + 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 + * @param {string} analysisId - Идентификатор анализа + * @returns {Promise} Blob с PDF файлом + */ + async downloadPdf(analysisId) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_ANALYSIS_DOWNLOAD}/${analysisId}/download`); + + if (!response.ok) { + const errorData = await response.json().catch(() => ({})); + throw new Error(errorData.message || errorData.error?.message || 'Ошибка при скачивании PDF'); + } + + return await response.blob(); + } catch (error) { + console.error('Ошибка при скачивании PDF:', error); + throw error; + } + } + + /** + * Вспомогательный метод для скачивания PDF в браузере + * @param {string} analysisId - Идентификатор анализа + */ + async downloadPdfFile(analysisId) { + try { + const blob = await this.downloadPdf(analysisId); + const url = window.URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = `marketing_analysis_${analysisId}.pdf`; + document.body.appendChild(a); + a.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(a); + } catch (error) { + console.error('Ошибка при скачивании PDF файла:', error); + throw error; + } + } + + /** + * Запуск генерации стратегии продвижения + * POST /api/marketing/strategy/generate?analysisId={analysisId} + * @param {string} analysisId - ID завершенного маркетингового анализа + * @param {Object} options - Опции генерации стратегии + * @param {number} options.durationWeeks - Длительность стратегии в неделях (1-12) + * @param {string[]} options.priorityPlatforms - Приоритетные платформы для продвижения + * @returns {Promise} Объект с strategyId и статусом + */ + async generateStrategy(analysisId, options = {}) { + try { + const params = new URLSearchParams(); + params.append('analysisId', analysisId); + + const body = {}; + if (options.durationWeeks) { + body.durationWeeks = options.durationWeeks; + } + if (options.priorityPlatforms && options.priorityPlatforms.length > 0) { + body.priorityPlatforms = options.priorityPlatforms; + } + + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_STRATEGY_GENERATE}?${params}`, { + method: 'POST', + ...DEFAULT_REQUEST_CONFIG, + body: Object.keys(body).length > 0 ? JSON.stringify(body) : undefined + }); + + 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; + } + } + + /** + * Получение стратегии по ID + * GET /api/marketing/strategy/{strategyId} + * @param {string} strategyId - Идентификатор стратегии + * @returns {Promise} Объект с статусом и результатами стратегии + */ + async getStrategy(strategyId) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_STRATEGY_GET}/${strategyId}`); + + 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; + } + } + + /** + * Получение стратегии по ID анализа + * GET /api/marketing/analysis/{analysisId}/strategy + * @param {string} analysisId - Идентификатор анализа + * @returns {Promise} Объект с статусом и результатами стратегии + */ + async getStrategyByAnalysis(analysisId) { + try { + const response = await AuthService.authFetch(`${API_BASE_URL}${API_CONFIG.ENDPOINTS.MARKETING_STRATEGY_BY_ANALYSIS}/${analysisId}/strategy`); + + 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/MarketingAnalysis.vue b/src/views/pages/marketing/MarketingAnalysis.vue new file mode 100644 index 0000000..320806e --- /dev/null +++ b/src/views/pages/marketing/MarketingAnalysis.vue @@ -0,0 +1,598 @@ + + + + + diff --git a/src/views/pages/marketing/MarketingMain.vue b/src/views/pages/marketing/MarketingMain.vue new file mode 100644 index 0000000..d414e7c --- /dev/null +++ b/src/views/pages/marketing/MarketingMain.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/src/views/pages/marketing/MarketingPromotion.vue b/src/views/pages/marketing/MarketingPromotion.vue new file mode 100644 index 0000000..b5afec7 --- /dev/null +++ b/src/views/pages/marketing/MarketingPromotion.vue @@ -0,0 +1,583 @@ + + + + + diff --git a/src/views/pages/marketing/MarketingResults.vue b/src/views/pages/marketing/MarketingResults.vue new file mode 100644 index 0000000..4064980 --- /dev/null +++ b/src/views/pages/marketing/MarketingResults.vue @@ -0,0 +1,144 @@ + + + + +