> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lovi.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Лучшие Практики и Руководства

> Рекомендации по безопасности, оптимизации производительности и интеграции с API Lovi

## Введение

Этот гид охватывает рекомендации по безопасности, оптимизацию производительности и руководства по интеграции, помогающие создавать надежные приложения с API Lovi.

***

## 🔒 Лучшие Практики Безопасности

### Управление API-Ключами

**✅ ДЕЛАТЬ:**

* Хранить API-ключи в переменных окружения или безопасных системах управления конфигурацией
* Использовать разные API-ключи для разных сред (разработка, staging, производство)
* Регулярно обновлять API-ключи (рекомендуется каждые 90 дней)
* Мониторить использование API-ключей и настраивать оповещения о необычной активности
* Использовать принцип наименьших привилегий (отдельные ключи для разных функций, если доступно)

**❌ НЕ ДЕЛАТЬ:**

* Хардкодить API-ключи в исходном коде или коммитить в систему контроля версий
* Передавать API-ключи по email, чату или другим незащищенным каналам
* Использовать ключи производства в среде разработки
* Логировать полные API-ключи в журналах приложений

### Безопасность Аутентификации

```javascript theme={null}
// ✅ Хорошо - Хранить в переменных окружения
const ACCESS_KEY = process.env.LOVI_ACCESS_KEY;

// ❌ Плохо - Хардкодировано в исходном коде
const ACCESS_KEY = 'your-actual-api-key-here';
```

### Безопасность Запросов

**Всегда использовать HTTPS:**

```javascript theme={null}
// ✅ Хорошо - Только HTTPS
const BASE_URL = 'https://cloud.lovi.ai';

// ❌ Плохо - Незащищенный HTTP
const BASE_URL = 'http://cloud.lovi.ai';
```

**Валидировать входные данные:**

```javascript theme={null}
function validatePhoneNumber(number) {
  // Удалить все нецифровые символы
  const cleaned = number.replace(/\D/g, '');

  // Проверить, является ли это допустимым международным форматом
  if (!/^\d{10,15}$/.test(cleaned)) {
    throw new Error('Недопустимый формат номера телефона');
  }

  return cleaned;
}
```

***

## ⚡ Оптимизация Производительности

### Управление Соединениями

**Повторно использовать HTTP-соединения:**

```javascript theme={null}
// ✅ Хорошо - Повторно использовать пул соединений
const https = require('https');
const agent = new https.Agent({
  keepAlive: true,
  maxSockets: 10
});

const fetch = require('node-fetch');

async function makeRequest(url, data) {
  return fetch(url, {
    method: 'POST',
    agent: agent,
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data)
  });
}
```

### Пакетная Обработка

**Обрабатывать уведомления пакетами:**

```javascript theme={null}
async function sendNotificationsBatch(notifications, batchSize = 10) {
  const results = [];

  for (let i = 0; i < notifications.length; i += batchSize) {
    const batch = notifications.slice(i, i + batchSize);
    const batchPromises = batch.map(notification =>
      sendNotification(notification)
    );

    const batchResults = await Promise.allSettled(batchPromises);
    results.push(...batchResults);

    // Ограничение скорости: ждать между пакетами
    if (i + batchSize < notifications.length) {
      await sleep(100); // 100ms задержка
    }
  }

  return results;
}
```

### Стратегии Кеширования

**Кешировать информацию о шаблонах:**

```javascript theme={null}
class TemplateCache {
  constructor(ttl = 3600000) { // 1 час TTL
    this.cache = new Map();
    this.ttl = ttl;
  }

  async getTemplate(templateName) {
    const cached = this.cache.get(templateName);

    if (cached && Date.now() - cached.timestamp < this.ttl) {
      return cached.data;
    }

    const template = await fetchTemplateFromAPI(templateName);
    this.cache.set(templateName, {
      data: template,
      timestamp: Date.now()
    });

    return template;
  }
}
```

***

## 📊 Ограничение Скорости и Регулировка

### Понимание Ограничений Скорости

