From 50001f5ec563271b24bcfe641851e9c77d24edb1 Mon Sep 17 00:00:00 2001 From: busya Date: Wed, 11 Mar 2026 11:30:07 +0300 Subject: [PATCH] fix logger import --- backend/src/api/routes/settings.py | 8 +- backend/src/core/auth/repository.py | 2 +- .../lib/components/health/PolicyForm.svelte | 41 ++++--- .../routes/settings/automation/+page.svelte | 83 ++++++++++++- init_task.md | 109 ------------------ specs/019-superset-ux-redesign/tasks.md | 4 + 6 files changed, 122 insertions(+), 125 deletions(-) delete mode 100644 init_task.md diff --git a/backend/src/api/routes/settings.py b/backend/src/api/routes/settings.py index 0280e450..94c74bb9 100755 --- a/backend/src/api/routes/settings.py +++ b/backend/src/api/routes/settings.py @@ -21,6 +21,7 @@ from ...core.logger import logger, belief_scope from ...core.superset_client import SupersetClient from ...services.llm_prompt_templates import normalize_llm_settings from ...models.llm import ValidationPolicy +from ...models.config import AppConfigRecord from ...schemas.settings import ValidationPolicyCreate, ValidationPolicyUpdate, ValidationPolicyResponse from ...core.database import get_db from sqlalchemy.orm import Session @@ -345,6 +346,7 @@ async def get_consolidated_settings( from ...services.llm_provider import LLMProviderService from ...core.database import SessionLocal db = SessionLocal() + notifications_payload = {} try: llm_service = LLMProviderService(db) providers = llm_service.get_all_providers() @@ -359,6 +361,10 @@ async def get_consolidated_settings( "is_active": p.is_active } for p in providers ] + + config_record = db.query(AppConfigRecord).filter(AppConfigRecord.id == "global").first() + if config_record and isinstance(config_record.payload, dict): + notifications_payload = config_record.payload.get("notifications", {}) or {} finally: db.close() @@ -371,7 +377,7 @@ async def get_consolidated_settings( llm_providers=llm_providers_list, logging=config.settings.logging.dict(), storage=config.settings.storage.dict(), - notifications=config.payload.get("notifications", {}) + notifications=notifications_payload ) # [/DEF:get_consolidated_settings:Function] diff --git a/backend/src/core/auth/repository.py b/backend/src/core/auth/repository.py index 440f3f84..cfa5ff33 100644 --- a/backend/src/core/auth/repository.py +++ b/backend/src/core/auth/repository.py @@ -17,7 +17,7 @@ from sqlalchemy.orm import Session from ...models.auth import Permission, Role, User from ...models.profile import UserDashboardPreference -from ..logger import belief_scope +from ..logger import belief_scope, logger # [/SECTION] # [DEF:AuthRepository:Class] diff --git a/frontend/src/lib/components/health/PolicyForm.svelte b/frontend/src/lib/components/health/PolicyForm.svelte index 2ea5a6e4..6a1dd19f 100644 --- a/frontend/src/lib/components/health/PolicyForm.svelte +++ b/frontend/src/lib/components/health/PolicyForm.svelte @@ -11,21 +11,36 @@ -->
diff --git a/init_task.md b/init_task.md deleted file mode 100644 index cb2bb121..00000000 --- a/init_task.md +++ /dev/null @@ -1,109 +0,0 @@ - - - -Это абсолютно логичный следующий шаг. Переход от **Pull-модели** (пользователь сам заходит в `ss-tools` посмотреть, не сломалось ли чего) к **Push-модели** (система сама бьет тревогу) — это стандарт для любого Enterprise инструмента. - -Более того, раз вы **уже внедрили профили пользователей и привязку аккаунтов Superset** (как мы обсуждали в предыдущем шаге), у вас открывается возможность делать **"Умный роутинг" (Smart Routing)** уведомлений. - -Вот как лучше всего спроектировать эту систему (UI, логика и форматы отчетов). - ---- - -### 1. Умный роутинг (Киллер-фича благодаря профилям) - -Вам не обязательно заставлять пользователей вручную вбивать email-ы для каждого дашборда. -В Superset у каждого дашборда есть `owners` (владельцы). - -**Логика:** -1. LLM-проверка дашборда завершается со статусом `FAIL`. -2. Бэкенд `ss-tools` смотрит: кто `owners` у этого дашборда в Superset? (например, `admin` и `ivan.ivanov`). -3. Бэкенд ищет этих пользователей в базе профилей `ss-tools`. -4. Если у `ivan.ivanov` в профиле `ss-tools` прописан Email или Telegram ID, система **автоматически** отправляет ему персональное уведомление: *"Привет! Твой дашборд упал"*. - ---- - -### 2. Как встроить это в UI (Настройки) - -Разделите настройки на **Глобальные провайдеры** (для админов) и **Правила отправки** (для пользователей/задач). - -#### А. Настройки интеграций (Global Settings -> Notifications) -Здесь администратор системы один раз настраивает доступы. -* **Email (SMTP):** Хост, Порт, Логин, Пароль, От кого (noreply@ss-tools.com). -* **Корпоративный мессенджер:** Webhook URL или Bot Token. -* **Telegram:** Bot Token. - -#### Б. Настройка правил в "Политике проверки" (Validation Policy) -Когда пользователь настраивает расписание проверок (о котором мы говорили ранее), добавьте секцию "Уведомления". - -```text -[ Настройка LLM-проверки: Nightly Prod Check ] - -... (выбор дашбордов и расписания) ... - -🔔 Уведомления об инцидентах: -Отправлять при статусе:[ Только FAIL ⌄ ] (Опции: FAIL, FAIL + WARN, Всегда) - -Куда отправлять: -[x] Автоматически Владельцам (Owners) дашборда (Email / Мессенджер из их профиля) -[x] В общий канал / группу: - + Добавить канал - [ Slack ⌄ ] -> Канал: [ #bi-alerts ] - [ Email ⌄ ] -> Адрес:[ data-team@company.com ] -``` - ---- - -### 3. Дизайн самих уведомлений (Payload) - -Очень важно, чтобы уведомление не было простыней логов, иначе его начнут игнорировать (Alert Fatigue). - -#### ✉️ Формат Email-письма (Богатый формат) -Письмо должно содержать всё необходимое, чтобы понять проблему без перехода в систему. - -* **Тема:** 🔴 [ss-tools] Ошибка валидации: Sales Executive Dashboard -* **Тело (HTML):** - * **Заголовок:** 🔴 **FAIL:** Sales Executive Dashboard (Окружение: PROD) - * **Краткий вердикт LLM:** "Сломан чарт Revenue YTD. Ошибка базы данных: колонка profit не найдена." - * **Картинка:** Вшитый скриншот дашборда с обведенной ошибкой (как он генерируется в вашей системе). - * **Кнопка:** `[ Открыть полный отчет в ss-tools ]` (Deep link прямо на страницу с логами). - -#### 💬 Формат для Мессенджеров (Slack / Telegram) -В мессенджере картинки и длинные тексты читаются хуже. Формат должен быть сверх-компактным. - -**Сообщение от бота:** -> 🚨 **Dashboard Validation Failed** -> **Dashboard:** [Sales Executive](link-to-ss-tools-report) -> **Env:** ss-prod | **Time:** 03:15 AM -> -> 🤖 **LLM Summary:** -> Обнаружена SQL-ошибка в чарте "Revenue". Данные не отображаются. -> -> 🔗 `[View in ss-tools]` 📊 `[Open in Superset]` - -*(Для Slack/Telegram можно прикрепить скриншот вторым сообщением или вложением, если API позволяет, но текст должен быть первичным).* - ---- - -### 4. Архитектура Бэкенда (Как это реализовать в FastAPI) - -Чтобы код не превратился в спагетти, используйте паттерн "Издатель-Подписчик" (Pub/Sub) или абстрактную фабрику уведомлений. - -1. **Создайте базовый класс `NotificationProvider`**: - ```python - class NotificationProvider(ABC): - @abstractmethod - async def send(self, report: ValidationResult, recipient: str): - pass - ``` -2. **Реализуйте провайдеры**: `SmtpEmailProvider`, `SlackWebhookProvider`, `TelegramBotProvider`. -3. **Слой `NotificationService`**: - В конце выполнения `DashboardValidationPlugin.execute()`, плагин вызывает: - ```python - await notification_service.dispatch_report(validation_result) - ``` -4. Служба `NotificationService` смотрит в БД настройки расписания и профили владельцев, решает, *кому* отправлять, и вызывает нужные провайдеры. -5. **Фоновые задачи:** Сама отправка почты/сообщений не должна тормозить основной поток задачи. Оберните вызов в `BackgroundTasks` FastAPI или отправляйте через Celery/Redis Queue, чтобы таска завершилась мгновенно, а письмо ушло асинхронно. - -### Итог по UX: -Пользователь заходит в свой профиль -> вводит свой Telegram ID -> ставит галочку "Уведомлять меня о моих упавших дашбордах". -Всё! Дальше система сама берет на себя всю рутину. Если ночью дашборд, где он Owner, упал — он утром получает сообщение в телегу со скриншотом. Это "Wow-эффект" для конечного пользователя. \ No newline at end of file diff --git a/specs/019-superset-ux-redesign/tasks.md b/specs/019-superset-ux-redesign/tasks.md index 009cac6c..c1066f72 100644 --- a/specs/019-superset-ux-redesign/tasks.md +++ b/specs/019-superset-ux-redesign/tasks.md @@ -573,3 +573,7 @@ All implementation tasks MUST follow the Design-by-Contract specifications: - [x] D095 [US3] Migrate deprecated native event directives to event attributes in [`+page.svelte`](frontend/src/routes/dashboards/+page.svelte), fix modal propagation handlers, and address targeted a11y warnings in [`automation/+page.svelte`](frontend/src/routes/settings/automation/+page.svelte). - [x] D096 [US6] Resolve blocking parse error in [`ProtectedRoute.svelte`](frontend/src/components/auth/ProtectedRoute.svelte) by removing HTML comments from script scope and aligning rendering with Svelte 5 (`{@render ...}`). +- [x] D097 [US1] Fix auth backend runtime failure by importing logger in [`AuthRepository`](backend/src/core/auth/repository.py) to eliminate `NameError` during [`POST /api/auth/login`](backend/src/api/auth.py). +- [x] D098 [US6] Fix consolidated settings 500 by replacing invalid `config.payload` access in [`settings router`](backend/src/api/routes/settings.py) with DB-backed `AppConfigRecord` notifications extraction and safe fallback. +- [x] D099 [US6] Diagnose Settings→Automation click crash for Svelte 5: confirmed runes-mode compile blocker in [`automation/+page.svelte`](frontend/src/routes/settings/automation/+page.svelte) (`$:` not allowed) and validated likely runtime null-source in [`PolicyForm.svelte`](frontend/src/lib/components/health/PolicyForm.svelte) where `policy={null}` can trigger `policy.name` access during add-flow initialization. +- [x] D100 [US6] Fix Settings→Automation policy form null crash for Svelte 5 by making [`PolicyForm.svelte`](frontend/src/lib/components/health/PolicyForm.svelte) null-safe for `policy`/`environments` and removing runes `state_referenced_locally` warning pattern from form initialization.