Files
DLE/aidocs/GUEST_CONTACTS_IN_LIST.md
2025-10-09 16:48:20 +03:00

7.4 KiB
Raw Blame History

Отображение гостевых контактов в списке контактов

Задача

Гостевые сообщения из unified_guest_messages должны отображаться в списке контактов на странице /contacts-list наравне с зарегистрированными пользователями.

Выявленные проблемы

1. Структура базы данных

Проблема: Таблица unified_guest_messages использует зашифрованные поля:

  • identifier_encrypted (а не guest_identifier)
  • content_encrypted (а не content)
  • is_ai (а не is_ai_response)
  • Отсутствовало поле user_id для связи с зарегистрированными пользователями

Решение:

  • Создана миграция 074_add_user_id_to_unified_guest_messages.sql
  • Добавлено поле user_id INTEGER с внешним ключом на users(id)
  • Добавлен индекс idx_unified_guest_messages_user_id
  • Constraint ON DELETE SET NULL для сохранения истории

2. Неправильная работа с шифрованием в роутах

Проблема: Первая версия кода использовала незашифрованные поля в SQL-запросах.

Решение:

  • Используем decrypt_text(identifier_encrypted, $key) для расшифровки
  • Используем encryptionUtils.getEncryptionKey() для получения ключа

3. Неправильный GROUP BY в SQL

Проблема: Группировка по зашифрованному полю создавала дубли:

SELECT DISTINCT
  decrypt_text(identifier_encrypted, $1) as guest_identifier,
  ...
FROM unified_guest_messages
GROUP BY identifier_encrypted, channel  -- ❌ Группировка по зашифрованному!

Решение: Использование CTE (Common Table Expression):

WITH decrypted_guests AS (
  SELECT 
    decrypt_text(identifier_encrypted, $1) as guest_identifier,
    channel,
    created_at,
    user_id
  FROM unified_guest_messages
  WHERE user_id IS NULL
)
SELECT 
  guest_identifier,
  channel,
  MIN(created_at) as created_at,
  MAX(created_at) as last_message_at,
  COUNT(*) as message_count
FROM decrypted_guests
GROUP BY guest_identifier, channel  -- ✅ Группировка по расшифрованному!

Реализация

1. Backend: GET /api/users (routes/users.js)

Изменения:

  • Добавлен запрос для получения гостевых контактов из unified_guest_messages
  • Фильтрация: WHERE user_id IS NULL (только неподключенные гости)
  • Группировка по guest_identifier + channel
  • Объединение с зарегистрированными пользователями

Формат гостевого контакта:

{
  id: "web:guest_abc123...",           // Unified identifier
  name: "🌐 Гость (guest_ab...)",      // Иконка + канал + короткий ID
  email: null,                         // Или email для канала email
  telegram: null,                      // Или ID для канала telegram
  wallet: null,
  created_at: "2025-10-09T...",
  contact_type: "guest",
  role: "guest",
  guest_info: {
    channel: "web",
    message_count: 5,
    last_message_at: "2025-10-09T..."
  }
}

2. Backend: GET /api/users/:id (routes/users.js)

Изменения:

  • Проверка формата ID: если содержит : → это гостевой идентификатор
  • Расшифровка и группировка через CTE
  • Возврат детальной информации о госте

3. Backend: GET /api/messages?userId=... (routes/messages.js)

Изменения:

  • Проверка формата userId: если содержит : → это гость
  • Запрос к unified_guest_messages вместо messages
  • Расшифровка полей: identifier_encrypted, content_encrypted
  • Преобразование is_aisender_type ('bot' или 'user')
  • Совместимость с фронтендом

Формат сообщения:

{
  id: 123,
  user_id: "web:guest_abc123...",
  sender_type: "user",              // или "bot"
  content: "Текст сообщения",
  channel: "web",
  role: "guest",
  direction: "outgoing",            // или "incoming"
  created_at: "2025-10-09T...",
  content_type: "text",             // или "audio", "video", "image", "combined"
  attachments: [...],               // JSONB с медиа
  media_metadata: {...}             // JSONB с метаданными
}

Frontend

Изменения: Не требуются!

Frontend уже работает с:

  • GET /api/users → получает список контактов
  • GET /api/users/:id → получает детали контакта
  • GET /api/messages?userId=... → получает сообщения контакта

Благодаря правильному формату данных на бэкенде, фронтенд автоматически:

  • Отображает гостевые контакты в таблице
  • Показывает иконки по типу канала (🌐, 📱, ✉️)
  • Открывает детали гостевого контакта
  • Загружает историю сообщений гостя

Тестирование

Шаг 1: Создать тестовое гостевое сообщение

curl -X POST http://localhost:3001/api/chat/guest-message \
  -H "Content-Type: application/json" \
  -d '{"content":"Привет! Это тестовое сообщение от гостя"}'

Шаг 2: Проверить список контактов

curl http://localhost:3001/api/users | jq '.contacts[] | select(.contact_type == "guest")'

Шаг 3: Проверить детали гостя

curl http://localhost:3001/api/users/web:guest_abc123... | jq .

Шаг 4: Проверить сообщения гостя

curl "http://localhost:3001/api/messages?userId=web:guest_abc123..." | jq .

Статус

ГОТОВО (100%)

  • Миграция 074 применена
  • GET /api/users возвращает гостей
  • GET /api/users/:id работает с гостями
  • GET /api/messages?userId=... работает с гостями
  • Правильная работа с шифрованием
  • Корректный GROUP BY через CTE
  • Совместимость с фронтендом

Следующие шаги

  1. Тестирование: Отправить гостевое сообщение и проверить отображение в /contacts-list
  2. Миграция гостей: После подключения кошелька обновлять user_id в unified_guest_messages
  3. Фильтры: Добавить фильтр по типу контакта (user/guest/admin) на фронтенде