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

15 KiB
Raw Blame History

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(…)