## Backend (7 production files + 6 test files) ### P0-2: LLM output truncation cascade fix - _token_budget.py: OUTPUT_PER_ROW_PER_LANG 120→200, OUTPUT_SAFETY_FACTOR 0.70→0.55 - Prevents finish_reason=length → split → retry cascade (3 calls → 1 call per batch) - P2-8: added qwen-flash/qwen-plus/qwen-max/qwen-coder to PROVIDER_DEFAULTS ### P1-4/P1-5: EncryptionManager singleton - encryption.py: get_encryption_manager() process-wide singleton - llm_provider.py: use singleton instead of new EncryptionManager() per batch - Eliminates ~90 redundant Fernet key validations per translation run ### P1-6: Cache-hit log aggregation - _batch_proc.py: one log per batch (batch_rows + cache_hits) instead of per-row - 1076 log lines → ~30 per run ### P1-7: Timezone-aware datetime fix - scheduler.py: _ensure_aware() helper for naive DB datetime → UTC-aware - Fixes TypeError in scheduled translation concurrency check ### P2-9: Connection test timeout - connection_service.py: asyncio.wait_for(15s) on all dialect tests - Prevents 2-minute UI hangs from DNS/TCP stalls ### Trace ID propagation - middleware/trace.py: inject x-trace-id response header via ASGI send wrapper ### Test fixes & integration tests - test_scheduler.py: AsyncMock for execute_run, mock get_async_job_runner - test_sql_insert_service.py: AsyncMock for execute_sql - test_token_budget.py: batch_size 50→45 for new OUTPUT_PER_ROW_PER_LANG=200 - test_encryption.py: +2 singleton tests - test_scheduler_ensure_aware.py: +4 (naive→aware, passthrough, None, subtraction) - test_batch_classify_persist.py: +2 cache-hit aggregation tests - test_connection_service_edge.py: +2 timeout tests - test_trace_middleware.py: +4 x-trace-id header tests - test_token_budget.py: +4 qwen-flash/O200 tests ## Frontend (7 production files + 5 test files) ### Trace ID propagation - api.ts: _captureTraceId() reads x-trace-id → setTraceId() in fetchApi/requestApi/postApi/deleteApi ### Duplicate datasource columns fetch - ConfigTabForm.svelte: guard availableColumns.length === 0 before fetch ### Admin pages Svelte 5 runes fix - admin/users/+page.svelte: plain let → () for all template-bound vars - admin/roles/+page.svelte: same fix - Both pages were stuck on «Загрузка...» due to mixed reactivity models ### Validation popover positioning - +page.svelte: pass trigger HTMLElement instead of event - DashboardHubModel.svelte.ts: toggleValidationPopover(HTMLElement), closeValidationPopover() - Added X close button + click-outside overlay + i18n ### Test fixes & integration tests - api.test.ts: mock setTraceId/getTraceId, +3 _captureTraceId tests - provider_config.integration.test.ts: handleDelete→promptDeleteProvider - DatasetPreview.test.ts: dashboards/ → ROUTES.dashboards - test_config_tab_form.svelte.js: +2 columns fetch guard tests (NEW) - admin-users.test.ts: +3 loading→table tests (NEW) - admin-roles.test.ts: +2 loading→table tests (NEW) ## Semantic curation - Removed @COMPLEXITY N from 6 route files + metrics.py (duplicate of [C:N]) - Added [C:N] to 2 orphan child contracts in metrics.py - Added [C:N] + @BRIEF to 4 frontend anchors - Fixed #region → # #region consistency in validation_tasks.py ## Verification - Backend: 608 pytest passed (0 failures) - Frontend: 2472 vitest passed (128 files, 0 failures) - Frontend build: ✓ built in 18s - Browser: dashboards, admin/users, admin/roles, validation popover — all green
16 KiB
#region FeatureSpec [C:3] [TYPE ADR] [SEMANTICS spec,requirements,feature,task,status,monitoring] @BRIEF Feature specification — единый центр просмотра статусов всех фоновых задач superset-tools: переводы, миграции, бекапы, валидации, документация и прочие. Без привязки к реализации Python/Svelte.
Navigation (DSA Indexer keywords)
@SEMANTICS: spec, requirements, feature, task, status, monitoring, dashboard
Feature Branch: 034-task-status-center
Created: 2026-06-18 | Status: Draft
Input: "я хочу единый центр просмотра статусов всех задач - переводов миграций бекапов валидаций и прочих."
Clarifications
Session 2026-06-18
- Q: Центр статусов — новая страница или переработка существующей
/reports? → A: Переработка/reports— добавляем сводную панель, real-time обновления и интеграцию с Task Drawer на существующей странице. Новый роут/tasksне создаётся. Старый режим «только история» остаётся доступным через фильтр. - Q: Какие задачи видит каждая роль (admin, analyst, viewer) на
/reports? → A: Admin — все задачи всех пользователей; analyst — свои задачи + задачи без владельца (системные); viewer — только задачи, запущенные им лично. - Q: Показывать ли в сводке и списке задачи, удалённые retention-политиками? → A: Нет. Сводка и список — оперативная панель, показывающая только незаархивированные задачи. Архивные задачи исключены из выборки.
User Scenarios
Each story is an independently testable unit. Prioritized P1 (MVP) → P2 → P3.
All stories share @SEMANTICS domain keywords from the feature header.
Story 1 — Сводный обзор всех задач (P1)
Why P1: Существующая страница /reports показывает только исторические отчёты завершённых задач. Оператору нужна сводная картина «прямо сейчас»: сколько задач выполняется, ожидает, требует ввода — без переключения между страницами. Сводная панель добавляется поверх существующего списка отчётов на /reports.
Independent Test: Открыть страницу /reports → над списком отчётов появилась сводная панель с агрегированными счётчиками задач по статусам (pending, running, awaiting_input, success, failed) для каждого типа.
Acceptance:
- Given в системе есть задачи разных типов (миграция выполняется, перевод ожидает, бекап завершён с ошибкой) When оператор открывает
/reportsThen он видит сводную панель над списком отчётов с агрегированными счётчиками по статусам и типам задач. - Given оператор находится на
/reportsWhen запускается новая задача или меняется статус существующей Then сводка обновляется в реальном времени (без ручной перезагрузки страницы). - Given в системе нет ни одной задачи When оператор открывает
/reportsThen сводная панель показывает нули по всем категориям, список отчётов пуст с пояснением «Нет задач».
Story 2 — Детальный список задач с фильтрацией (P2)
Why P2: Сводка даёт общую картину, но оператору нужно найти конкретную задачу: «что там с миграцией дашборда X?», «какие переводы упали сегодня?», «показать только бекапы за последние сутки».
Independent Test: На странице /reports кликнуть по карточке сводки «Миграция / Выполняется (3)» → список отчётов фильтруется: только миграции в статусе running.
Acceptance:
- Given в системе есть задачи всех типов When оператор применяет фильтр по типу задачи Then список обновляется и показывает только задачи выбранного типа.
- Given в системе есть задачи в разных статусах When оператор применяет фильтр по статусу (только running + pending) Then список показывает только активные задачи.
- Given оператор ввёл текст в строку поиска When текст совпадает с названием задачи или идентификатором дашборда/конфигурации Then список фильтруется по совпадению.
- Given оператор выбрал временной диапазон «последний час» When задачи созданы более часа назад Then они не отображаются в списке.
Story 3 — Быстрый переход к логам и результатам задачи (P3)
Why P3: Увидев, что задача упала или выполняется, оператор хочет немедленно посмотреть логи или результат — без поиска задачи на другой странице.
Independent Test: На странице /reports кликнуть на строку задачи со статусом FAILED → открывается Task Drawer с логами этой задачи.
Acceptance:
- Given оператор на
/reportsвидит задачу со статусом FAILED When он кликает по задаче Then открывается Task Drawer с логами задачи, курсор прокручивается к последней ошибке. - Given оператор на
/reportsвидит задачу со статусом RUNNING When он кликает по задаче Then открывается Task Drawer и начинает показывать live-логи через WebSocket. - Given оператор навёлся на строку задачи When курсор находится над строкой Then появляется тултип с краткой информацией: тип, время запуска, длительность, ключевой параметр (например, название дашборда).
Edge Cases
- Массовое завершение задач: Одновременно завершаются десятки задач (например, batch-перевод) → сводка и список должны корректно отобразить все изменения без зависания UI (debounce обновлений, batch-обработка WebSocket-событий).
- Потеря WebSocket-соединения: Соединение разрывается → индикатор состояния соединения в интерфейсе; автоматический reconnect с экспоненциальной задержкой; на время разрыва показывается «данные могут быть неактуальны».
- Длительная загрузка истории: В системе тысячи завершённых задач → пагинация и серверная фильтрация предотвращают загрузку полного списка; активные задачи всегда показываются первыми.
- Задача с типом UNKNOWN: Плагин не сопоставлен ни с одним известным типом → отображается с меткой «Неизвестный тип», не ломает фильтрацию.
- Задача в статусе AWAITING_INPUT: Задача ожидает ввода пользователя → отображается в сводке отдельной категорией «Ожидает ввода»; в списке — с визуальным индикатором и кнопкой «Ответить».
- Отсутствие прав: Пользователь с ролью viewer видит только свои задачи в списке и сводке; задачи других пользователей не отображаются. Попытка прямого доступа к чужой задаче через URL — 403.
- Переключение между страницами: Оператор уходит с
/reportsи возвращается → восстанавливается последний набор фильтров (из URL query params), сводка перезапрашивается. - Задачи, удалённые retention-политикой: Задача очищена из БД → исчезает из сводки и списка при следующем обновлении данных. Оператору не нужно видеть «призраки» удалённых задач.
Requirements
Functional (IDs survive HCA 128× via hierarchical naming)
- TSC-FR-001: Страница
/reportsотображает сводную панель над списком отчётов с агрегированными счётчиками задач по статусам (pending, running, awaiting_input, success, failed) для каждого типа задач (перевод, миграция, бекап, валидация, документация, прочие). - TSC-FR-002: Сводная панель обновляется в реальном времени через WebSocket без перезагрузки страницы.
- TSC-FR-003: Список отчётов (задач) отображается с пагинацией, сортировкой по времени создания (свежие сверху) и возможностью изменить сортировку.
- TSC-FR-004: Оператор может фильтровать список отчётов по: типу задачи, статусу, текстовому поиску (по названию задачи, идентификатору ресурса), временному диапазону. Клик по карточке сводки автоматически устанавливает соответствующий фильтр.
- TSC-FR-005: Каждая задача в списке показывает: тип (с иконкой), название/идентификатор, статус (с цветовой индикацией), время запуска, длительность, связанный ресурс (дашборд, датасет, конфигурация перевода).
- TSC-FR-006: Клик по задаче открывает Task Drawer с логами этой задачи через WebSocket (
/ws/logs/{task_id}). Для завершённых задач — загружает архивные логи. - TSC-FR-007: Задачи в статусе AWAITING_INPUT отображаются с визуальным индикатором и кнопкой «Ответить», открывающей форму ввода в Task Drawer.
- TSC-FR-008: Статус WebSocket-соединения отображается индикатором; при разрыве — автоматический reconnect с уведомлением оператора.
- TSC-FR-009: Страница
/reportsсоблюдает RBAC: admin видит задачи всех пользователей; analyst видит свои задачи и системные задачи (без владельца); viewer видит только задачи, запущенные им лично. Сводная панель отражает только видимые пользователю задачи. - TSC-FR-010: Активные задачи (running, pending, awaiting_input) всегда показываются в начале списка, независимо от выбранной сортировки.
Key Entities
- Task: Фоновая задача, запущенная через любой плагин superset-tools. Ключевые атрибуты: идентификатор, тип (translate, migration, backup, validation, documentation, git, storage, debug, search, mapper, maintenance, clean_release, unknown), статус (PENDING, RUNNING, SUCCESS, FAILED, AWAITING_INPUT, AWAITING_MAPPING), время создания/запуска/завершения, связанный ресурс, идентификатор пользователя. Архивные задачи (удалённые retention-политикой) исключаются из сводки и списка.
- TaskSummary: Агрегированная сводка — срез количества задач по каждой комбинации (тип × статус). Обновляется в реальном времени.
- TaskFilter: Набор параметров фильтрации, применяемых к списку задач: типы, статусы, поисковый запрос, временной диапазон.
Success Criteria
- SC-001: Оператор получает сводку по всем задачам не более чем за 1 секунду после открытия
/reports. - SC-002: Изменение статуса задачи отражается в сводке и списке не более чем через 2 секунды после события на backend (измеряется от отправки WebSocket-события до обновления DOM).
- SC-003: Оператор находит нужную задачу (фильтрация + поиск или клик по карточке сводки) не более чем за 2 действия после открытия
/reports. - SC-004: При 100+ одновременно активных задачах интерфейс остаётся отзывчивым (частота кадров не падает ниже 30 fps при прокрутке списка).
- SC-005: Восстановление WebSocket-соединения после разрыва происходит автоматически в течение 5 секунд с экспоненциальной задержкой.
#endregion FeatureSpec