# Запрос для Opus — Рефакторинг фронтенда Contracts ## Контекст Проект: сверка договоров через LLM (colocation, ЦОД). Фронтенд — ванильный JS (app.js ~51KB + app_utils.js ~4KB). Бэкенд — Python http.server на ВМ. Фронт управляет пайплайном: ``` Загрузка → Парсинг → Классификация → Группировка → Сравнение ``` ## Текущая проблема Код эволюционировал organically. Глобальные переменные (`fileQueue`, `contractId`, `batchId`), манипуляции с DOM через `innerHTML`, состояние размазано по DOM и JS-переменным. Последствия: - Сложно тестировать (нет изолированных юнитов) - Сложно отлаживать (состояние не в одном месте) - Баги с гонками, затиранием данных, повторными срабатываниями кнопок - Любое изменение ломает что-то в другом месте ## Идея заказчика (НЕ догма — оцени и предложи лучшее) Разбить на независимые функции-пайплайн: ``` upload(files) → [{ id, name, parsed }] classify(docs) → [{ id, name, parsed, type, number, date, counterparty }] group(classified) → [{ contract, documents[] }] compare(group) → { contract, documents[], results[], expandable } render(state) → DOM ``` Каждая функция: чистые входные данные → новые выходные, не мутирует, не трогает DOM. Рендеринг — отдельно. Состояние хранится в одном месте. ## Что нужно от тебя 1. **Оценить идею.** Это правильный подход для ванильного JS? Или есть более подходящий паттерн (state machine, pub/sub, flux-like store)? Не изобретай велосипед — бери best practices для проектов такого масштаба (~50KB JS). 2. **Предложить архитектуру.** Как организовать код чтобы: - Каждый этап пайплайна тестируем изолированно - Состояние предсказуемо и отлаживаемо (console.log одного объекта показывает всё) - DOM-рендеринг отделён от логики - Минимальные изменения в текущем коде (не переписывать с нуля) 3. **План миграции.** Как перейти от текущего состояния к новому постепенно, не ломая работающий функционал. ## Релевантные файлы (читать) - `contractor/deploy/app.js` — весь фронтенд (~51KB): renderTable, runClassify, loadGroups, runCompareForGroup, buildGroupCard, markGroupDone, syncDB, stepper, toggleClassifyDetail, showText, SSE handlers - `contractor/deploy/app_utils.js` — утилиты: removeFile, escHtml, formatSize, formatDate, openAbout - `contractor/index.cfm` — HTML-оболочка, DOM-структура ## Игнорировать - `contractor/deploy/convert_server.py` и все Python-файлы — бэкенд, не рефакторим - `contractor/deploy/db/`, `contractor/deploy/services/` — бэкенд - `contractor/*.cfm` кроме index.cfm — старый Lucee-код - `contracts-app/`, `contracts-vm/`, `History/`, `DOC/`, `FILES/` — не относится ## Ключевые функции для анализа | Функция | Строки (app.js) | Что делает | |---------|-----------------|------------| | renderTable | 57-75 | Рендер таблицы файлов | | fileInput change | 76-290 | Загрузка + парсинг | | runClassify | 308-360 | Классификация | | loadGroups | 362-430 | Группировка + рендер карточек | | buildGroupCard | 433-442 | Карточка необработанной группы | | markGroupDone | 444-478 | Карточка обработанной группы | | runCompareForGroup | 483-590 | Сравнение группы (apply → SSE) | | toggleClassifyDetail | 91-130 | Раскрытие промежуточных результатов | | syncDB | 26-34 | Синхронизация БД с таблицей | | stepper | 38-56 | StepDone/StepActive/ResetStepper | ## Ограничения - Без фреймворков (ванильный JS) - Без классов и наследования (не ООП) - Минимум зависимостей между модулями - Фокус на тестируемость и отлаживаемость - Не переписывать с нуля — мигрировать постепенно