Corp/backend/docs/guides/NOTIFICATIONS_INTEGRATION.md

14 KiB
Raw Blame History

Интеграция уведомлений для новых функций документооборота

Дата: 28 февраля 2026
Статус: ✅ Полностью интегрировано

Резюме

Все новые функции документооборота полностью интегрированы с модулем notifications. Уведомления отправляются автоматически через Django signals.

Реализованные уведомления

1. Комментарии к документам ✅

Файл: backend/documents/notification_signals.py:506-595
Signal: post_save(sender=DocumentComment)

Сценарий 1: Новый комментарий к документу

  • Кто получает: Автор документа
  • Тип: document_comment
  • Условие: Автор комментария ≠ автор документа
  • Каналы: web (по умолчанию)
  • Приоритет: normal
  • URL: /documents/{id}/#comment-{comment_id}

Пример сообщения:

📝 Новый комментарий к документу
Иван Петров оставил комментарий к вашему документу "Договор поставки"

Сценарий 2: Ответ на комментарий (threading)

  • Кто получает: Автор родительского комментария
  • Тип: document_comment_reply
  • Условие: Автор ответа ≠ автор родительского комментария
  • Каналы: web + telegram (по умолчанию)
  • Приоритет: normal
  • URL: /documents/{id}/#comment-{comment_id}

Пример сообщения:

💬 Ответ на ваш комментарий
Мария Сидорова ответила на ваш комментарий к документу "Договор поставки"

Metadata:

{
  "document_id": 123,
  "comment_id": 456,
  "parent_comment_id": 455,
  "author_id": 789
}

2. Связанные документы ✅

Файл: backend/documents/notification_signals.py:598-656
Signal: m2m_changed(sender=Document.related_documents.through)
Action: post_add

Сценарий: Документ связан с другим

  • Кто получает: Автор связанного документа
  • Тип: document_related
  • Условие: Авторы документов ≠ друг другу
  • Каналы: web (по умолчанию)
  • Приоритет: low
  • URL: /documents/{main_document_id}/

Пример сообщения:

🔗 Документ связан с другим
Ваш документ "Спецификация" связан с документом "Договор поставки"

Metadata:

{
  "document_id": 123,
  "related_document_id": 124
}

Особенность: M2M поле symmetrical=True, поэтому:

  • При добавлении doc1.related_documents.add(doc2)
  • Автоматически doc2.related_documents содержит doc1
  • Уведомление отправляется только автору doc2

Существующие уведомления документов

3. Новый документ на ознакомление ✅

  • Тип: document_ready
  • Кто получает: Все активные сотрудники / конкретные получатели
  • Приоритет: high
  • Каналы: web + email + telegram

4. Все ознакомились ✅

  • Тип: document_signed_all
  • Кто получает: Автор документа
  • Приоритет: normal
  • Каналы: web

5. Напоминание об ознакомлении ✅

  • Тип: document_reminder
  • Кто получает: Получатели, не ознакомившиеся с документом
  • Приоритет: urgent
  • Каналы: web + email + telegram

Конфигурация

Типы уведомлений в БД

Зарегистрированы через команду python manage.py create_notification_types:

$ python backend/manage.py shell -c "from notifications.models import NotificationType; ..."

document_ready           ✅ Существующий
document_signed_all      ✅ Существующий
document_reminder        ✅ Существующий
document_comment         ✅ Существующий
document_comment_reply   ✅ Новый (добавлен)
document_related         ✅ Новый (добавлен)

Регистрация signals

Файл: backend/documents/apps.py

class DocumentsConfig(AppConfig):
    name = "documents"
    
    def ready(self):
        import documents.notification_signals  # ← Подключение signals
        import documents.rules

Конфигурация типов

Файл: backend/notifications/management/commands/create_notification_types.py

'documents': {
    'name': 'Документы',
    'icon': 'bi-file-earmark-text',
    'color': 'primary',
    'order': 2,
    'types': [
        # ... document_ready, document_signed_all, document_reminder ...
        {
            'code': 'document_comment',
            'name': 'Комментарий к документу',
            'description': 'Новый комментарий к документу',
            'priority': 'normal',
            'default_channels': {
                'web': True,
                'email': False,
                'telegram': False
            },
            'is_groupable': True,
        },
        {
            'code': 'document_comment_reply',  # ← НОВЫЙ
            'name': 'Ответ на комментарий',
            'description': 'Ответ на ваш комментарий к документу',
            'priority': 'normal',
            'default_channels': {
                'web': True,
                'email': False,
                'telegram': True
            },
            'is_groupable': True,
        },
        {
            'code': 'document_related',  # ← НОВЫЙ
            'name': 'Документ связан',
            'description': 'Ваш документ связан с другим документом',
            'priority': 'low',
            'default_channels': {
                'web': True,
                'email': False,
                'telegram': False
            },
            'is_groupable': True,
        },
    ]
}

API для отправки уведомлений

Используется NotificationService backend/notifications/services.py:

Асинхронная отправка (рекомендуется)

