BREAKING CHANGE: Полная независимость communications модуля
Удалено:
- Поле Chat.department (FK на employees.Department)
- Импорты Department из всех файлов communications
- Q(department=...) фильтры в API/WebSocket/rules
Перемещено:
- Сигнал create_main_department_chat → employees/signals.py (проектоспецифичная логика)
Обновлено:
- models.py: удалено поле department, constraint, index
- api/viewsets.py: использует GenericFK через ContentType.objects.get()
- consumers.py: использует GenericFK через ContentType.objects.get()
- rules.py: is_department_chat теперь использует get_participants()
- admin.py: удален department из list_display/search_fields
Миграция:
- 0035_remove_department_field.py: удаляет поле, constraint, index
Результат:
✅ communications НЕ зависит от employees
✅ System check: 0 errors
✅ Использует только GenericFK (context_object)
✅ Полностью переиспользуемый модуль
Для EUSRR-специфичной логики department чатов:
- Настроить COMMUNICATIONS_PARTICIPANT_RESOLVER в settings.py
- Сигнал автосоздания чатов теперь в employees/signals.py
BREAKING CHANGES (backward compatible):
- All code updated to support both old and new fields
- context_object (GenericFK) and flags now primary
- department and is_main still work (DEPRECATED)
FILES UPDATED:
1. signals.py:
- create_main_department_chat() uses context_object + flags
- Creates both old and new fields for compatibility
- Checks existence using Q() for both fields
2. views.py (4 critical updates):
- has_user_access_to_chat(): uses get_participants() (supports both)
- ChatListView.get_queryset(): checks department OR context_object
- ChatDetailView.get_queryset(): checks department OR context_object
- mark_as_read_ajax(): uses get_participants() and include_all_users
3. rules.py:
- is_department_chat(): checks both department and context_object
- Supports GenericFK for Department context
4. apps.py:
- create_main_global_chat(): checks and sets flags['is_primary']
- Backward compatible with is_main
5. admin.py:
- get_readonly_fields(): checks flags['is_primary'] OR is_main
- Prevents editing primary chats
6. notifications/config.py:
- get_chat_display_name(): uses context_object OR department
7. models.py:
- Chat.__str__(): uses context_object OR department
TESTED:
✅ Signal creates chat with context_object + flags
✅ get_participants() works with both fields
✅ __str__ displays correctly
✅ is_department_chat rule works
✅ Backward compatibility preserved
Создание новых нормализованных моделей:
- MessageEditHistory: история редактирования (вместо JSON поля)
- MessageForwardMetadata: метаданные пересылки (OneToOne связь)
Миграции:
- 0025: создание MessageEditHistory и MessageForwardMetadata
- 0026: миграция данных из JSON/полей в новые таблицы (без потерь)
- 0027: удаление старых денормализованных полей
Удалены из Message:
- edit_history (JSONField) → MessageEditHistory модель
- forwarded_from_author (FK)
- forwarded_from_message_id (IntegerField)
- forwarded_from_created_at (DateTimeField)
- forwarded_from_chat_name (CharField)
- thread_reply_count (IntegerField)
Обновлена admin.py:
- Добавлен MessageEditHistoryInline
- Зарегистрированы новые модели
Преимущества:
- Соблюдение 3НФ (нормальная форма Бойса-Кодда)
- FK constraints для целостности данных
- Удобные запросы через ORM (вместо JSON)
- История редактирования с автором и временем
- Счетчик пересылок (forward_count)
Ref: docs/reports/MODELS_ARCHITECTURE_AUDIT.md
- ApiClient теперь обрабатывает 401 и 403 ошибки для обновления токена
- Добавлен JWTRefreshMiddleware для проактивного обновления токенов за 5 минут до истечения
- Добавлена настройка JWT_REFRESH_THRESHOLD_MINUTES (по умолчанию 5)
- Исправлена проблема с периодическими 403 ошибками после истечения access token
## Что сделано
### Модели
- **employees**
- : теперь включает отделы, где сотрудник является **руководителем**.
- Уточнены :
- → у , у .
- : добавлены удобные геттеры , ; улучшён .
- Модели , , приведены к актуальным полям (без start_date/end_date/level и т.п., чтобы не конфликтовать с формами/админкой).
- **feed**
- Вынесены константы типов постов: , , + .
- Жёсткие **CheckConstraint**:
- для департаментских постов ,
- для остальных — .
- Индексы по , , .
- **communications**
- :
- для (чаты отдела удаляются вместе с отделом).
- Метод : активные сотрудники отдела + **руководитель**; для глобального — все активные.
- Запрет удаления **основных** чатов (global/department), но обычные удаляются нормально.
### Админка
- Приведена в соответствие моделям: убраны несуществующие поля, добавлены фильтры/поиск по реальным полям, inlines для отделов (связи сотрудников).
- Исправлены ошибки system check (E033/E108/E116).
### Формы
- , : валидация аватара, корректные required/optional, PhoneNumberField для WhatsApp/WeChat.
- , (динамический queryset сотрудников, не состоящих в отделе).
- , , : соответствуют актуальным моделям, с базовой валидацией диапазонов дат (если применимо).
### Вьюхи (employees)
- Переписаны аккуратно и проще:
- Списки/детали отделов на CBV (, ), в контексте — сотрудники, новости отдела, новые сотрудники.
- Профиль и чужой профиль использует общий шаблон с подключаемыми блоками.
- : доступ только **админу/руководителю**; добавление связи и автодобавление участника (и руководителя) в **чат отдела**.
- : подготовлено к фильтрации по .
### Вьюхи (feed)
- — **универсальная** форма:
- контекст определяется автоматически из GET: | ,
- скрываем поля , чтобы пользователь не ломал контекст,
- редирект — на **красивые** страницы: главная лента / страница отдела / лента сотрудника.
- : только админ — для компании, только **руководитель отдела** — для департамента.
- : комментарии + форма добавления.
- **Добавлены** CRUD для постов и комментариев:
- , — автор/админ/руководитель отдела.
- , — только автор комментария.
### URL-ы
- : добавлены маршруты , , , .
- : все нужные эндпоинты в рабочем состоянии, на месте.
### Шаблоны
- : опрятная шапка, линк на «Все сотрудники отдела», кнопка «Пригласить» (для админа/руководителя), внизу — include **новостей отдела**.
- : приведение к общему стилю, кнопка «Новая публикация» с автоподстановкой department.
- : отображает бейдж контекста (Компания/Отдел/Личное), **одна** кнопка «Отмена», приходит из вьюхи.
- : контекстная кнопка «Назад к ленте» (определяется автоматически), кнопки **Редактировать/Удалить** (по правам), комментарии с кнопками **ред./удал.** у автора.
- Исправлены include-пути (везде , без обратных слешей).
## Почему всё ок
- Нет циклических импортов, выровнены.
- Никакой магии в шаблонах: вся логика определения контекста — во вьюхах.
- Чаты отдела удаляются вместе с отделом; основные чаты защищены от удаления.
- Учитываем **руководителя отдела** везде, где нужно (новости, чат, права).
## Что проверить локально
1) Миграции:
- python manage.py makemigrations
- python manage.py migrate
2) Создать отдел, назначить руководителя.
3) Пригласить сотрудника → автоматически попадёт в чат отдела.
4) Создать новости:
- с главной → тип company,
- со страницы отдела → тип department, поле Department скрыто,
- из ленты сотрудника → тип employee.
5) Закрепление новостей:
- компания — только staff,
- отдел — только head.
6) Редактирование/удаление постов и комментариев — по правам.
## Примечания
- Если ранее в БД были посты с типом 'personal' — вручную мигрируйте на 'employee'.