Files
upload-platform/HISTORY/2026-09-06-layer2-architecture-and-api-boundaries.md
T

7.4 KiB
Raw Blame History

2026-09-06: Архитектурные решения Слоя 2 и границы независимых API слоёв

1. Контекст и цели

Зафиксированы ключевые проектные и архитектурные решения по разработке Слоя 2 в репозитории upload-platform перед началом реализации:

  1. Полная автономность и независимость каждого слоя как отдельного API.
  2. Легкость интеграции обоих слоёв (Слой 1 + Слой 2) в целевые сервисы (drhider, contractor) без переделки исходного кода ядра.
  3. Составлено подробное ТЗ и резюме в файле LAYER2-RESUME.md.

2. Архитектурные границы слоёв и API-контракты

Слой 1: File Picker (v0.1.13 — готов и протестирован)

  • Зона ответственности: выбор отдельных файлов, выбор папок (webkitdirectory), клиентская рекурсивная распаковка ZIP-архивов с помощью fflate, дедупликация, фильтрация по расширениям, проверка лимитов, отрисовка древовидного UI.
  • API-контракт: метод picker.getFiles() возвращает плоский массив стандартных объектов File. Слой полностью изолирован от транспорта и бэкенда.

Слой 2: Транзитная доставка через ВМ-буфер в RAM бэкенда (текущая задача)

  • Причина существования: Ingress-контроллер k8s-кластера (pythonk8s) обрывает входящие запросы с телом более 64 КБ. Прямой POST больших файлов в кластер невозможен; исходящий трафик (egress) из кластера не ограничен.
  • Принципиальные решения:
    1. Пофайловый транзит (Per-File Transit) вместо накопления всей пачки в буфере:
      • Файл k отправляется браузером через PUT в буфер на ВМ.
      • Браузер сразу отправляет POST /api/upload_refs бэкенду во Flask для одного файла k.
      • Бэкенд забирает файл исходящим потоковым GET прямо в RAM сессии (upload/backend/session/state.py).
      • Бэкенд немедленно отправляет DELETE на ВМ.
      • Файл на ВМ удалён, буфер чист. Браузер переходит к файлу k+1.
      • В любой момент времени в буфере на ВМ находится максимум один файл.
    2. RAM-only (хранение строго в памяти):
      • Никакой записи на диск ни на бэкенде, ни на ВМ в постоянном режиме.
    3. Zero Hardcode:
      • Полная параметризация через конфигурацию (vmUploadUrl на фронтенде, vmUploadPrefix на бэкенде для обязательной SSRF-валидации).
    4. Автономный mock-буфер:
      • In-memory mock WebDAV (PUT, GET, DELETE) внутри тестового стенда site/app.py для автономного прогона pytest и Playwright без внешней сети.
  • API-контракт фронтенда: функция uploadFilesViaVm(files, options) с колбэками прогресса по файлу/пачке, завершения файла и поддержкой отмены (AbortController).
  • API-контракт бэкенда: Blueprint upload_refs и менеджер сессий session (создание сессии, потоковое вытягивание, хранение в RAM, TTL, мягкая отмена).

Слой 3: Бизнес-логика потребителей (не входит в текущую задачу)

  • Сервисы drhider (обфускация, LLM) и contractor (парсинг, diff договоров) забирают файлы из оперативной памяти сессии через session.get_files(session_id).
  • В upload-platform Слой 3 эмулируется тестовым callback/эндпоинтом, фиксирующим успешный приём файла из сессии для дальнейшей обработки.

3. Файловая структура Слоя 2 в upload-platform

upload-platform/
├── upload/
│   ├── frontend/
│   │   ├── index.js                     # Слой 1 (initFilePicker)
│   │   ├── table/                       # UI Слоя 1
│   │   ├── zip/                         # fflate
│   │   └── upload/                      # Слой 2 (Фронтенд):
│   │       ├── put_to_vm.js             # XHR PUT одного файла на буфер с прогрессом и abort
│   │       └── upload_via_vm.js         # Пофайловый транзит (PUT -> upload_refs -> repeat)
│   └── backend/                         # Слой 2 (Бэкенд):
│       ├── __init__.py
│       ├── upload_refs/
│       │   ├── __init__.py
│       │   ├── blueprint.py             # Flask Blueprint (POST /api/upload_refs)
│       │   ├── pull_file.py             # Исходящий потоковый GET с ретраями (httpx)
│       │   ├── safe_name.py             # Санитизация имен файлов
│       │   └── config.py                # Конфигурация по умолчанию
│       └── session/
│           ├── __init__.py
│           ├── state.py                 # In-memory хранилище сессий
│           ├── create_session.py
│           ├── add_file.py
│           ├── get_files.py
│           ├── store_result.py
│           ├── store_csv.py
│           ├── ttl.py
│           ├── cancel.py
│           └── cleanup.py
├── site/
│   ├── app.py                           # Flask demo + local RAM mock buffer
│   └── templates/index.html
├── tests/                               # pytest + browser smoke
├── LAYER2-RESUME.md                     # Техническое задание и сводка
├── build.mjs
├── package.json
└── requirements.txt

4. Зафиксированные факты инфраструктуры

  1. ВМ 5.172.178.213: Nginx WebDAV настроен на сброс на диск (/var/www/drhider-upload/, /var/www/contracts-upload/) с cron-очисткой каждые 5 мин (find ... -mmin +30 -delete). Для целевого прода требуется перевод в RAM/in-memory буфер.
  2. Кластер k8s: неймспейсы 20a75175-a58c-49cb-b8fa-e86367b1a8dc (drhider), b4523aba-b5e6-40f1-be56-bb4d2509357c (contractor), 0e108526-5bb2-4757-9499-3f0bac4f0e83 (uploader-dev).