- Добавлена закрывающая скобка } в onClick handler
- Добавлено содержимое кнопки с иконкой Eye
- Удален блок отображения document_type (поле не существует в модели)
- Убраны поля document_type и tags из DocumentUploadForm
- Обновлен API клиент: createDocument и updateDocument без этих полей
- Обновлены TypeScript типы в api.ts
- Убраны document_type и tags из отображения в documents/page.tsx
- Форма теперь принимает только: title, description, file
- Создана management команда fix_filer_polymorphic
- Использует прямой SQL для обновления polymorphic_ctype_id
- Исправляет ошибку PolymorphicTypeUndefined при GET /api/v1/documents/
- Обработано 22 файла в базе данных
Установлен и настроен django-fsm==3.0.1 для управления жизненным циклом документов.
Изменения в модели (documents/models.py):
- Добавлено FSM поле 'status' с 6 состояниями:
* draft (черновик) - по умолчанию
* in_review (на рассмотрении)
* approved (одобрен)
* published (опубликован)
* archived (архивирован)
* rejected (отклонен)
- Созданы transitions (переходы между состояниями):
* submit_for_review(): draft → in_review
* approve(): in_review → approved
* reject(): in_review → rejected
* publish(): approved → published (с отправкой уведомлений)
* return_to_draft(): draft/in_review → draft
* archive(): published → archived
* unarchive(): archived → published
Изменения в админке (documents/admin.py):
- Добавлен status_badge() с цветовыми индикаторами статусов
- Добавлен available_transitions() - список доступных переходов
- Поле status добавлено в list_display и fieldsets
- Фильтрация по статусам в list_filter
Изменения в API (api/v1/documents/):
- Добавлены поля status и status_code в DocumentReadSerializer
- Созданы actions для всех FSM transitions:
* POST /api/v1/documents/{id}/submit-for-review/
* POST /api/v1/documents/{id}/approve/
* POST /api/v1/documents/{id}/reject/
* POST /api/v1/documents/{id}/publish/
* POST /api/v1/documents/{id}/return-to-draft/
* POST /api/v1/documents/{id}/archive/
* POST /api/v1/documents/{id}/unarchive/
Миграция:
- Создана 0006_add_fsm_status.py
- Применена успешно
- Все 16 юнит-тестов проходят
Зависимости:
- Добавлен django-fsm==3.0.1 в requirements.txt
- Создан FilerFileField для сериализации filer.File объектов
- При чтении: возвращает URL файла через filer.url
- При записи: создает filer.File из UploadedFile с валидацией размера
- Обновлены serializers для работы с FilerFileField
- Обновлены тесты API: _filer_file() helper, mak_document() использует filer
- Удален устаревший mock documents.notification
- Удален validate_file() (валидация перенесена в FilerFileField)
WIP: Некоторые тесты не проходят, требуется отладка permissions
- Fixed TypeError in create_notification_async() call
- Removed send_immediately parameter (only supported by create_notification)
- All 16 tests now pass
Подробный отчет о выполненной работе по интеграции django-filer:
- Установленные пакеты и зависимости
- Изменения в конфигурации
- Описание созданных файлов
- Статистика кода и сокращение
- План миграции (6 фаз)
- Преимущества решения
- Проверка работоспособности
Файл: docs/in-progress/DJANGO_FILER_INTEGRATION.md (550+ строк)
Добавлена поддержка django-filer для профессионального управления файлами в приложении documents.
Что добавлено:
- models_v2.py: Новые модели DocumentV2 и DocumentAcknowledgementV2 с FilerFileField
- admin_v2.py: Django admin с drag & drop загрузкой и превью thumbnails
- rules_v2.py: Правила доступа django-rules для новых моделей
- tests_v2.py: Юнит-тесты для моделей и правил доступа
- management/commands/migrate_to_filer.py: Команда для миграции данных из старых моделей
Настройки:
- settings.py: Добавлены filer, easy_thumbnails, mptt, reversion в INSTALLED_APPS
- settings.py: Настроены THUMBNAIL_PROCESSORS и THUMBNAIL_ALIASES
- requirements.txt: Добавлены django-filer==3.4.4, easy-thumbnails==2.10.1, django-mptt==0.18.0, django-reversion==6.1.0
Документация:
- docs/reports/DOCUMENTS_REPLACEMENT_ANALYSIS.md: Анализ вариантов замены приложения documents
Преимущества:
- Поддержка папок и вложенной структуры файлов
- Автоматическая генерация thumbnails для изображений и PDF
- Полнотекстовый поиск по содержимому файлов
- Информация о размере, MIME-типе, метаданные
- История версий через django-reversion
- Сокращение кода с 1180 → ~580 строк (50%)
Миграция:
- Старые модели Document и DocumentAcknowledgement оставлены для совместимости
- Миграция данных: python manage.py migrate_to_filer
- После проверки старые модели можно удалить
Связанные issues: #N/A
Тип изменений: Feature
Область: documents, file management
- requests_app/rules.py: 8 предикатов + 10 правил
* Предикаты: is_request_author, is_request_assignee, can_manage_requests и др.
* Правила: view/change/delete/assign/approve requests, комментирование, статистика
- communications/rules.py: 9 предикатов + 15 правил
* Предикаты: is_chat_member, is_chat_owner, is_chat_admin, is_message_author и др.
* Правила: view/send/change/delete чаты и сообщения, управление участниками, закрепление
* Включены примеры для WebSocket consumers
- calendar_app/rules.py: 9 предикатов + 12 правил
* Предикаты: is_calendar_owner, is_personal_calendar, has_calendar_access и др.
* Правила: view/change/delete календари и события, подписки, экспорт iCal, приглашения
- procurement/rules.py: 8 предикатов + 13 правил
* Предикаты: is_procurement_manager, is_purchase_request_author, can_approve_purchases и др.
* Правила: view/change/delete заявки на закупку, управление поставщиками и договорами
- feed/rules.py: 8 предикатов + 11 правил
* Предикаты: is_post_author, can_publish_posts, can_moderate_posts и др.
* Правила: view/create/change/delete посты, публикация, закрепление, комментирование, реакции
Во всех apps.py добавлен импорт rules для автозагрузки правил при старте Django
- Установлен пакет rules==3.5
- Добавлен ObjectPermissionBackend в AUTHENTICATION_BACKENDS
- Созданы базовые правила для employees:
* Предикаты: is_hr_staff, is_department_head, is_own_profile и др.
* Правила: view/change/delete employee, view reports и контакты
- Созданы базовые правила для documents:
* Предикаты: is_document_owner, has_document_access, can_approve и др.
* Правила: view/change/delete/approve/publish/share documents
- Правила регистрируются в apps.py (ready() метод)
- Создана подробная документация с примерами использования
* В views, templates, DRF permissions, Django Admin
* Сценарии: многоуровневое согласование, временные ограничения
* Сравнение с django-guardian, отладка, тестирование
Документация: docs/guides/DJANGO_RULES_INTEGRATION.md
- Добавлен django-service-objects==0.7.1 в requirements.txt
- Создан отчёт LIBRARY_REPLACEMENT_ANALYSIS.md с рекомендациями:
* django-cacheops → замена common/cache_decorators.py
* django-post-office → замена common/emails.py
* easy-thumbnails → замена common/image_utils.py
* django-rules → улучшение permissions
* requests-cache → кэширование внешних API
План внедрения по фазам с метриками и приоритетами.
Impact: снижение кастомного кода с ~360 до ~50 строк.
Refs: #tech-debt #modernization
- Интегрирован django-service-objects 0.7.1 для Service Layer Pattern
- Перенесена вся логика дней рождения из calendar_app → employees:
* UpsertBirthdayEventService - создание/обновление событий ДР
* DeleteBirthdayEventService - удаление событий ДР
* BulkSyncBirthdaysService - массовая синхронизация
* signals_birthday.py - автосинхронизация через post_save/post_delete
* management command sync_birthdays - CLI команда синхронизации
* тесты (11 tests, 6 passing)
- Обновлена миграция 0013_migrate_to_django_scheduler:
* Добавлен ШАГ 5: автоматическая синхронизация дней рождения (131 событие)
* Исключены старые события ДР из миграции (source.endswith(':birthday'))
* Исправлены имена сотрудников (f'{last_name} {first_name}' вместо get_full_name())
* Добавлен цвет #FFC107 для событий дней рождения
- Очищен calendar_app от birthday сервисов:
* Удалены calendar_app/services/birthday_events.py
* Удалены calendar_app/signals_scheduler.py
* Удалены calendar_app/management/commands/sync_birthdays.py
* Удалены calendar_app/tests/test_services.py
* Обновлен apps.py - удалены ссылки на signals_scheduler
- API улучшения:
* Добавлен api/v1/schedule/permissions.py (IsCalendarOwnerOrAdmin)
* Обновлен views.py с правильными permissions
- Документация:
* DJANGO_SERVICE_OBJECTS_INTEGRATION.md - руководство по Service Layer
* CALENDAR_MIGRATION_ANALYSIS.md - анализ миграции
* MODERNIZATION_ANALYSIS.md - анализ модернизации кодовой базы
Цель: подготовка к будущему удалению calendar_app, централизация
логики сотрудников в employees приложении.
Refs: #birthday-refactoring
- Добавлена проверка Array.isArray() в NotificationCenter
- Добавлена защита от non-array в useNotifications хук
- Исправлен импорт date-fns/locale для версии 4+
- В случае ошибки API устанавливается пустой массив []
Frontend:
- Установлен Sonner для toast уведомлений
- Создан Service Worker (public/sw.js) для Web Push
- Реализован хук useWebPush для управления подписками
- Добавлены утилиты Web Push (lib/push.ts)
- Создан компонент NotificationCenter с UI
- Интегрирован в AppShell (header desktop + mobile)
- Добавлен Toaster в Providers
API методы:
- getVapidPublicKey() - получение VAPID ключа
- subscribePush() - создание подписки
- unsubscribePush() - удаление подписки
- getPushSubscriptions() - список подписок
Возможности:
- � Web Push (работают даже когда вкладка закрыта)
- � NotificationCenter с badge и историей
- � Toast уведомления (Sonner)
- ⚙️ Настройки push подписок
- � Респонсивный дизайн
Документация: frontend/NOTIFICATIONS_IMPLEMENTATION.md
- Добавлен django-push-notifications==3.1.0 в requirements.txt
- Настроен PUSH_NOTIFICATIONS_SETTINGS в settings.py
- Создана миграция данных 0008_migrate_webpush_to_library.py (9 подписок)
- Обновлен send_web_push_notification() в services.py (150→25 строк)
- Обновлены API endpoints: subscribe_push, unsubscribe_push, get_push_subscriptions
- Ожидается 10-50x ускорение при отправке push уведомлений
- Обратная совместимость: API не изменилось, старая модель сохранена
- Полный отчет: backend/docs/reports/DJANGO_PUSH_NOTIFICATIONS_INTEGRATION.md
Расширение поиска: добавлены модели procurement, documents, notifications, schedule.
Всего 12 моделей доступны для полнотекстового поиска через django-watson.
- Добавлены 5 новых моделей в watson search:
* ProcurementRequest (заявки на закупку)
* Equipment (оборудование)
* Document (документы)
* Notification (уведомления)
* Event из django-scheduler (расписание)
- Backend API: форматтеры для новых типов моделей
- Frontend: добавлены иконки и названия для новых типов
- Тесты: исправлены фикстуры, все 13 тестов проходят
- Индексы: 3895 записей проиндексировано
Итого: 12 моделей доступны для полнотекстового поиска
Backend:
- Created REST API endpoint /api/v1/search/
- Added SearchResultSerializer and SearchResponseSerializer
- Implemented search_api_view with model formatters (employee, department, post, request, chat, message, event)
- Registered search endpoint in api/v1/urls.py
- Added permission check for requests (HR can see all, users only their own)
Frontend:
- Added SearchResponse, SearchResult, SearchModelType types
- Added apiClient.search() method in lib/api.ts
- Completely rewrote search/page.tsx:
* Single API call instead of 6 parallel requests
* Cleaner UI with icons for each result type
* Real-time search with loading states
* Meta information display (email, phone, status, etc.)
* Better performance and UX
Benefits:
- Frontend: 220 lines → 178 lines (19% reduction)
- 1 API request instead of 6 (83% less network calls)
- Server-side full-text search via watson (better relevance)
- Unified search results with metadata
Testing:
- API endpoint verified at /api/v1/search/?q=test
- Returns JSON with query, results, counts, total
- Requires authentication (IsAuthenticated decorator)
- Удалено поле last_read_at из ChatReadState, используется только last_read_message FK
- Исправлена логика автоотметки: отмечается последнее ЗАГРУЖЕННОЕ сообщение, а не последнее в чате
- Убран вызов chat.mark_read() при WebSocket open_chat (отмечал последнее в чате вместо загруженного)
- Добавлен signal для мониторинга изменений ChatReadState
- Исправлена логика скролла: убран автоскролл при дозагрузке вниз
- Добавлена проверка разрывов при WebSocket сообщениях (предотвращает пропуск сообщений)
- Реализована автоотметка WebSocket сообщений (только если пользователь внизу)
- Асимметричная загрузка: 24 контекста + 6 новых сообщений
- Добавлен ScrollableMessageList компонент для корректной работы скролла
- Миграции: 0028 (удаление last_read_at), 0029 (индекс на last_read_message)
- Добавлены API методы в api.ts:
* getChats, getChat, createChat
* getChatMessages, sendMessage, sendMessageWithFiles
* updateMessage, deleteMessage
* markChatAsRead, togglePinChat, toggleChatNotifications
- Создан компонент NewChatModal:
* Поиск и выбор сотрудников
* Поддержка приватных и групповых чатов
* Автоматическое название для групп
- Интегрирована кнопка 'Новый чат' в Chatscope UI
- При создании чата автоматически открывается диалог
- Установлены пакеты @chatscope/chat-ui-kit-react и @chatscope/chat-ui-kit-styles
- Создана новая страница /messages-chatscope с полнофункциональным мессенджером
- Добавлен пункт 'Мессенджер (NEW)' в навигационное меню
- Реализована интеграция с существующим Django API
- Добавлена поддержка WebSocket для real-time сообщений
- Список чатов с поиском и аватарами
- Отображение сообщений с датами и вложениями
- Индикатор 'печатает...' через WebSocket
- Extract CalendarCard to separate component (467 lines)
- Create calendarService for API and caching (156 lines)
- Add useCalendarEvents hook (96 lines)
- Create CalendarSidebar wrapper component (29 lines)
- Reduce AppShell.tsx from 1277 to 634 lines (-50%)
- Implement proper separation of concerns
- Move global cache to service layer
- Improve code maintainability and testability
- Реализована возможность конвертации повторяющегося события в обычное:
* При снятии галочки 'Повторяющееся событие' rule_id сбрасывается в null
* Событие становится одиночным, все occurrence исчезают
- Добавлен метод updateRule() в apiClient:
* Позволяет обновлять существующие правила повторения
* Изменения применяются ко всем occurrence события
* Использует PUT запрос к /api/v1/schedule/rules/{id}/
- Исправлено использование repeatMode:
* Заменен устаревший useCount на repeatMode ('until' | 'count' | 'forever')
* Корректная обработка end_recurring_period только для режима 'until'
- Добавлена универсальная функция normalizeByweekday():
* Решена проблема с разными форматами byweekday с backend:
- Массив: [0, 4] ✓
- Строка: '0,4' ✓
- Число: 4 ✓
* Функция используется во всех компонентах:
- EventModal: авто-выбор дней, отображение кнопок, сохранение
- ViewEventDetailsModal: отображение дней недели
* Исправлены ошибки '.map is not a function' и '.includes is not a function'
- Улучшена логика handleSave() в EventModal:
* Проверка необходимости сброса rule при снятии галочки
* Разделение логики создания и обновления правил
* Нормализация byweekday перед отправкой на backend
Closes: полная поддержка CRUD операций для повторяющихся событий
- Заменен boolean useCount на enum repeatMode: 'until' | 'count' | 'forever'
- Добавлен третий radio button 'Бесконечно' в UI
- При выборе 'forever' count и end_recurring_period = undefined
- Для бесконечного режима показывается пояснение вместо input
- loadRule() правильно определяет repeatMode при загрузке правила
- При включении isRecurring по умолчанию repeatMode = 'until'
Проблема: нельзя было создать событие без ограничений по дате или количеству.
Решение: RFC 5545 RRULE поддерживает бесконечное повторение (без count/until).
- Убрана блокировка редактирования для существующих повторяющихся событий
- loadRule() теперь заполняет поля формы параметрами из Rule:
* frequency, interval, byweekday, count
* isRecurring = true
* useCount устанавливается если есть count
- Удален readonly блок с информацией о повторении
- Редактируемые поля теперь доступны для всех событий
- При сохранении будет обновлен Rule через API
Проблема: нельзя было изменять параметры повторения (частота, дни недели, count).
Решение: все occurrences используют общий Rule - просто редактируем его параметры.
Backend:
- Добавлено поле rule_data в EventSerializer
- get_rule_data() возвращает частоту, параметры и описание правила
- Использует rule.get_params() для получения распарсенных параметров
Frontend:
- Добавлены константы FREQUENCY_LABELS и WEEKDAY_LABELS для русификации
- Новый блок с детальной информацией о повторении в синем фоне
- Отображается частота (WEEKLY, MONTHLY и т.д.)
- Дни недели для еженедельных событий (ПН, ВТ, СР...)
- Количество повторений (count)
- Дата окончания повторения (end_recurring_period)
- Подсказка о невозможности редактирования параметров
Проблема: пользователь не видел детали повторяющихся событий.
Решение: красивый информационный блок с полной информацией о правиле.
- Добавлено поле color_event в тип SidebarCalendarEvent
- Добавлен цветной индикатор (h-2 w-2 rounded-full) перед названием события
- Используется fallback: color_event || color || #3498db
- Индикатор отображается рядом с названием события
Проблема: в списке 'На этой неделе' не было визуальных индикаторов цвета события.
Решение: добавлен цветной кружок перед названием каждого события.
- Изменена логика eventDays для учета всех дней многодневного события
- Теперь перебираются все дни от start до end включительно
- Добавлена обработка событий без end (однодневные)
- Сброс времени для корректного сравнения дат
Проблема: точки-индикаторы отображались только в день начала события.
Решение: добавление всех дней из диапазона [start, end] в Set eventDays.
- Убран вызов useCalendar() из AppShell (вызывался до создания CalendarProvider)
- Добавлен state currentSelectedCalendarId в AppShell
- selectedCalendarId передается через props и синхронизируется через useEffect
- onCalendarChange callback передается в Calendar -> CalendarCard
- CalendarCard синхронизирует selectedCalendarId с родительским компонентом
Проблема: useCalendar вызывался в AppShell до того, как CalendarProvider был создан.
Решение: передача selectedCalendarId через props вместо прямого вызова хука.
- Добавлена проверка selectedCalendarId при создании события из мини-календаря
* Теперь при попытке создать событие без выбранного календаря появляется предупреждение
* selectedCalendarId передается в новое событие вместо null
* Добавлен useCalendar() хук в AppShell для доступа к selectedCalendarId
- Исправлено отображение многодневных событий в ViewDayEventsModal
* Изменена логика фильтрации событий: теперь проверяется диапазон [start, end]
* Многодневные события отображаются для всех промежуточных дней, не только для начала/конца
* Исправлена проблема, когда события не показывались в промежуточные дни
Проблема: в большом календаре проверка была, в мини-календаре - нет.
Решение: унификация логики создания события с проверкой выбранного календаря.