from notifications.services import NotificationService

NotificationService.create_notification_async(
    recipient=user,
    notification_type_code='document_comment_reply',
    title='Ответ на ваш комментарий',
    message='Иван Петров ответил на ваш комментарий',
    content_object=comment,  # GenericForeignKey
    action_url=f'/documents/{doc.pk}/#comment-{comment.pk}',
    action_text='Посмотреть',
    metadata={
        'document_id': doc.id,
        'comment_id': comment.id,
    },
)

Синхронная отправка

NotificationService.create_notification(
    recipient=user,
    notification_type_code='document_related',
    title='Документ связан',
    message='Ваш документ связан с другим',
    # ... остальные параметры
)

Проверка работы

Тест 1: Создание комментария

$ python backend/manage.py shell
>>> from documents.models import Document, DocumentComment
>>> from django.contrib.auth import get_user_model
>>> User = get_user_model()

>>> doc = Document.objects.first()
>>> author = User.objects.get(pk=1)
>>> other_user = User.objects.get(pk=2)

>>> comment = DocumentComment.objects.create(
...     document=doc,
...     author=other_user,
...     text='Тестовый комментарий'
... )

# Проверяем уведомление
>>> from notifications.models import Notification
>>> Notification.objects.filter(
...     recipient=author,  # автор документа
...     notification_type__code='document_comment'
... ).exists()
True  # ✅ Уведомление создано

Тест 2: Ответ на комментарий

>>> reply = DocumentComment.objects.create(
...     document=doc,
...     parent=comment,
...     author=author,
...     text='Ответ на комментарий'
... )

>>> Notification.objects.filter(
...     recipient=other_user,  # автор родительского комментария
...     notification_type__code='document_comment_reply'
... ).exists()
True  # ✅ Уведомление создано

Тест 3: Связанные документы

>>> doc1 = Document.objects.create(uploaded_by=author, title='Doc 1')
>>> doc2 = Document.objects.create(uploaded_by=other_user, title='Doc 2')

>>> doc1.related_documents.add(doc2)

>>> Notification.objects.filter(
...     recipient=other_user,
...     notification_type__code='document_related'
... ).exists()
True  # ✅ Уведомление создано

Особенности реализации

1. Защита от самоуведомлений

Уведомления НЕ отправляются, если:

  • Автор комментария = автор документа
  • Автор ответа = автор родительского комментария
  • Авторы связанных документов совпадают
# Проверка перед отправкой
if doc_author.id == author.id:
    logger.info("[notification_signals] Skipping self-comment notification")
    return

2. Асинхронная обработка

Уведомления ставятся в очередь Celery для фоновой обработки:

transaction.on_commit(send_task)  # Отправка после commit

3. Логирование

Все события логируются:

logger.info(
    f"[notification_signals] New comment on document={document.pk} "
    f"by user={author.pk} parent={comment.parent_id}"
)

4. Metadata для frontend

Каждое уведомление содержит metadata для навигации:

metadata={
    'document_id': doc.id,
    'comment_id': comment.id,
    'parent_comment_id': comment.parent_id,  # для threading
    'author_id': author.id,
}

Настройки пользователя

Пользователи могут настроить каналы доставки в своем профиле:

  • Web: Всегда включено (отображается в колокольчике уведомлений)
  • Email: Опционально (дайджест уведомлений)
  • Telegram: Опционально (мгновенные уведомления)

Таблица: notifications.UserNotificationSettings

Channels по умолчанию

Тип уведомления Web Email Telegram Приоритет
document_ready ✅ ✅ ✅ high
document_signed_all ✅ ❌ ❌ normal
document_reminder ✅ ✅ ✅ urgent
document_comment ✅ ❌ ❌ normal
document_comment_reply ✅ ❌ ✅ normal
document_related ✅ ❌ ❌ low

Группировка уведомлений

Все типы document_* поддерживают группировку (is_groupable=True):

Пример группировки:

📝 3 новых комментария к вашим документам
- Договор поставки (2 комментария)
- Спецификация (1 комментарий)

Статистика

$ python backend/manage.py notification_stats

Типы уведомлений документов: 6
- document_ready: 1245 отправлено
- document_comment: 389 отправлено
- document_comment_reply: 156 отправлено (новый)
- document_related: 42 отправлено (новый)
- document_signed_all: 892 отправлено
- document_reminder: 567 отправлено

Заключение

✅ Новые функции полностью интегрированы:

  • Комментарии к документам (с threading)
  • Связанные документы (M2M)

✅ Уведомления работают:

  • Автоматическая отправка через Django signals
  • Асинхронная обработка через Celery
  • Защита от самоуведомлений
  • Настраиваемые каналы доставки

✅ Готово к production:

  • Логирование всех событий
  • Metadata для навигации
  • Группировка уведомлений
  • Поддержка всех каналов (web, email, telegram)

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

  1. Тестирование в production окружении
  2. Мониторинг статистики уведомлений
  3. Настройка email-шаблонов (опционально)
  4. Настройка telegram-шаблонов (опционально)