diff --git a/docs/MIGRATION-GUIDE.md b/docs/MIGRATION-GUIDE.md
new file mode 100644
index 0000000..458a365
--- /dev/null
+++ b/docs/MIGRATION-GUIDE.md
@@ -0,0 +1,253 @@
+# Инструкция: перенос UI и загрузки файлов с ВМ на Flask (Штурвал)
+
+**Дата:** 2026-07-14
+**Основано на:** drhider v0.0.26 — проверено в бою
+
+---
+
+## Архитектура загрузки (drhider как образец)
+
+```
+Браузер (index.html)
+ │ JS: uploadFiles() — цикл по файлам
+ │ XHR POST /api/upload (FormData, по одному файлу)
+ ▼
+Flask (api_bp.py)
+ │ upload(): сохраняет в сессию → {session_id}
+ │ process_stream(): SSE — обработка с прогрессом
+ ▼
+Python (drhider/*.py)
+ │ obfuscate_files() — основная логика
+ ▼
+Flask → ZIP + CSV → браузеру
+```
+
+## Файлы, отвечающие за UI и загрузку
+
+### 1. `site/templates/index.html` — весь фронтенд
+
+**Ключевые элементы:**
+
+```html
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+**Ключевые JS-функции:**
+
+| Функция | Что делает |
+|---------|------------|
+| `resetAll()` | Сброс всего состояния (F5, между загрузками) |
+| `rr()` | Перерисовка таблицы файлов |
+| `uploadFiles()` | **Главная** — цикл загрузки + SSE-обработка |
+| `ss(idx, html)` | Обновление ячейки статуса в таблице |
+| `downloadZip()` / `downloadCsv()` | Скачивание результатов |
+
+**Критичные исправления (v0.0.26):**
+
+```javascript
+// 1. Прогрев upstream при загрузке страницы — обязательно!
+window.addEventListener('load', () => {
+ sf = []; fi.value = ''; rr();
+ fetch('/health').catch(() => {}); // ← вот это
+});
+
+// 2. Abort предыдущих запросов перед новым
+let activeES = null; // активный EventSource
+let activeXHR = null; // активный XHR
+
+// 3. Защита от F5 во время загрузки
+window.addEventListener('beforeunload', () => resetAll());
+
+// 4. Сохранение списка файлов до очистки
+const files = sf.slice(); // копия перед resetAll()
+
+// 5. Цикл загрузки (по одному файлу)
+for (let i = 0; i < total; i++) {
+ const fd = new FormData();
+ fd.append('files', f, f.name);
+ if (currentSid) fd.append('session', currentSid);
+ const resp = await fetch('/api/upload?_=' + Date.now(), {
+ method: 'POST', body: fd
+ });
+ const data = await resp.json();
+ currentSid = data.session;
+}
+
+// 6. SSE-обработка
+activeES = new EventSource('/api/process_stream/' + currentSid);
+activeES.addEventListener('start', ...); // файл начат
+activeES.addEventListener('done', ...); // файл готов
+activeES.addEventListener('complete', ...); // всё готово
+```
+
+### 2. `site/routes/api_bp.py` — API эндпоинты
+
+```
+POST /api/upload — загрузка одного файла → {session_id}
+GET /api/process_stream/ — SSE: обработка с прогрессом
+POST /api/process/ — обработка без SSE (legacy)
+GET /api/download/ — скачать ZIP
+GET /api/csv/ — скачать CSV отдельно
+```
+
+**Критичные заголовки для SSE:**
+
+```python
+return Response(
+ stream_with_context(generate()),
+ content_type="text/event-stream",
+ headers={
+ "Cache-Control": "no-cache",
+ "X-Accel-Buffering": "no" # ← без этого nginx буферизует SSE
+ }
+)
+```
+
+**Критично: GeneratorExit в SSE-генераторе:**
+
+```python
+def generate():
+ for idx, (fname, content) in enumerate(files):
+ try:
+ yield f"event: start\ndata: ...\n\n"
+ except GeneratorExit:
+ return # клиент отключился — не обрабатываем дальше
+
+ # ... обработка файла ...
+
+ try:
+ yield f"event: done\ndata: ...\n\n"
+ except GeneratorExit:
+ return
+```
+
+### 3. `site/routes/health_bp.py` — liveness probe
+
+```python
+@health_bp.route("/health")
+def health():
+ return jsonify({"ok": True, "version": "0.0.1"})
+```
+
+**Обязательно для Штурвала.**
+
+### 4. `site/app.py` — точка входа
+
+**Критичные настройки:**
+
+```python
+VERSION = "0.0.1"
+
+def create_app():
+ app = Flask(__name__)
+ app.config["VERSION"] = VERSION
+ app.config["MAX_CONTENT_LENGTH"] = 200 * 1024 * 1024 # 200 MB
+
+ from routes import register_routes
+ register_routes(app)
+
+ @app.after_request
+ def no_cache(response):
+ response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
+ response.headers["Pragma"] = "no-cache"
+ response.headers["Expires"] = "0"
+ return response
+
+ return app
+
+app = create_app()
+```
+
+---
+
+## Пошаговая инструкция миграции
+
+### Шаг 1: Скопировать скелет UI
+
+Скопировать `site/templates/index.html` из drhider как основу.
+Заменить:
+- Заголовок (``, `.title`, `.card-header`)
+- Текст описания
+- `accept` в `` если другие форматы
+- Логику в `uploadFiles()` — вызов своего API вместо `obfuscate_files`
+
+### Шаг 2: Адаптировать API
+
+Скопировать `site/routes/api_bp.py`, заменить:
+- Название blueprint'а
+- Логику в `process_stream()` — вызов своей функции вместо `obfuscate_files()`
+- Формат SSE-событий если нужен другой
+
+### Шаг 3: Health endpoint
+
+Скопировать `site/routes/health_bp.py` как есть. Только версию поменять.
+
+### Шаг 4: app.py
+
+Скопировать `site/app.py`, заменить:
+- `VERSION`
+- `MAX_CONTENT_LENGTH` если нужен другой лимит
+- Импорт своих blueprint'ов
+
+### Шаг 5: session.py
+
+Скопировать `site/session.py` как есть. Это in-memory хранилище загруженных файлов и результатов.
+
+### Шаг 6: Интеграция бизнес-логики
+
+Твоя функция обработки должна принимать тот же интерфейс что и `obfuscate_files`:
+
+```python
+def твоя_функция(files, **kwargs):
+ """
+ Args:
+ files: list of (filename: str, content: bytes, mimetype: str)
+ Returns:
+ zip_bytes: bytes — ZIP-архив с результатами
+ csv_str: str — CSV с маппингом (или "")
+ """
+```
+
+---
+
+## Чек-лист перед деплоем
+
+- [ ] `/health` возвращает `{"ok": true}`
+- [ ] `MAX_CONTENT_LENGTH` достаточен для файлов
+- [ ] `no_cache` after_request есть
+- [ ] `X-Accel-Buffering: no` на SSE-эндпоинте
+- [ ] `GeneratorExit` в каждом `yield` SSE-генератора
+- [ ] `stream_with_context` оборачивает генератор
+- [ ] `fetch('/health')` при загрузке страницы
+- [ ] `beforeunload` → `resetAll()`
+- [ ] `activeXHR` и `activeES` очищаются перед новым запуском
+- [ ] `Connection: close` — **НЕ ставить** (Waitress/PEP 3333 запрещает hop-by-hop)
+
+---
+
+## Ссылки на файлы-образцы
+
+| Что | Где в drhider |
+|-----|---------------|
+| HTML/JS/CSS фронтенд | `site/templates/index.html` |
+| API (upload + SSE + download) | `site/routes/api_bp.py` |
+| Health probe | `site/routes/health_bp.py` |
+| Точка входа Flask | `site/app.py` |
+| In-memory сессии | `site/session.py` |
+| Полная архитектура | `docs/ARCHITECTURE.md` |
+| Решённые проблемы кластера | `PROBLEM-AND-SOLUTION.md` |