Corp/backend/docs/CHAT_MODAL_IMPROVEMENTS.md

10 KiB
Raw Blame History

Улучшения модала создания чатов

Что добавлено

1. Новые типы чатов

  • Чат отдела (department) - автоматически включает всех сотрудников отдела
  • Глобальный чат (global) - для всей компании

2. Новые поля

Аватар чата

  • Загрузка изображения (JPG/PNG/GIF, до 5 МБ)
  • Предпросмотр перед загрузкой
  • Автоматическое сжатие до 512x512px (до 500KB)
  • Удаление старых файлов при замене

Выбор отдела

  • Для типа "Чат отдела"
  • Dropdown со всеми отделами
  • Автодобавление всех сотрудников отдела

Включить всех сотрудников

  • Для типов: announcement, global, channel
  • Автодобавление всех активных сотрудников компании
  • Ограниченная отправка для channel и announcement

Основной чат

  • Для типов: global, department
  • Только 1 основной глобальный чат
  • Только 1 основной чат на отдел
  • Валидация на уровне API

3. Улучшенный UI

Типы чатов с подсказками

Личный: приватный чат с 1 сотрудником
Группа: чат с несколькими участниками
Отдел: автоматически включает всех сотрудников отдела
Канал: для объявлений с ограниченной отправкой
Объявления: односторонняя рассылка
Глобальный: общий чат компании (может быть только 1 основной)

Динамическое переключение полей

  • Private: только выбор участника
  • Group: название + описание + аватар + участники
  • Department: название + описание + аватар + отдел + "основной"
  • Global: название + описание + аватар + "включить всех" + "основной"
  • Channel/Announcement: название + описание + аватар + "включить всех"

4. API изменения

FormData support

// Теперь поддерживает загрузку файлов
const formData = new FormData();
formData.append('type', 'group');
formData.append('name', 'Команда разработки');
formData.append('avatar', file);
formData.append('participant_ids', [1, 2, 3]);

Новые параметры API

  • avatar (file) - файл аватара
  • department_id (int) - ID отдела для type=department
  • include_all_employees (bool) - включить всех сотрудников
  • is_main (bool) - сделать основным чатом

Валидация

  • ✅ Проверка типа чата
  • ✅ Обязательное название (кроме private)
  • ✅ Обязательный отдел для department
  • ✅ Уникальность основного глобального чата
  • ✅ Уникальность основного чата отдела

5. Автоматическое сжатие аватаров

Signal compress_and_cleanup_chat_avatar

@receiver(pre_save, sender='communications.Chat')
def compress_and_cleanup_chat_avatar(sender, instance, **kwargs):
    # 1. Сжимает новый аватар до 512x512px (макс 500KB)
    # 2. Удаляет старый файл при замене
    # 3. Использует LANCZOS для высокого качества

Параметры сжатия

  • Размер: 512x512px (оптимально для отображения)
  • Формат: JPEG (универсальный)
  • Качество: 50-85 (бинарный поиск оптимального)
  • Максимум: 500KB

6. Автодобавление участников

Для include_all_employees=True

# Добавляются все активные сотрудники
all_employees = Employee.objects.filter(is_active=True)

# Права зависят от типа чата:
# - channel/announcement: can_send_messages=False
# - остальные: can_send_messages=True

Для type=department

# Добавляются сотрудники отдела
dept_employees = EmployeeDepartment.objects.filter(
    department=department,
    is_active=True
)

# Все получают can_send_messages=True

Примеры использования

Создать групповой чат с аватаром

const formData = new FormData();
formData.append('type', 'group');
formData.append('name', 'DevOps Team');
formData.append('description', 'Обсуждение инфраструктуры');
formData.append('avatar', avatarFile);
formData.append('participant_ids', 5);
formData.append('participant_ids', 12);
formData.append('participant_ids', 23);

fetch('/communications/api/chat/create/', {
  method: 'POST',
  headers: { 'X-CSRFToken': csrftoken },
  body: formData
});

Создать основной чат отдела

