Files
ss-tools/specs/032-translate-requests-httpx/ux_reference.md
busya ec6421de35 rename ss-tools to superset-tools across the entire project
- Replace all occurrences of 'ss-tools' with 'superset-tools' in 104 files
- Rename git bundle file ss-tools.bundle → superset-tools.bundle
- Update .gitignore pattern accordingly
- Preserve variable names (hasSsTools etc.) and code identifiers
2026-06-16 11:15:19 +03:00

181 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# UX Reference: Async Backend Refactoring
**Feature Branch**: `032-translate-requests-httpx`
**Created**: 2026-06-04
**Status**: ✅ Implemented — all scenarios verified
## 1. User Persona & Context
- **Who is the user?**:
- **Оператор superset-tools** — настраивает и запускает задачи (переводы, бэкапы, деплои, миграции). Может быть несколько операторов одновременно.
- **Администратор** — мониторит состояние системы, просматривает дашборды, управляет окружениями.
- **API-клиент** — внешние системы, вызывающие API superset-tools (например, CI/CD pipeline для деплоя).
- **What is their goal?**: Выполнять несколько операций параллельно без блокировок. Видеть отзывчивый интерфейс независимо от того, какие фоновые задачи выполняются.
- **Context**: Работа через веб-интерфейс SvelteKit SPA или напрямую через REST API. Один экземпляр сервера обслуживает нескольких пользователей.
## 2. The «Happy Path» Narratives
### Narrative A: Translate Setup (основная жалоба)
Оператор открывает переводческую задачу. На вкладке Preview нажимает «Run Preview» (sample_size=10). Видит спиннер. **Не дожидаясь**, переключается на Target Config → жмёт «Check Target Schema». Через 2 секунды — зелёная галочка. Возвращается на Preview — переводы уже загрузились. Всё заняло ~8 секунд параллельно вместо 11 последовательно.
### Narrative B: Multi-Operator (командная работа)
Оператор А запускает бэкап 100 дашбордов из продакшен-Superset. Оператор Б в это же время настраивает переводческую задачу — нажимает предпросмотр, проверяет схему. Администратор открывает список джоб. Все три пользователя работают без задержек — их запросы не стоят в очереди за бэкапом.
### Narrative C: CI/CD Deploy + Monitoring (API-клиент)
CI/CD пайплайн дёргает `POST /git/deploy` для деплоя дашборда в стейджинг. Одновременно администратор через UI проверяет статус дашбордов в LLM Analysis. Деплой (15 секунд на экспорт/импорт + Git-операции) и анализ (скриншоты + LLM) выполняются параллельно.
## 3. Interface Mockups
### API Interaction Flow — Multi-Plugin Concurrency
```
Клиент A (Backup) Сервер (1 worker) Клиент B (Translate) Клиент C (Dashboard)
│ │ │ │
│ POST /backup/run ───────►│ │ │
│ │ ┌─ Superset export ──┐ │ │
│ │ │ get_dashboards() │ │ │
│ │ │ (async, не блок.) │ │ │
│ │ └─────────────────────┘ │ │
│ │ │ │
│ │◄── POST /preview ────────│ │
│ │ │ │
│ │ ┌─ Superset chart data ┐│ │
│ │ │ LLM call (async) ││ │
│ │ └──────────────────────┘│ │
│ │ │ │
│ │ │◄── GET /dashboards ─────│
│ │ │ │
│ │ ┌─ Все три выполняются ┐│ │
│ │ │ конкурентно, ни один ││ │
│ │ │ не ждёт другой ││ │
│ │ └──────────────────────┘│ │
│ │ │ │
│◄── backup result ────────│ │ │
│ (100 dashboards OK) │ │ │
│ │◄── preview result ───────│ │
│ │ (10 rows + cost) │ │
│ │ │◄── dashboard list ──────│
```
### До vs После (тайминг при 1 worker)
```
ДО рефакторинга (sync, 1 worker):
┌────────────┬──────────────────┬───────────────┬──────────┐
│ Backup 45s │ Preview 8s │ SchemaCheck 3s│ GET /jobs│ = 56.5s total
└────────────┴──────────────────┴───────────────┴──────────┘
ПОСЛЕ рефакторинга (async, 1 worker):
┌──────────────────────────────────────────────────────────┐
│ Backup 45s (экспорт дашбордов, файловый I/O) │
│ ┌──────────────────┐ │
│ │ Preview 8s │ │
│ │ ┌──────────────┐ │
│ │ │SchemaCheck 3s│ │
│ │ └──────────────┘ │
│ └──────────────────┘ │
│ ┌── GET /jobs 50ms│
└────────────────────────────────────────┴─────────────────┘ = 45s total
```
### Существующие UI-компоненты (без изменений)
Контракты компонентов не меняются. Меняется только временная характеристика — компоненты больше не ждут друг друга:
| Компонент | Файл | Состояния (без изменений) | Что изменилось |
|-----------|------|---------------------------|----------------|
| TranslationPreview | `TranslationPreview.svelte` | idle → loading → preview_loaded / error | Может быть в loading одновременно с TargetSchemaHint в checking |
| TargetSchemaHint | `TargetSchemaHint.svelte` | idle → checking → complete / error | Не ждёт окончания preview |
| DashboardGrid | `DashboardGrid.svelte` | Загрузка списка | Не ждёт backup/git/deploy |
| BackupConfig | `BackupConfig.svelte` | Запуск бэкапа | Не блокирует другие вкладки |
| GitDeployPanel | Компонент деплоя | Деплой дашборда | Не блокирует просмотр дашбордов |
| StorageUpload | Загрузка файлов | Upload progress | Не блокирует фоновые задачи |
## 4. The «Error» Experience
### Scenario A: Таймаут Superset API при бэкапе
- **User Action**: Запущен бэкап 100 дашбордов. Superset начинает отвечать медленно.
- **System Response**:
- Конкретный вызов `export_dashboard(id)` получает таймаут (30 секунд).
- В отчёте бэкапа этот дашборд помечается как FAILED с причиной «timeout».
- Бэкап продолжается со следующим дашбордом.
- **Другие запросы не затронуты** — админ всё ещё может смотреть список дашбордов.
- **Recovery**: Повторный запуск бэкапа только для упавших дашбордов.
### Scenario B: Отмена запроса (браузер закрыт)
- **User Action**: Оператор запустил предпросмотр, закрыл вкладку.
- **System Response**:
- FastAPI обнаруживает `asyncio.CancelledError`.
- Активный HTTP-вызов к LLM отменяется (`httpx.AsyncClient` закрывает соединение).
- Поллинг SQL Lab прекращается.
- Если БД-транзакция не закоммичена — откатывается.
- **Recovery**: Ноль утечек. При следующем открытии страницы — состояние «idle».
### Scenario C: Сетевая ошибка LLM-провайдера
- **User Action**: Запущен предпросмотр, LLM-провайдер недоступен (DNS failure).
- **System Response**:
- Исключение только в запросе предпросмотра.
- UI показывает `preview_error`: «Preview failed: connection to LLM provider failed».
- Параллельный запрос проверки схемы (к Superset) выполняется нормально.
- **Recovery**: Кнопка «Retry Preview».
### Scenario D: Конкурентный deploy + backup одного дашборда
- **User Action**: CI/CD запустил деплой дашборда X. Оператор запустил бэкап всех дашбордов (включая X).
- **System Response**: Бэкап и деплой работают с разными версиями дашборда. Бэкап экспортирует текущую версию из Superset, деплой импортирует новую. Конфликта данных не возникает — каждый работает со своим снимком.
- **Recovery**: Не требуется. Операции идемпотентны.
### Scenario E: SMTP-сервер недоступен при отправке отчёта
- **User Action**: Задача завершилась, scheduler пытается отправить email-отчёт.
- **System Response**:
- `aiosmtplib` получает connection timeout (10 секунд).
- Уведомление не отправлено, ошибка залогирована.
- Основной API продолжает работать — пользователи не замечают проблему.
- **Recovery**: Отчёт доступен в UI. Администратор проверяет логи, чинит SMTP-сервер.
## 5. Tone & Voice
- **Style**: Технический, лаконичный. Аудитория — DevOps-инженеры и операторы данных.
- **Terminology**: «Предпросмотр» (Preview), «Бэкап» (Backup), «Деплой» (Deploy), «Поллинг» (Polling), «Event loop», «Конкурентность» (Concurrency), «Таймаут» (Timeout).
## 6. Backward Compatibility Contract
**Все публичные API-эндпоинты сохраняют обратную совместимость.** Меняется только транспортный слой и временные характеристики.
| Модуль | Endpoint | Method | Тело запроса | Тело ответа | Коды |
|--------|----------|--------|-------------|-------------|------|
| Translate | `/jobs/{id}/preview` | POST | Без изменений | Без изменений | 201, 400, 502 |
| Translate | `/check-target-schema` | POST | Без изменений | Без изменений | 200, 502, 503, 504 |
| Notifications | (scheduler, no public API) | — | Без изменений | Без изменений | — |
**Error Mapping (единый для всех эндпоинтов, взаимодействующих с Superset):**
| Условие | HTTP Status |
|---------|-------------|
| Pool acquire timeout (семафор исчерпан) | 503 Service Unavailable |
| Superset network unreachable / connection error | 502 Bad Gateway |
| Superset request timeout (upstream) | 504 Gateway Timeout |
| Superset auth failure после retry | 502 Bad Gateway |
| Superset rate-limit (429 от Superset) | 502 Bad Gateway (не раскрываем upstream 429) |
Единственное изменение — **временные характеристики**: лёгкие запросы больше не ждут тяжёлых.
## 7. Файловые операции (File I/O Contract)
Файловые операции, вызываемые из `async def`-ручек, должны быть неблокирующими:
| Операция | До рефакторинга | После рефакторинга |
|----------|-----------------|---------------------|
| Экспорт дашборда (ZIP до 50MB) | `shutil.copy` + `open(wb)` | `asyncio.to_thread(…)` или `aiofiles` |
| Сохранение загруженного файла | `shutil.copyfileobj` | `asyncio.to_thread(…)` или `aiofiles` |
| Чтение дашборда с диска | `path.read_bytes()` | `asyncio.to_thread(…)` |
| Git-клонирование репозитория | GitPython (sync) | `asyncio.to_thread(…)` |
| Удаление директории | `shutil.rmtree` | `asyncio.to_thread(…)` |