| Операция           | Лимит        | Окно     |
| ------------------ | ------------ | -------- |
| Аутентификация     | 10 запросов  | 1 минута |
| Уведомления        | 100 запросов | 1 минута |
| Получение шаблонов | 50 запросов  | 1 минута |
| Создание шаблонов  | 5 запросов   | 1 час    |

### Обработка Ограничений Скорости

```javascript theme={null}
class RateLimitHandler {
  constructor() {
    this.requestQueue = [];
    this.processing = false;
  }

  async makeRequest(url, data) {
    return new Promise((resolve, reject) => {
      this.requestQueue.push({ url, data, resolve, reject });
      this.processQueue();
    });
  }

  async processQueue() {
    if (this.processing || this.requestQueue.length === 0) return;

    this.processing = true;

    while (this.requestQueue.length > 0) {
      const request = this.requestQueue.shift();

      try {
        const response = await this.executeRequest(request);
        request.resolve(response);
      } catch (error) {
        if (error.status === 429) {
          // Ограничение скорости - вернуть запрос и ждать
          this.requestQueue.unshift(request);
          await sleep(error.retryAfter * 1000);
          continue;
        }
        request.reject(error);
      }

      // Небольшая задержка между запросами
      await sleep(100);
    }

    this.processing = false;
  }
}
```

***

## 🏗️ Архитектурные Паттерны

### Паттерн Репозитория

```javascript theme={null}
class NotificationRepository {
  constructor(apiClient) {
    this.apiClient = apiClient;
  }

  async sendWhatsAppNotification(notification) {
    const payload = this.formatWhatsAppPayload(notification);
    return await this.apiClient.post('/notify', payload);
  }

  async sendVoiceNotification(notification) {
    const payload = this.formatVoicePayload(notification);
    return await this.apiClient.post('/notify/voice', payload);
  }

  formatWhatsAppPayload(notification) {
    return {
      contact: {
        number: this.validatePhoneNumber(notification.phoneNumber),
        name: notification.contactName
      },
      language_template: notification.language,
      name_template: notification.templateName,
      recipient_id: notification.phoneNumber,
      notification_type: notification.type,
      campaign_name: notification.campaign
    };
  }
}
```

***

## 🧪 Стратегии Тестирования

### Модульное Тестирование

```javascript theme={null}
// Мокировать ответы API для тестирования
const mockAPIClient = {
  post: jest.fn()
};

describe('NotificationService', () => {
  test('должен успешно отправить WhatsApp-уведомление', async () => {
    mockAPIClient.post.mockResolvedValue({
      success: true,
      notification_id: 'test-123'
    });

    const service = new NotificationService(mockAPIClient);
    const result = await service.sendWhatsApp({
      phoneNumber: '34666033135',
      templateName: 'welcome',
      contactName: 'John Doe'
    });

    expect(result.success).toBe(true);
    expect(mockAPIClient.post).toHaveBeenCalledWith('/notify', expect.any(Object));
  });
});
```

***

## 🔍 Мониторинг и Логирование

### Структурированное Логирование

```javascript theme={null}
const logger = require('winston');

logger.configure({
  format: logger.format.combine(
    logger.format.timestamp(),
    logger.format.errors({ stack: true }),
    logger.format.json()
  ),
  transports: [
    new logger.transports.File({ filename: 'api-calls.log' })
  ]
});

async function loggedAPICall(endpoint, data) {
  const requestId = generateRequestId();

  logger.info('API-запрос запущен', {
    request_id: requestId,
    endpoint: endpoint,
    method: 'POST',
    timestamp: new Date().toISOString()
  });

  try {
    const response = await makeAPICall(endpoint, data);

    logger.info('API-запрос завершен', {
      request_id: requestId,
      endpoint: endpoint,
      status_code: response.status,
      success: true,
      duration: Date.now() - startTime
    });

    return response;
  } catch (error) {
    logger.error('API-запрос не удался', {
      request_id: requestId,
      endpoint: endpoint,
      error: error.message,
      status_code: error.statusCode,
      duration: Date.now() - startTime
    });

    throw error;
  }
}
```

***

## 📱 Интеграция Мобильных и Фронтенд

### Пример React Hook