const formData = new FormData();
formData.append('type', 'department');
formData.append('name', 'Отдел разработки');
formData.append('department_id', 3);
formData.append('is_main', 'true');

fetch('/communications/api/chat/create/', {
  method: 'POST',
  headers: { 'X-CSRFToken': csrftoken },
  body: formData
});

Создать канал с аватаром для всех

const formData = new FormData();
formData.append('type', 'channel');
formData.append('name', 'Новости компании');
formData.append('description', 'Официальные объявления');
formData.append('avatar', avatarFile);
formData.append('include_all_employees', 'true');

fetch('/communications/api/chat/create/', {
  method: 'POST',
  headers: { 'X-CSRFToken': csrftoken },
  body: formData
});

Технические детали

Структура модели Chat

class Chat(models.Model):
    type = CharField(choices=[...])
    name = CharField(max_length=255)
    description = TextField()
    avatar = ImageField(upload_to='chat_avatars/%Y/%m/')  # NEW
    created_by = ForeignKey(Employee)
    department = ForeignKey(Department)                   # NEW
    include_all_employees = BooleanField(default=False)   # NEW
    is_main = BooleanField(default=False)                 # NEW
    participants = ManyToManyField(Employee)
    created_at = DateTimeField(auto_now_add=True)

Constraints

# Только 1 основной глобальный чат
UniqueConstraint(
    fields=["type"],
    condition=Q(is_main=True, type="global"),
    name="unique_main_global_chat"
)

# Только 1 основной чат на отдел
UniqueConstraint(
    fields=["type", "department"],
    condition=Q(is_main=True, type="department"),
    name="unique_main_department_chat"
)

Путь хранения аватаров

media/
  chat_avatars/
    2024/
      11/
        chat_avatar_abc123.jpg  (сжато до 512x512, <500KB)

Совместимость

Backward compatibility

  • ✅ Старые чаты без аватаров работают как прежде
  • ✅ API поддерживает JSON (legacy) и FormData (новый)
  • ✅ Все новые поля опциональные (кроме валидируемых случаев)

Frontend

  • Модал: Bootstrap 5
  • Preview: FileReader API
  • Validation: Client-side + Server-side
  • CSRF: Из cookie или hidden input

Производительность

Оптимизации

  • ✅ Сжатие аватаров на лету (JPEG quality 50-85)
  • ✅ Удаление старых файлов (нет дубликатов)
  • ✅ Batch добавление участников (без N+1 queries)
  • ✅ select_related('employee') для отделов

Размеры файлов

  • До: 8.3 MB PNG, 800+ KB JPEG
  • После: <500 KB JPEG, 512x512px
  • Экономия: ~90-95% места на диске

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

Проверить создание чатов

  1. Личный чат с 1 участником ✅
  2. Групповой чат с аватаром ✅
  3. Чат отдела с автодобавлением ✅
  4. Глобальный основной чат (только 1) ✅
  5. Канал для всех с ограниченной отправкой ✅

Проверить сжатие

  1. Загрузить PNG 5MB → сжато до <500KB JPEG ✅
  2. Заменить аватар → старый файл удален ✅
  3. Проверить preview в модале ✅

Проверить валидацию

  1. Попытка создать 2 основных глобальных чата → ошибка ✅
  2. Чат отдела без выбора отдела → ошибка ✅
  3. Файл >5MB → отклонен на клиенте ✅

Changelog

v1.0 (30 ноября 2024)

  • ✅ Добавлены поля: avatar, department, include_all_employees, is_main
  • ✅ Реализовано автосжатие аватаров (512x512, <500KB)
  • ✅ Добавлены типы: department, global
  • ✅ Динамические поля в модале
  • ✅ API поддержка FormData + файлов
  • ✅ Валидация основных чатов
  • ✅ Автодобавление участников по правилам
  • ✅ Signal для сжатия и cleanup

TODO

  • Crop аватара перед загрузкой (client-side)
  • Batch upload нескольких аватаров
  • История изменений аватара чата
  • Права на изменение аватара (только owner/admin)
  • Предпросмотр аватара в списке чатов
  • Поиск чатов по названию в модале