Files
upload-platform/docs/sonnet-architecture-review-prompt.md
T

5.1 KiB

Второе мнение по архитектуре — LEGACY

Исторический prompt для старой архитектуры. Не использовать как план или описание текущего кода.

Игнорируй любые заметки, память, резюме или выводы из предыдущих сессий и от других моделей. Отвечай строго на основе этого промпта, ничего не дочитывая.

Ты — ревьюер архитектуры. Отвечай ТОЛЬКО по существу, тезисами, без введения и воды. Язык ответа: русский. Цель — сэкономить токены. Не переспрашивай, всё нужное уже ниже.

Что за проект

Browser-only file picker (vanilla JS, ES-модули). Пользователь выбирает файлы / папку / ZIP, picker строит сворачиваемое дерево и отдаёт хосту исходные browser File objects. Контент файлов на сервер НЕ уходит. Flask — только статический сервер (страница + модули).

Текущее состояние

Переиспользуемый слой upload/frontend/:

  • table/init_upload_table.js — фабрика initUploadTable(cfg). ТРЕБУЕТ готовые DOM-элементы fileInputEl, folderInputEl, tableBodyEl, countEl. Возвращает {pickFiles, pickFolder, addFiles, getFiles, remove, render, clear}. Внутренний state {nodes, fileKeys(Set), busy}.
  • table/on_files_change.js, on_folder_change.js — обработка выбора, фильтр расширений.
  • table/add_file_with_dedup.js — дедуп по ключу path + NUL + size.
  • table/render.js — рендер дерева, findNode, flattenFiles.
  • table/rebase_tree.js, esc.js (HTML-экранирование), fs.js (формат байт).
  • zip/list_zip_files.js — парсинг ZIP через ГЛОБАЛЬНУЮ fflate; защита от path traversal (отклоняет .., /, \, пустые сегменты); лимит глубины вложенности 20; вложенные ZIP.
  • site/ — demo-обёртка: app.py (Flask: /, /health, /upload-frontend/<path>), templates/index.html (глобально подключает vendor fflate, импортирует модуль по АБСОЛЮТНОМУ пути /upload-frontend/..., содержит <thead> с «Путь/Размер/Статус»), static/style.css, static/vendor/fflate.min.js.

Жёсткие связи (мешают переиспользованию)

  1. Абсолютный путь импорта /upload-frontend/... — привязка к конкретному Flask-маршруту.
  2. Глобальная зависимость fflate (интегратор сам подключает и следит за порядком).
  3. Надписи и структура таблицы зашиты (thead, статус «готов», пустое состояние).
  4. Принудительный DOM-контракт — интегратор строит разметку сам, «вставить без изменений» нельзя.
  5. Нет сборки/дистрибутива — только исходники ES-модулей.

Цель

Универсальный встраиваемый компонент/АПИ, который вставляется в любое приложение (включая managed Flask — drhider) одной строкой. На входе задаются: типы файлов (allowedExt), порядок/скрытие колонок, все надписи, тема. Без излишней сложности.

Моё предложение

  1. Единая точка входа initFilePicker(config) — сама строит DOM (не требует готовых элементов). Config: mount, allowedExt, labels{...все надписи...}, layout{columns, controls, theme}, onChange. Возвращает API + destroy.
  2. Сборка esbuild/rollup в ОДИН бандл с вшитым fflate, форматы ESM + IIFE.
  3. Опционально тонкий Custom Element <file-picker allowed-ext="..."> поверх фабрики (~30 строк).
  4. Без iframe/postMessage, без системы тем/плагинов, без npm-пайплайна (dist коммитится в git).

Вопрос

  1. Архитектура верна? Есть ли ошибка или переусложнение?
  2. Есть ли вариант проще, но столь же универсальный?
  3. Custom Element делать сразу или хватит фабрики + бандла?
  4. Критичные риски / что упущено (безопасность, совместимость, managed Flask)?

Ответь по пунктам 1–4, кратко, только по делу.