```javascript theme={null}
import { useState, useEffect } from 'react';

function useLoviNotification() {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);

  const sendNotification = async (notificationData) => {
    setLoading(true);
    setError(null);

    try {
      const response = await fetch('/api/send-notification', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(notificationData)
      });

      if (!response.ok) {
        throw new Error('Не удалось отправить уведомление');
      }

      const result = await response.json();
      return result;
    } catch (err) {
        setError(err.message);
        throw err;
      } finally {
        setLoading(false);
      }
    };

    return { sendNotification, loading, error };
}
```

***

## 🔧 Управление Конфигурацией

### Конфигурация Окружения

```javascript theme={null}
// config/lovi.js
module.exports = {
  development: {
    baseURL: 'https://cloud.lovi.ai',
    accessKey: process.env.LOVI_DEV_ACCESS_KEY,
    rateLimits: {
      requests: 10,
      window: 60000 // 1 минута
    },
    retries: 3,
    timeout: 30000
  },
  production: {
    baseURL: 'https://cloud.lovi.ai',
    accessKey: process.env.LOVI_PROD_ACCESS_KEY,
    rateLimits: {
      requests: 100,
      window: 60000
    },
    retries: 5,
    timeout: 60000
  }
};
```

***

## 📚 Документация и Руководства Команды

### Документация Кода

```javascript theme={null}
/**
 * Отправить WhatsApp-уведомление с использованием шаблона
 *
 * @param {Object} notification - Данные уведомления
 * @param {string} notification.phoneNumber - Номер телефона получателя (международный формат, без +)
 * @param {string} notification.templateName - Название утвержденного шаблона
 * @param {string} notification.language - Код языка (например, 'ru_RU', 'en_US')
 * @param {Object} notification.variables - Переменные шаблона
 * @param {string} [notification.scheduledTime] - ISO 8601 дата/время для планирования
 * @param {string} [notification.timezone] - IANA код часового пояса
 *
 * @returns {Promise<Object>} Ответ API с notification_id
 *
 * @throws {ValidationError} Когда отсутствуют обязательные параметры
 * @throws {APIError} Когда вызов API не удался
 *
 * @example
 * const result = await sendWhatsAppNotification({
 *   phoneNumber: '34666033135',
 *   templateName: 'welcome_user',
 *   language: 'ru_RU',
 *   variables: { name: 'Иван', course: 'JavaScript' }
 * });
 */
async function sendWhatsAppNotification(notification) {
  // Реализация...
}
```

### Стандарты Команды

**Чек-лист Интеграции API:**

* ✅ Реализовать правильную обработку ошибок
* ✅ Добавить логирование запросов/ответов
* ✅ Включить модульные тесты
* ✅ Валидировать входные параметры
* ✅ Обработать ограничение скорости
* ✅ Использовать конфигурации специфичные для окружения
* ✅ Документировать все функции и классы
* ✅ Реализовать проверки здоровья
* ✅ Добавить мониторинг и оповещения

***

## 🚨 Распространенные Ошибки и Решения

### Ошибка: Жестко Закодированные Значения

```javascript theme={null}
// ❌ Плохо
const templateName = 'welcome_template_final_v2';

// ✅ Хорошо
const templateName = config.templates.welcome;
```

### Ошибка: Плохая Обработка Ошибок

```javascript theme={null}
// ❌ Плохо
try {
  await sendNotification(data);
} catch (error) {
  console.log('Error:', error);
}

// ✅ Хорошо
try {
  await sendNotification(data);
} catch (error) {
  logger.error('Отправка уведомления не удалась', {
    error: error.message,
    data: sanitizeForLog(data),
    stack: error.stack
  });

  throw new NotificationError(
    'Не удалось отправить уведомление',
    error.statusCode,
    error.requestId
  );
}
```

### Ошибка: Игнорирование Ограничений Скорости

```javascript theme={null}
// ❌ Плохо - Отправить все сразу
notifications.forEach(notification => {
  sendNotification(notification);
});

// ✅ Хорошо - Учитывать ограничения скорости
await sendNotificationsBatch(notifications, 10);
```

Помните: Следование этим лучшим практикам поможет вам создавать более надежные, безопасные и поддерживаемые интеграции с API Lovi.
