- Создана структура docs/ с категориями: completed, guides, architecture, diagnostic, in-progress, reports - Перемещено 47+ MD файлов из корня проекта в docs/ - Удалено 6 устаревших/дублирующихся файлов - Создана структура backend/scripts/ для тестов и утилит - Перемещено 35 Python скриптов в backend/scripts/ - Создана структура backend/docs/ для технической документации - Перемещено 12 MD файлов backend в backend/docs/ - Перемещены LDAP тестовые данные в backend/tests/fixtures/ - Добавлены README файлы для навигации - Добавлены правила в .github/copilot-instructions.md для размещения документации Результат: - Корень проекта: только README.md - Корень backend/: только manage.py и Django приложения - Вся документация организована в структурированные папки
9.1 KiB
9.1 KiB
Рефакторинг JS-модулей - ВЫПОЛНЕНО
Изменения в модулях
✅ 1. userWebSocket.js
Добавлено:
- Метод
.configure(options)для динамической конфигурации после инициализации
Функциональность:
const userWs = initUserWebSocket({ userId });
// Позже можно расширить конфигурацию
userWs.configure({
scrollContainerId: 'chatScroll',
formId: 'chatForm',
textareaId: 'id_content',
typingIndicatorId: 'typing',
avatarMap: avatarMap.getAll(),
markReadApi: markReadApi,
onListUpdate: (chatId, message) => { ... }
});
Параметры configure():
scrollContainerId- ID контейнера с сообщениямиformId- ID формы отправкиtextareaId- ID textareatypingIndicatorId- ID индикатора "печатает..."avatarMap- Карта аватаров пользователейmarkReadApi- API из chatMarkReadonListUpdate- Callback для обновления списка чатов
✅ 2. chatComposer.js
Изменено:
- Удалена авто-инициализация в конце файла
- Теперь инициализируется явно из
chat_detail_scripts.html - Возвращает один инстанс (если одна форма) или массив
Было:
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => initChatComposer());
} else {
initChatComposer();
}
Стало:
// УДАЛЕНО: Авто-инициализация
// Теперь происходит через chat_detail_scripts.html
Использование:
const composer = initChatComposer({
chatId: 123,
formId: 'chatForm',
textareaId: 'id_content',
uploadUrl: '/api/v1/upload-message/',
userWs: userWs
});
✅ 3. chatHistoryLoader.js
Изменено:
- Удалена авто-инициализация в конце файла
- Теперь инициализируется явно из
chat_detail_scripts.html
Было:
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', () => initChatHistoryLoader());
} else {
initChatHistoryLoader();
}
Стало:
// УДАЛЕНО: Авто-инициализация
// Теперь происходит через chat_detail_scripts.html
Использование:
const historyLoader = initChatHistoryLoader({
chatId: 123,
scrollContainerId: 'chatScroll',
fetchUrl: '/api/v1/chats/123/messages/',
avatarMap: avatarMap.getAll(),
meId: 1
});
✅ 4. chatListFilter.js
Статус: Уже правильно структурирован
- Нет авто-инициализации
- Экспортирует
initChatListFilter()
✅ 5. chatListRealtime.js
Статус: Уже правильно структурирован
- Нет авто-инициализации
- Экспортирует
initChatListRealtime()
Новая архитектура инициализации
Последовательность загрузки на chat_detail.html:
1. base.html
└─ initUserWebSocket({ userId })
└─ событие: user:ws-ready
2. chat_scripts.html
└─ слушает: user:ws-ready
└─ initChatAvatarMap()
└─ initChatBadgeManager()
└─ событие: chat:system-ready
3. chat_detail_scripts.html
└─ слушает: chat:system-ready
└─ initChatMarkRead({ chatId, ... })
└─ initChatComposer({ chatId, userWs, ... })
└─ initChatHistoryLoader({ chatId, avatarMap, ... })
└─ userWs.configure({ ... }) ← расширяем конфигурацию
└─ userWs.openChat(chatId)
Граф событий
[PAGE LOAD]
↓
[base.html] initUserWebSocket()
↓
[user:ws-ready] ← WebSocket подключен
↓
[chat_scripts.html] инициализация общих модулей
↓
[chat:system-ready] ← Система чатов готова
↓
[chat_detail_scripts.html] инициализация специфичных модулей
↓
[userWs.configure()] ← Расширение конфигурации
↓
[userWs.openChat()] ← Открытие чата
↓
[READY] ← Страница полностью готова
Преимущества новой архитектуры
1. ✅ Явная инициализация
- Понятно, когда и где инициализируется каждый модуль
- Нет "магии" автоматической инициализации
- Легко отследить порядок загрузки
2. ✅ Event-driven координация
- Модули не зависят друг от друга напрямую
- Связь через события:
user:ws-ready,chat:system-ready - Легко добавлять новые слушатели
3. ✅ Ленивая конфигурация
- Базовая инициализация в
base.html - Расширение конфигурации по мере необходимости
- Метод
.configure()для динамического расширения
4. ✅ Изоляция модулей
- Каждый модуль экспортирует только
initфункцию - Нет побочных эффектов при импорте
- Модули можно тестировать независимо
5. ✅ Масштабируемость
- Легко добавлять новые модули
- Легко создавать новые страницы с чатами
- Переиспользование кода
Примеры использования
Создание новой страницы с чатом:
{# templates/communications/new_page.html #}
{% extends "base.html" %}
{% block extra_js %}
{# Подключаем общие chat-скрипты #}
{% include "includes/chat_scripts.html" %}
{# Специфичная логика #}
<script type="module">
window.addEventListener('chat:system-ready', (e) => {
const { userWs, avatarMap, badgeManager } = e.detail;
// Инициализируем нужные модули
const myFeature = initMyFeature({
userWs,
avatarMap,
badgeManager
});
// Расширяем userWs
userWs.configure({
onSpecialEvent: (data) => {
myFeature.handle(data);
}
});
});
</script>
{% endblock %}
Добавление нового обработчика в userWs:
window.addEventListener('chat:system-ready', (e) => {
const { userWs } = e.detail;
// Расширяем конфигурацию
userWs.configure({
onCustomEvent: (data) => {
console.log('Custom event:', data);
}
});
});
Обратная совместимость
Сохранены глобальные переменные:
window.userWebSocket = userWs;
window.chatWebSocketApi = userWs; // legacy
window.chatWebSocket = userWs.ws; // legacy
window.chatAvatarMap = avatarMap;
window.chatBadgeManager = badgeManager;
Старый код продолжает работать:
// Старый способ (работает)
if (window.chatWebSocketApi) {
window.chatWebSocketApi.sendMessage('Hello');
}
// Новый способ (рекомендуется)
window.addEventListener('chat:system-ready', (e) => {
const { userWs } = e.detail;
userWs.sendMessage('Hello');
});
Метрики
До рефакторинга:
- ❌ Автоматическая инициализация во всех модулях
- ❌ Прямые зависимости между модулями
- ❌ Непонятный порядок загрузки
- ❌ Сложно тестировать
После рефакторинга:
- ✅ Явная инициализация через
initфункции - ✅ Event-driven архитектура
- ✅ Чёткий порядок: base → chat_scripts → chat_detail_scripts
- ✅ Изолированные модули, легко тестировать
Следующие шаги
- ✅ ГОТОВО: Рефакторинг base.html
- ✅ ГОТОВО: Добавлен метод .configure() в userWebSocket.js
- ✅ ГОТОВО: Удалена авто-инициализация из chatComposer.js
- ✅ ГОТОВО: Удалена авто-инициализация из chatHistoryLoader.js
- 🔄 СЛЕДУЮЩЕЕ: Тестирование на реальной странице
- 🔄 СЛЕДУЮЩЕЕ: Документирование API всех модулей
- 📋 ПОТОМ: Полный рефакторинг на React/Vue (компонентный подход)