diff --git a/REFACTORING_PLAN.md b/REFACTORING_PLAN.md
new file mode 100644
index 0000000..40f9662
--- /dev/null
+++ b/REFACTORING_PLAN.md
@@ -0,0 +1,816 @@
+# План рефакторинга app.js на ES6 модули
+
+## Текущее состояние
+
+- **Размер файла**: 1671 строка
+- **Проблемы**:
+ - Монолитная структура затрудняет поддержку
+ - Все функции в глобальной области видимости
+ - Сложно тестировать отдельные компоненты
+ - Повторное использование кода затруднено
+
+## Целевая архитектура
+
+```
+static/
+├── index.html
+├── styles.css
+├── js/
+│ ├── main.js # Точка входа, инициализация
+│ ├── config.js # Константы и конфигурация
+│ ├── state/
+│ │ └── appState.js # Глобальное состояние приложения
+│ ├── services/
+│ │ ├── api-client.js # Существующий API клиент (переместить)
+│ │ ├── auth.service.js # Аутентификация
+│ │ ├── settings.service.js # Управление настройками
+│ │ └── query.service.js # Запросы к RAG
+│ ├── ui/
+│ │ ├── auth.ui.js # UI авторизации
+│ │ ├── settings.ui.js # Диалог настроек
+│ │ ├── query-builder.ui.js # Построитель запросов
+│ │ ├── answer-viewer.ui.js # Просмотр ответов
+│ │ ├── questions-list.ui.js # Список вопросов
+│ │ ├── annotations.ui.js # Аннотации
+│ │ └── loading.ui.js # Индикаторы загрузки
+│ ├── utils/
+│ │ ├── dom.utils.js # DOM манипуляции
+│ │ ├── format.utils.js # Форматирование (время, текст)
+│ │ ├── file.utils.js # Работа с файлами
+│ │ └── validation.utils.js # Валидация данных
+│ └── data/
+│ ├── storage.js # LocalStorage обертка
+│ └── defaults.js # Дефолтные настройки (из settings.js)
+└── settings.js # Удалить после рефакторинга
+```
+
+## Этапы рефакторинга
+
+### Этап 1: Подготовка (день 1)
+
+**Цель**: Настроить окружение для ES6 модулей
+
+#### 1.1. Обновить index.html
+```html
+
+
+```
+
+#### 1.2. Создать структуру папок
+```bash
+mkdir static/js
+mkdir static/js/state
+mkdir static/js/services
+mkdir static/js/ui
+mkdir static/js/utils
+mkdir static/js/data
+```
+
+#### 1.3. Настроить конфигурацию
+- Создать `js/config.js` с константами
+- Определить экспорты/импорты
+
+---
+
+### Этап 2: Утилиты и вспомогательные функции (день 1-2)
+
+**Цель**: Вынести независимые функции
+
+#### 2.1. `utils/format.utils.js`
+**Функции** (из app.js строки 150-188):
+- `generateUUID()`
+- `formatTime(seconds)`
+- `formatTimestamp(isoString)`
+- `isTableText(text)`
+- `parseTextTable(text)`
+- `escapeHtml(text)`
+
+**Экспорт**:
+```javascript
+export {
+ generateUUID,
+ formatTime,
+ formatTimestamp,
+ isTableText,
+ parseTextTable,
+ escapeHtml
+}
+```
+
+#### 2.2. `utils/file.utils.js`
+**Функции** (строки 262-273, 984-1132):
+- `downloadJSON(data, filename)`
+- `loadFileAsJSON(file)` - новая функция для загрузки
+- `loadFileAsText(file)` - новая функция
+
+**Экспорт**:
+```javascript
+export {
+ downloadJSON,
+ loadFileAsJSON,
+ loadFileAsText
+}
+```
+
+#### 2.3. `utils/validation.utils.js`
+**Функции** (строки 823-860):
+- `validateJSON(jsonString)`
+- `validateLoginFormat(login)`
+
+**Экспорт**:
+```javascript
+export {
+ validateJSON,
+ validateLoginFormat
+}
+```
+
+#### 2.4. `utils/dom.utils.js`
+**Функции**:
+- `showElement(id)`
+- `hideElement(id)`
+- `toggleElement(id)`
+- `setElementText(id, text)`
+- `showToast(message, type)` (строка 277-281)
+
+**Экспорт**:
+```javascript
+export {
+ showElement,
+ hideElement,
+ toggleElement,
+ setElementText,
+ showToast
+}
+```
+
+---
+
+### Этап 3: State Management (день 2)
+
+**Цель**: Централизовать управление состоянием
+
+#### 3.1. `state/appState.js`
+**Содержимое** (строки 10-42):
+```javascript
+class AppState {
+ constructor() {
+ this.settings = { /* ... */ }
+ this.currentEnvironment = 'ift'
+ this.environments = {
+ ift: { /* ... */ },
+ psi: { /* ... */ },
+ prod: { /* ... */ }
+ }
+ }
+
+ // Геттеры
+ getCurrentEnv() { /* ... */ }
+ getCurrentEnvSettings() { /* ... */ }
+
+ // Сеттеры
+ setCurrentEnvironment(env) { /* ... */ }
+ updateSettings(settings) { /* ... */ }
+
+ // Persistence
+ saveToLocalStorage() { /* ... */ }
+ loadFromLocalStorage() { /* ... */ }
+}
+
+export default new AppState()
+```
+
+#### 3.2. `data/storage.js`
+**Функции**:
+- `saveEnvironmentData(env, data)`
+- `loadEnvironmentData(env)`
+- `clearEnvironmentData(env)`
+
+**Экспорт**:
+```javascript
+export {
+ saveEnvironmentData,
+ loadEnvironmentData,
+ clearEnvironmentData
+}
+```
+
+#### 3.3. `data/defaults.js`
+**Перенести из settings.js** (строки 1-70):
+```javascript
+export const defaultSettings = {
+ activeEnvironment: 'ift',
+ environments: { /* ... */ }
+}
+```
+
+---
+
+### Этап 4: Services (день 3)
+
+**Цель**: Бизнес-логика и API взаимодействие
+
+#### 4.1. `services/api-client.js`
+**Действие**: Переместить существующий `api-client.js` в папку `services/`
+
+**Обновить**:
+```javascript
+class BriefBenchAPI {
+ // ... существующий код
+}
+
+export default new BriefBenchAPI()
+```
+
+#### 4.2. `services/auth.service.js`
+**Функции** (строки 60-140):
+- `checkAuth()`
+- `login(loginString)`
+- `logout()`
+- `isAuthenticated()`
+
+**Экспорт**:
+```javascript
+import api from './api-client.js'
+
+export class AuthService {
+ async checkAuth() { /* ... */ }
+ async login(loginString) { /* ... */ }
+ logout() { /* ... */ }
+ isAuthenticated() { /* ... */ }
+}
+
+export default new AuthService()
+```
+
+#### 4.3. `services/settings.service.js`
+**Функции** (строки 290-357):
+- `loadSettingsFromServer()`
+- `saveSettingsToServer(settings)`
+- `extractEnvironmentSettings(envSettings)`
+- `resetToDefaults()`
+
+**Экспорт**:
+```javascript
+import api from './api-client.js'
+import appState from '../state/appState.js'
+
+export class SettingsService {
+ async loadFromServer() { /* ... */ }
+ async saveToServer(settings) { /* ... */ }
+ extractEnvSettings(envSettings) { /* ... */ }
+ resetToDefaults() { /* ... */ }
+}
+
+export default new SettingsService()
+```
+
+#### 4.4. `services/query.service.js`
+**Функции** (строки 861-1063):
+- `buildRequestBody()`
+- `sendQuery(environment, apiMode, requestBody)`
+- `extractQuestions()`
+- `loadRequestFromFile()`
+- `loadResponseFromFile()`
+
+**Экспорт**:
+```javascript
+import api from './api-client.js'
+import appState from '../state/appState.js'
+
+export class QueryService {
+ buildRequestBody() { /* ... */ }
+ async sendQuery(env, apiMode, body) { /* ... */ }
+ extractQuestions() { /* ... */ }
+ async loadRequestFromFile() { /* ... */ }
+ async loadResponseFromFile() { /* ... */ }
+}
+
+export default new QueryService()
+```
+
+---
+
+### Этап 5: UI Components (день 4-5)
+
+**Цель**: Разделить UI логику по компонентам
+
+#### 5.1. `ui/auth.ui.js`
+**Функции** (строки 77-132):
+- `showLoginScreen()`
+- `hideLoginScreen()`
+- `setupLoginListeners()`
+- `handleLoginSubmit()`
+
+**Экспорт**:
+```javascript
+import authService from '../services/auth.service.js'
+
+export class AuthUI {
+ showLoginScreen() { /* ... */ }
+ hideLoginScreen() { /* ... */ }
+ setupListeners() { /* ... */ }
+ async handleLoginSubmit() { /* ... */ }
+}
+
+export default new AuthUI()
+```
+
+#### 5.2. `ui/loading.ui.js`
+**Функции** (строки 1137-1145):
+- `showLoading(message)`
+- `hideLoading()`
+
+**Экспорт**:
+```javascript
+export class LoadingUI {
+ show(message) { /* ... */ }
+ hide() { /* ... */ }
+}
+
+export default new LoadingUI()
+```
+
+#### 5.3. `ui/settings.ui.js`
+**Функции** (строки 362-813):
+- `openSettingsDialog()`
+- `closeSettingsDialog()`
+- `populateSettingsDialog()`
+- `readSettingsFromDialog()`
+- `toggleBackendSettings(show)`
+- `saveSettings()`
+- `resetSettings()`
+- `exportSettings()`
+- `importSettings()`
+
+**Экспорт**:
+```javascript
+import settingsService from '../services/settings.service.js'
+import appState from '../state/appState.js'
+
+export class SettingsUI {
+ open() { /* ... */ }
+ close() { /* ... */ }
+ populate() { /* ... */ }
+ read() { /* ... */ }
+ toggleBackendSettings(show) { /* ... */ }
+ async save() { /* ... */ }
+ async reset() { /* ... */ }
+ export() { /* ... */ }
+ async import() { /* ... */ }
+ setupListeners() { /* ... */ }
+}
+
+export default new SettingsUI()
+```
+
+#### 5.4. `ui/query-builder.ui.js`
+**Функции** (строки 643-883):
+- `showQueryBuilder()`
+- `switchQueryMode(mode)`
+- `validateJSON()`
+- `setupQueryBuilderListeners()`
+
+**Экспорт**:
+```javascript
+import queryService from '../services/query.service.js'
+
+export class QueryBuilderUI {
+ show() { /* ... */ }
+ switchMode(mode) { /* ... */ }
+ validateJSON() { /* ... */ }
+ setupListeners() { /* ... */ }
+ async handleSendQuery() { /* ... */ }
+}
+
+export default new QueryBuilderUI()
+```
+
+#### 5.5. `ui/questions-list.ui.js`
+**Функции** (строки 1179-1273):
+- `renderQuestionsList()`
+- `selectAnswer(index)`
+- `updateQuestionsCount()`
+- `hasAnnotationsInDocs(docsSection)`
+- `pluralize(count, one, few, many)`
+
+**Экспорт**:
+```javascript
+import appState from '../state/appState.js'
+
+export class QuestionsListUI {
+ render() { /* ... */ }
+ selectAnswer(index) { /* ... */ }
+ updateCount() { /* ... */ }
+ hasAnnotations(docsSection) { /* ... */ }
+ setupListeners() { /* ... */ }
+}
+
+export default new QuestionsListUI()
+```
+
+#### 5.6. `ui/answer-viewer.ui.js`
+**Функции** (строки 1279-1443):
+- `renderAnswer(index)`
+- `renderAnswerBody(elementId, text)`
+- `renderDocuments(containerId, docs, ...)`
+- `toggleExpansion(id)`
+- `switchTab(tabButton, tabId)`
+
+**Экспорт**:
+```javascript
+import appState from '../state/appState.js'
+import { formatTime, parseTextTable, escapeHtml } from '../utils/format.utils.js'
+
+export class AnswerViewerUI {
+ render(index) { /* ... */ }
+ renderBody(elementId, text) { /* ... */ }
+ renderDocuments(containerId, docs, ...) { /* ... */ }
+ toggleExpansion(id) { /* ... */ }
+ switchTab(tabButton, tabId) { /* ... */ }
+ setupListeners() { /* ... */ }
+}
+
+export default new AnswerViewerUI()
+```
+
+#### 5.7. `ui/annotations.ui.js`
+**Функции** (строки 1448-1615):
+- `initAnnotationForAnswer(index)`
+- `loadAnnotationsForAnswer(index)`
+- `loadSectionAnnotation(section, data)`
+- `loadDocumentAnnotations(section, subsection, docs)`
+- `setupAnnotationListeners()`
+- `updateCheckboxStyle(checkbox)`
+- `saveAnnotationsDraft()`
+
+**Экспорт**:
+```javascript
+import appState from '../state/appState.js'
+import { saveEnvironmentData } from '../data/storage.js'
+
+export class AnnotationsUI {
+ initForAnswer(index) { /* ... */ }
+ loadForAnswer(index) { /* ... */ }
+ loadSection(section, data) { /* ... */ }
+ loadDocuments(section, subsection, docs) { /* ... */ }
+ setupListeners() { /* ... */ }
+ saveDraft() { /* ... */ }
+}
+
+export default new AnnotationsUI()
+```
+
+---
+
+### Этап 6: Main Entry Point (день 6)
+
+**Цель**: Создать точку входа и инициализацию
+
+#### 6.1. `js/main.js`
+```javascript
+// Импорты
+import appState from './state/appState.js'
+import authService from './services/auth.service.js'
+import settingsService from './services/settings.service.js'
+import authUI from './ui/auth.ui.js'
+import settingsUI from './ui/settings.ui.js'
+import queryBuilderUI from './ui/query-builder.ui.js'
+import questionsListUI from './ui/questions-list.ui.js'
+import answerViewerUI from './ui/answer-viewer.ui.js'
+import annotationsUI from './ui/annotations.ui.js'
+
+// Инициализация приложения
+async function initApp() {
+ // Load settings from server
+ await settingsService.loadFromServer()
+ appState.setCurrentEnvironment(appState.settings.activeEnvironment || 'ift')
+
+ // Load saved data for each environment
+ appState.loadFromLocalStorage()
+
+ // Setup all UI listeners
+ authUI.setupListeners()
+ settingsUI.setupListeners()
+ queryBuilderUI.setupListeners()
+ questionsListUI.setupListeners()
+ answerViewerUI.setupListeners()
+ annotationsUI.setupListeners()
+
+ // Setup environment tabs
+ setupEnvironmentTabs()
+
+ // Render initial state
+ updateUI()
+}
+
+// Setup environment tabs
+function setupEnvironmentTabs() {
+ const tabs = document.querySelectorAll('.env-tab')
+ tabs.forEach(tab => {
+ tab.addEventListener('click', () => {
+ switchEnvironment(tab.dataset.env)
+ })
+ })
+}
+
+// Switch environment
+function switchEnvironment(env) {
+ appState.setCurrentEnvironment(env)
+ updateEnvironmentTabs()
+ updateUI()
+}
+
+// Update environment tabs
+function updateEnvironmentTabs() {
+ const tabs = document.querySelectorAll('.env-tab')
+ tabs.forEach(tab => {
+ if (tab.dataset.env === appState.currentEnvironment) {
+ tab.classList.add('active')
+ } else {
+ tab.classList.remove('active')
+ }
+ })
+}
+
+// Update UI based on current state
+function updateUI() {
+ questionsListUI.render()
+
+ const env = appState.getCurrentEnv()
+ if (env.currentResponse && env.currentResponse.answers) {
+ answerViewerUI.render(env.currentAnswerIndex || 0)
+ } else {
+ queryBuilderUI.show()
+ }
+}
+
+// Entry point
+document.addEventListener('DOMContentLoaded', async () => {
+ const isAuthenticated = await authService.checkAuth()
+
+ if (isAuthenticated) {
+ await initApp()
+ }
+})
+```
+
+#### 6.2. `js/config.js`
+```javascript
+// API Configuration
+export const API_CONFIG = {
+ baseURL: '/api/v1',
+ timeout: 1800000 // 30 minutes
+}
+
+// UI Configuration
+export const UI_CONFIG = {
+ defaultQueryMode: 'questions',
+ defaultWithDocs: true,
+ maxAnnotationLength: 5000
+}
+
+// Storage Keys
+export const STORAGE_KEYS = {
+ token: 'briefBenchToken',
+ user: 'briefBenchUser',
+ settings: 'briefBenchSettings',
+ envData: (env) => `briefBenchData_${env}`,
+ annotations: 'briefBenchAnnotationsDraft'
+}
+
+// Constants
+export const ENVIRONMENTS = ['ift', 'psi', 'prod']
+export const API_MODES = ['bench', 'backend']
+```
+
+---
+
+## Этап 7: Тестирование и оптимизация (день 7)
+
+### 7.1. Ручное тестирование
+- ✅ Авторизация работает
+- ✅ Загрузка/сохранение настроек
+- ✅ Отправка запросов (bench/backend)
+- ✅ Отображение ответов
+- ✅ Аннотации сохраняются
+- ✅ Экспорт/импорт работает
+- ✅ Переключение окружений
+
+### 7.2. Проверка производительности
+- Измерить время загрузки
+- Проверить размер бандла
+- Оптимизировать импорты
+
+### 7.3. Очистка
+- Удалить старый `app.js`
+- Удалить `settings.js`
+- Обновить `.gitignore` если нужно
+
+---
+
+## Миграционная стратегия
+
+### Вариант 1: Постепенная миграция (РЕКОМЕНДУЕТСЯ)
+
+**Подход**: Модули живут параллельно с монолитом
+
+1. Создать папку `js/` с модулями
+2. Оставить `app.js` работающим
+3. Постепенно переносить функции
+4. Тестировать после каждого этапа
+5. Когда все готово - переключиться на `main.js`
+
+**Преимущества**:
+- Можно откатиться в любой момент
+- Меньше риска
+- Легче тестировать
+
+**index.html во время миграции**:
+```html
+
+
+
+
+
+
+
+```
+
+### Вариант 2: Быстрая миграция
+
+**Подход**: Переписать всё за раз
+
+**НЕ РЕКОМЕНДУЕТСЯ** из-за высокого риска багов
+
+---
+
+## Чек-лист миграции
+
+### Подготовка
+- [ ] Создать ветку `feature/modularize-frontend`
+- [ ] Сделать backup текущего app.js
+- [ ] Создать структуру папок
+
+### Этап 1: Утилиты
+- [ ] Создать `utils/format.utils.js`
+- [ ] Создать `utils/file.utils.js`
+- [ ] Создать `utils/validation.utils.js`
+- [ ] Создать `utils/dom.utils.js`
+- [ ] Тесты: проверить что функции работают
+
+### Этап 2: State
+- [ ] Создать `state/appState.js`
+- [ ] Создать `data/storage.js`
+- [ ] Создать `data/defaults.js`
+- [ ] Тесты: проверить геттеры/сеттеры
+
+### Этап 3: Services
+- [ ] Переместить `api-client.js` в `services/`
+- [ ] Создать `services/auth.service.js`
+- [ ] Создать `services/settings.service.js`
+- [ ] Создать `services/query.service.js`
+- [ ] Тесты: проверить API вызовы
+
+### Этап 4: UI Components
+- [ ] Создать `ui/auth.ui.js`
+- [ ] Создать `ui/loading.ui.js`
+- [ ] Создать `ui/settings.ui.js`
+- [ ] Создать `ui/query-builder.ui.js`
+- [ ] Создать `ui/questions-list.ui.js`
+- [ ] Создать `ui/answer-viewer.ui.js`
+- [ ] Создать `ui/annotations.ui.js`
+- [ ] Тесты: проверить рендеринг
+
+### Этап 5: Main
+- [ ] Создать `js/main.js`
+- [ ] Создать `js/config.js`
+- [ ] Обновить `index.html`
+- [ ] Тесты: полный цикл работы
+
+### Этап 6: Очистка
+- [ ] Удалить старый `app.js`
+- [ ] Удалить `settings.js`
+- [ ] Обновить документацию
+- [ ] Code review
+
+---
+
+## Преимущества после рефакторинга
+
+### Для разработки
+- ✅ **Модульность**: Каждый файл отвечает за свою область
+- ✅ **Тестируемость**: Легко покрыть модули unit-тестами
+- ✅ **Читаемость**: Проще найти нужную функцию
+- ✅ **Переиспользование**: Функции можно использовать в других проектах
+
+### Для поддержки
+- ✅ **Изоляция**: Баг в одном модуле не затронет другие
+- ✅ **Масштабируемость**: Легко добавлять новые функции
+- ✅ **Документация**: Каждый модуль самодокументируемый
+- ✅ **Team work**: Разные разработчики могут работать над разными модулями
+
+### Для производительности
+- ✅ **Tree shaking**: Неиспользуемый код не попадет в бандл
+- ✅ **Lazy loading**: Можно подгружать модули по требованию
+- ✅ **Кеширование**: Браузер может кешировать отдельные модули
+
+---
+
+## Риски и митигация
+
+### Риск 1: Поломка существующего функционала
+**Митигация**: Постепенная миграция с тестированием после каждого этапа
+
+### Риск 2: Увеличение времени загрузки (много файлов)
+**Митигация**: Использовать bundler (Vite/Webpack) для production
+
+### Риск 3: Проблемы совместимости браузеров
+**Митигация**: ES6 модули поддерживаются всеми современными браузерами
+
+### Риск 4: Сложность отладки
+**Митигация**: Source maps и понятная структура папок
+
+---
+
+## Следующие шаги
+
+1. **Обсудить план** с командой
+2. **Выбрать стратегию миграции** (постепенная/быстрая)
+3. **Создать ветку** для рефакторинга
+4. **Начать с Этапа 1** (утилиты)
+5. **Тестировать** после каждого этапа
+6. **Code review** перед мержем
+
+---
+
+## Временные оценки
+
+| Этап | Описание | Время |
+|------|----------|-------|
+| Этап 1 | Подготовка | 2 часа |
+| Этап 2 | Утилиты | 3 часа |
+| Этап 3 | State | 2 часа |
+| Этап 4 | Services | 4 часа |
+| Этап 5 | UI Components | 8 часов |
+| Этап 6 | Main Entry | 2 часа |
+| Этап 7 | Тестирование | 4 часа |
+| **ИТОГО** | | **~25 часов** (3-4 рабочих дня) |
+
+---
+
+## Пример использования после рефакторинга
+
+```javascript
+// Было (app.js, строка 900):
+async function handleSendQuery() {
+ const envSettings = getCurrentEnvSettings()
+ const env = getCurrentEnv()
+ const apiMode = envSettings.apiMode || 'bench'
+ // ... 50 строк кода
+}
+
+// Стало (js/ui/query-builder.ui.js):
+import queryService from '../services/query.service.js'
+import appState from '../state/appState.js'
+import loadingUI from './loading.ui.js'
+
+export class QueryBuilderUI {
+ async handleSendQuery() {
+ const envSettings = appState.getCurrentEnvSettings()
+ const apiMode = envSettings.apiMode || 'bench'
+
+ loadingUI.show('Отправка запроса...')
+
+ try {
+ const result = await queryService.sendQuery(
+ appState.currentEnvironment,
+ apiMode,
+ this.buildRequestBody()
+ )
+
+ // Update state
+ appState.getCurrentEnv().currentResponse = result.response
+
+ // Re-render
+ this.hide()
+ answerViewerUI.render(0)
+ } catch (error) {
+ showToast(error.message, 'error')
+ } finally {
+ loadingUI.hide()
+ }
+ }
+}
+```
+
+**Преимущества**:
+- Понятно где искать функцию
+- Легко тестировать
+- Явные зависимости
+- Переиспользуемый код
+
+---
+
+*Автор: Claude Sonnet 4.5*
+*Дата: 2025-12-25*