Проект — коннектор для синхронизации данных из Bitrix24 CRM в PostgreSQL/MySQL с AI-аналитикой (генерация чартов, описание схемы) и публикацией дашбордов.
- workClickHouse.py — модуль для работы с ClickHouse (устаревшая версия)
- Создание таблиц, добавление/удаление столбцов
- Вставка, обновление, удаление записей
- Конвертация типов данных
Архитектура: Clean Architecture (API → Domain → Infrastructure)
- app/config.py — Pydantic Settings: DB URL, Bitrix webhook, OpenAI, charts, dashboards (secret_key, token_expiry), auth (auth_login, auth_password, auth_token_expiry_minutes)
- app/core/auth.py — JWT аутентификация:
create_access_token(email)— генерация JWT сtype: "access", секретdashboard_secret_keyget_current_user()— валидация Bearer JWT, проверкаtype == "access"(изоляция от dashboard-токенов)CurrentUser— типизированная зависимость для protected routes
- app/core/logging.py — structlog с JSON/pretty форматированием
- app/core/exceptions.py — иерархия исключений:
AppException(base),BitrixAPIError,BitrixRateLimitError,BitrixAuthError,BitrixOperationTimeLimitErrorDatabaseError,SyncError,AuthenticationError,AuthorizationErrorAIServiceError(502),ChartServiceError(400)DashboardServiceError(400),DashboardAuthError(401)ReportServiceError(400),PublishedReportAuthError(401)
- app/infrastructure/bitrix/client.py —
BitrixClient: обёртка над fast-bitrix24 с retry/rate limiting- CRM сущности:
crm.{entity}.list,crm.{entity}.get,crm.{entity}.fields,crm.{entity}.userfield.list - Users:
user.get,user.fields(+USER_FIELD_TYPESmapping для типов полей),user.userfield.list - Tasks:
tasks.task.list,tasks.task.get,tasks.task.getFields(UF-поля внутри getFields) - Вспомогательные функции:
_camel_to_upper_snake()— конвертация camelCase → UPPER_SNAKE_CASE для нормализации ключей задач;_normalize_task_records()— пакетная нормализация ключей списка задач
- CRM сущности:
- app/infrastructure/database/connection.py — SQLAlchemy async engine (asyncpg/aiomysql), session factory
- app/infrastructure/database/models.py — ORM модели:
SyncConfig— конфигурация синхронизации по entity_typeSyncLog— история синхронизацийSyncState— состояние инкрементальной синхронизацииAIChart— сохранённые AI-чартыReportPromptTemplate— системные промпты для AI отчётовAIReport— определение AI-отчёта (title, user_prompt, status, schedule_type, schedule_config, sql_queries, report_template, is_pinned)AIReportRun— результат выполнения отчёта (status, trigger_type, result_markdown, result_data, sql_queries_executed, execution_time_ms, llm_prompt)AIReportConversation— история диалога генерации отчёта (session_id, role, content, metadata)PublishedDashboard— опубликованные дашборды (slug, password_hash, is_active, refresh_interval_minutes)DashboardChart— чарты в дашборде (layout позиции, title/description override)DashboardLink— связи между дашбордами для табов (dashboard_id → linked_dashboard_id, sort_order, label)PublishedReport— опубликованные отчёты (slug, title, description, report_id FK → ai_reports, password_hash, is_active)PublishedReportLink— связи между опубликованными отчётами для табов (published_report_id → linked_published_report_id, sort_order, label)
- 001_create_system_tables.py — sync_config, sync_logs, sync_state + default config
- 002_create_ai_charts_table.py — ai_charts
- 003_create_schema_descriptions_table.py — schema_descriptions
- 004_create_dashboards_tables.py — published_dashboards, dashboard_charts (FK cascade)
- 005_add_refresh_interval.py — добавление refresh_interval_minutes в published_dashboards
- 006_create_dashboard_links_table.py — dashboard_links (FK → published_dashboards CASCADE, unique constraint)
- 007_create_dashboard_selectors_tables.py — dashboard_selectors (FK → published_dashboards CASCADE, config JSON, sort_order, is_required), selector_chart_mappings (FK → dashboard_selectors CASCADE, FK → dashboard_charts CASCADE, target_column, target_table, operator_override)
- 007_create_chart_prompt_templates.py — chart_prompt_templates
- 008_add_sql_history.py — sql_query_history
- 009_create_chart_prompts_table.py — chart_prompt_templates (промпт-шаблоны для чартов)
- 010_add_records_fetched_to_sync_logs.py — добавление records_fetched в sync_logs
- 011_create_reports_tables.py — report_prompt_templates, ai_reports, ai_report_runs, ai_report_conversations (PG/MySQL dual dialect, default report_context промпт)
- 012_create_published_reports_tables.py — published_reports (slug, report_id FK, password_hash), published_report_links (PG/MySQL dual dialect)
- 013_add_llm_prompt_to_report_runs.py — добавление колонки llm_prompt (Text, nullable) в ai_report_runs для хранения полного промпта отправленного в LLM
- 016_add_post_filter_to_mappings.py — добавление post_filter в selector_chart_mappings
- 017_add_dashboard_heading_items.py — добавление item_type, heading_config в dashboard_charts для heading-элементов
- 018_add_tab_label_to_dashboards.py — добавление tab_label VARCHAR(255) NULL в published_dashboards
- 019_add_hide_title_to_dashboard_charts.py — добавление hide_title BOOLEAN NOT NULL DEFAULT FALSE в dashboard_charts
- 020_add_title_font_size_override.py — добавление title_font_size_override VARCHAR(10) NULL в dashboard_charts для переопределения размера заголовка на уровне элемента дашборда
- sync_queue.py —
SyncQueue: центральная очередь с двумя каналами:- Heavy Queue (
asyncio.PriorityQueue) — full/incremental/reference синхронизации, один worker (строго последовательно) - Webhook Queue (
asyncio.Queue) — webhook-обработка, worker сSemaphore(3)(до 3 параллельно) SyncPriority(IntEnum)— WEBHOOK=0, MANUAL=10, REFERENCE=20, SCHEDULED=30SyncTaskType(Enum)— FULL, INCREMENTAL, WEBHOOK, WEBHOOK_DELETE, REFERENCE, REFERENCE_ALLSyncTask(dataclass)— задача с приоритетом, дедупликацией поdedup_keyget_sync_queue()— singleton- Дедупликация: задача с тем же
dedup_keyне ставится в очередь повторно _execute_task()— диспетчер: создаёт BitrixClient и вызывает SyncService/ReferenceSyncService
- Heavy Queue (
- chart_service.py —
ChartService:- SQL валидация (
validate_sql_query,validate_table_names,ensure_limit) - Контекст схемы (
get_schema_context,get_allowed_tables,get_tables_info) - Выполнение запросов (
execute_chart_query) с таймаутом - CRUD чартов (
save_chart,get_charts,get_chart_by_id,delete_chart,toggle_pin,update_chart_config,update_chart_sql) update_chart_sql(chart_id, new_sql, title?, description?)— валидирует (SELECT-only, allowed_tables, ensure_limit), выполняет smoke-test черезexecute_chart_query, затем UPDATE- CRUD описаний схемы (
save_schema_description,get_latest_schema_description, etc.)
- SQL валидация (
- ai_service.py —
AIService:generate_chart_spec(prompt, schema_context)→ JSON спецификация чартаrefine_chart_sql(current_sql, instruction, schema_context)→ обновлённый SQL-запрос по текстовой инструкции пользователя (промпт CHART_SQL_REFINE_PROMPT)generate_schema_description(schema_context)→ Markdown документацияgenerate_report_step(conversation_history, schema_context)→ шаг диалога генерации отчёта (вопрос или готовая спецификация)analyze_report_data(report_title, sql_results, analysis_prompt, user_prompt, report_context)→ tuple[str, str] (markdown-отчёт, полный промпт отправленный в LLM)_get_report_context()→ системный промпт из report_prompt_templates
- report_service.py —
ReportService:- Диалог:
save_conversation_message(),get_conversation_history(),generate_session_id() - CRUD:
save_report(),get_reports(),get_report_by_id(),delete_report(),update_report(),update_schedule(),toggle_pin() - Выполнение:
execute_report(report_id, trigger_type)— SQL запросы + LLM анализ → ai_report_runs - Запуски:
get_runs(),get_run_by_id() - Промпт:
get_report_prompt_template(),update_report_prompt_template() - Расписание:
get_active_scheduled_reports() - Переиспользует ChartService для SQL валидации и выполнения
- Публикация:
publish_report(),get_published_reports(),get_published_report_by_id(),delete_published_report(),change_published_report_password() - Публичный доступ:
verify_published_report_password(),get_published_report_by_slug()(с runs + links),get_published_report_runs() - Токены:
generate_report_token(slug)/verify_report_token(token)→ JWT сtype: "report" - Связи:
add_published_report_link(),remove_published_report_link(),get_published_report_links(),update_published_report_link_order(),verify_published_report_linked_access() - Переиспользует
DashboardService._hash_password,_generate_slug,_generate_password,_verify_password
- Диалог:
- sync_service.py —
SyncService: полная/инкрементальная синхронизация сущностей (CRM, users, tasks)- Инкрементальная синхронизация:
DATE_MODIFY(CRM),TIMESTAMP_X(users),CHANGED_DATE(tasks)
- Инкрементальная синхронизация:
- reference_sync_service.py —
ReferenceSyncService: синхронизация справочников - dashboard_service.py —
DashboardService:create_dashboard(title, chart_ids, refresh_interval_minutes)→ slug + bcrypt passwordget_dashboards(page, per_page),get_dashboard_by_id/slug→ с join chartsget_dashboard_id_by_slug(slug)— лёгкий запрос только ID (без charts/selectors)get_chart_sql_by_slug(slug, dc_id)— лёгкий запрос SQL одного чарта (1 JOIN, без загрузки всего дашборда)verify_password(slug, password)→ bcrypt verifygenerate_token(slug)/verify_token(token)→ JWT (HS256, python-jose)update_dashboard,update_layout,update_chart_overrideremove_chart,change_password,delete_dashboardadd_link(dashboard_id, linked_dashboard_id, label?, sort_order?)— связывание дашбордов для табовremove_link(link_id),get_links(dashboard_id),update_link_order(dashboard_id, links)verify_linked_access(main_slug, linked_slug)— проверка связи + активности обоих дашбордов_get_selectors(dashboard_id)— загрузка селекторов через SelectorService (lazy import)
- selector_service.py —
SelectorService:- CRUD:
create_selector(),get_selector_by_id(),get_selectors_for_dashboard(),update_selector(),delete_selector() get_selectors_for_dashboard()— один JOIN-запрос (selectors + mappings), без N+1- Маппинги:
add_mapping(),remove_mapping(),_replace_mappings()— полная перезапись маппингов - Фильтрация:
build_filters_for_chart(dashboard_id, dc_id, filter_values, selectors?)→ список фильтров дляChartService.apply_filters(), принимает предзагруженные селекторы - Опции:
get_selector_options(selector_id),get_all_selector_options(dashboard_id)(batch),_resolve_options(selector)— SELECT DISTINCT с опциональным LEFT JOIN для label-таблицы, или static_values из config - Колонки:
get_chart_columns(dc_id)→ column names через LIMIT 0 subquery - Preview:
preview_filter(dc_id, target_column, operator, target_table?, sample_value?)→ original_sql, filtered_sql, where_clause для визуализации на доске
- CRUD:
- base.py —
BitrixEntityбазовый класс,EntityTypeenum (deal, contact, lead, company, user, task)- CRM сущности (deal, contact, lead, company): API namespace
crm.*, таблицыcrm_{entity}s - User: API namespace
user.*, таблицаbitrix_users - Task: API namespace
tasks.task.*, таблицаbitrix_tasks is_crm()— проверка принадлежности к CRM namespace
- CRM сущности (deal, contact, lead, company): API namespace
- deal.py — Pydantic модель сделки (TITLE, STAGE_ID, OPPORTUNITY, etc.)
- contact.py — Pydantic модель контакта (NAME, PHONE, EMAIL, etc.)
- lead.py — Pydantic модель лида (TITLE, STATUS_ID, OPPORTUNITY, etc.)
- company.py — Pydantic модель компании (TITLE, INDUSTRY, REVENUE, etc.)
- user.py — Pydantic модель пользователя (NAME, EMAIL, WORK_POSITION, PERSONAL_, WORK_, etc.)
- task.py — Pydantic модель задачи (TITLE, DESCRIPTION, STATUS, PRIORITY, DEADLINE, RESPONSIBLE_ID, etc.)
- reference.py —
ReferenceType(crm_status, crm_deal_category, crm_currency)
- init.py — регистрация роутеров с разделением на public и protected:
- Публичные (без auth): auth, webhooks, public
- Защищённые (JWT
Depends(get_current_user)): sync, status, charts, schema, references, dashboards, selectors, reports
- common.py —
HealthResponse,ErrorResponse,SuccessResponse,PaginationParams - charts.py —
ChartGenerateRequest,ChartConfigUpdateRequest,ChartSpec,ChartGenerateResponse,ChartResponse,ChartListResponse,ChartDataResponse - dashboards.py —
DashboardPublishRequest,DashboardUpdateRequest,LayoutItem,DashboardLayoutUpdateRequest,ChartOverrideUpdateRequest(title_override, description_override, hide_title, title_font_size_override),DashboardAuthRequest,IframeCodeRequest,DashboardLinkRequest,DashboardLinkOrderItem,DashboardLinkUpdateRequest,DashboardChartResponse(включает hide_title, title_font_size_override),DashboardLinkResponse,DashboardResponse(сlinked_dashboards,selectors),DashboardListResponse,DashboardPublishResponse,DashboardAuthResponse,PasswordChangeResponse,IframeCodeResponse - selectors.py —
SelectorCreateRequest,SelectorUpdateRequest,MappingCreateRequest,FilterValue,FilterRequest,SelectorResponse,MappingResponse,SelectorListResponse,SelectorOptionItem,SelectorOptionsResponse,ChartColumnsResponse,ChartTablesResponse,FilterPreviewRequest,FilterPreviewResponse - schema_description.py —
ColumnInfo,TableInfo,SchemaTablesResponse,SchemaDescriptionResponse - sync.py —
SyncConfigItem,BitrixFilter,SyncStartRequest/Response(с optional filter),SyncStatusItem/Response,SyncHistoryResponse - webhooks.py —
WebhookEventData,WebhookResponse,WebhookRegistration - reports.py —
ReportConversationRequest/Response,ReportPreview,ReportSaveRequest,ReportScheduleUpdateRequest,ReportUpdateRequest,ReportResponse,ReportListResponse,ReportRunResponse,ReportRunListResponse,ReportPromptTemplateResponse/UpdateRequest,SqlQueryItem,DataResultItem,PublishReportRequest/Response,PublishedReportAuthRequest/Response,PublishedReportResponse,PublishedReportListItem/Response,PublishedReportLinkRequest/Response/OrderItem/UpdateRequest,PublicReportRunResponse,PublicReportResponse
- auth.py — POST
/login— single-user аутентификация (email + password из .env), возвращает JWT access token - charts.py — POST
/generate, POST/execute-sql, POST/save, GET/list, GET/{id}/data(post-enrichment план/факт черезPlanService.enrich_rows_with_planпри наличииchart_config.plan_fact, список фильтров пустой — fallback на полный диапазон), PATCH/{id}/config, PATCH/{id}/sql(ручное обновление SQL с валидацией + smoke-test), POST/{id}/refine-sql-ai(ChartSqlRefineRequest → ChartSqlRefineResponse, AI-рефайн SQL по текстовой инструкции без сохранения), DELETE/{id}, POST/{id}/pin, GET/PUT/prompt-template/bitrix-context - dashboards.py (internal):
- POST
/publish, GET/list, GET/{id}, PUT/{id}, DELETE/{id} - PUT
/{id}/layout, PUT/{id}/charts/{dc_id}, DELETE/{id}/charts/{dc_id} - POST
/{id}/change-password, POST/iframe-code - POST
/{id}/links, DELETE/{id}/links/{link_id}, PUT/{id}/links— управление связями дашбордов
- POST
- public.py (no app auth):
- GET
/chart/{id}/meta, GET/chart/{id}/data - POST
/dashboard/{slug}/auth, GET/dashboard/{slug}, GET/dashboard/{slug}/chart/{dc_id}/data - GET
/dashboard/{slug}/linked/{linked_slug}— получение связанного дашборда (JWT главного) - GET
/dashboard/{slug}/linked/{linked_slug}/chart/{dc_id}/data— данные чарта связанного дашборда - POST
/report/{slug}/auth— авторизация паролем → JWT сtype: "report" - GET
/report/{slug}— данные опубликованного отчёта (runs + linked_reports, JWT) - GET
/report/{slug}/linked/{linked_slug}— данные связанного отчёта (JWT главного) - POST
/dashboard/{slug}/chart/{dc_id}/data— данные чарта с фильтрами (FilterRequest body, JWT); внутри_execute_filtered_chartпослеexecute_chart_queryвызывается post-enrichmentPlanService.enrich_rows_with_planпри наличииchart_config.plan_fact— используется тот же список резолвнутых фильтров изbuild_filters_for_chart(без повторного резолва дата-токенов). Хелпер_extract_plan_fact_cfgпарситchart_config.plan_fact→PlanFactConfig. - POST
/dashboard/{slug}/linked/{linked_slug}/chart/{dc_id}/data— данные чарта linked дашборда с фильтрами (тот же путь_execute_filtered_chart, симметричный post-enrichment план/факт) - GET
/dashboard/{slug}/selectors— список селекторов публичного дашборда (JWT) - GET
/dashboard/{slug}/selector/{selector_id}/options— опции для dropdown/multi-select (JWT) - GET
/dashboard/{slug}/selector-options— batch-опции всех селекторов дашборда за один запрос (JWT)
- GET
- selectors.py (internal, prefix
/dashboards):- POST
/{dashboard_id}/selectors— создание селектора с маппингами - GET
/{dashboard_id}/selectors— список селекторов дашборда - PUT
/{dashboard_id}/selectors/{selector_id}— обновление (включая полную перезапись маппингов) - DELETE
/{dashboard_id}/selectors/{selector_id}— удаление - GET
/{dashboard_id}/selectors/{selector_id}/options— опции dropdown - GET
/{dashboard_id}/charts/{dc_id}/columns— колонки SQL-запроса чарта - GET
/{dashboard_id}/charts/{dc_id}/tables— таблицы из SQL-запроса чарта (FROM/JOIN) - POST
/{dashboard_id}/charts/{dc_id}/preview-filter— превью SQL с фильтром (FilterPreviewRequest → FilterPreviewResponse)
- POST
- schema_description.py — GET
/describe, GET/tables, GET/history, PATCH/{id}, GET/list - sync.py — GET
/config, PUT/config, POST/start/{entity}, GET/status, GET/running - webhooks.py — POST
/register, DELETE/unregister, GET/registered - references.py — GET
/types, GET/status, POST/sync/{ref_name}, POST/sync-all - reports.py — POST
/converse, POST/save, GET/list, GET/{id}, DELETE/{id}, PATCH/{id}(update report fields), PATCH/{id}/schedule, POST/{id}/run, POST/{id}/pin, GET/{id}/runs, GET/{id}/runs/{run_id}, GET/prompt-template/report-context, PUT/prompt-template/report-context, POST/publish, GET/published, GET/published/{id}, POST/published/{id}/change-password, DELETE/published/{id}, POST/published/{id}/links, DELETE/published/{id}/links/{link_id}, PUT/published/{id}/links - status.py — GET
/health, GET/stats, GET/history, GET/scheduler
- scheduler.py — APScheduler:
- Синхронизация:
IntervalTriggerзадачи для инкрементальных синков - Отчёты:
report_execution_job(report_id)— запуск отчёта по расписанию build_report_trigger(schedule_type, schedule_config)— создание CronTriggerschedule_report_jobs()— загрузка активных отчётов из БД и создание задачreschedule_report(report_id, ...)/remove_report_job(report_id)— управление задачами
- Синхронизация:
- FastAPI, SQLAlchemy[asyncio], asyncpg, aiomysql
- fast-bitrix24, python-jose[cryptography], passlib[bcrypt]
- openai, structlog, alembic, httpx, tenacity, apscheduler
React 18 + TypeScript + Vite + Tailwind CSS
- src/services/api.ts — axios HTTP клиент (с 401 interceptor → redirect на /login), все типы и API объекты:
syncApi,statusApi,webhooksApi,referencesApi,chartsApi(сupdateConfig,updateSql,refineSqlWithAiдля ручного и AI-редактирования SQL сохранённых чартов),schemaApidashboardsApi— publish, list, get, update, delete, updateLayout, updateChartOverride, removeChart, changePassword, getIframeCode, addLink, removeLink, updateLinks, listSelectors, createSelector, updateSelector, deleteSelector, getSelectorOptions, getChartColumns, getChartTables, previewFilterreportsApi— converse, save, list, get, delete, update, updateSchedule, run, togglePin, getRuns, getRun, getPromptTemplate, updatePromptTemplatepublishedReportsApi— publish, list, get, delete, changePassword, addLink, removeLink, updateLinkspublicApi— getChartMeta, getChartData, authenticateDashboard, getDashboard, getDashboardChartData, getLinkedDashboard, getLinkedDashboardChartData, getDashboardChartDataFiltered, getLinkedDashboardChartDataFiltered, getPublicSelectors, getPublicSelectorOptions, authenticateReport, getPublicReport, getLinkedReport
- src/hooks/useSync.ts — хуки синхронизации и справочников
- src/hooks/useCharts.ts — хуки чартов (
useUpdateChartConfigдля PATCH config,useUpdateChartSqlдля PATCH sql,useRefineChartSqlWithAiдля AI-рефайна) и описаний схемы - src/hooks/useDashboards.ts —
usePublishDashboard,useDashboardList,useDashboard,useUpdateDashboard,useDeleteDashboard,useUpdateDashboardLayout,useUpdateChartOverride,useRemoveChartFromDashboard,useChangeDashboardPassword,useIframeCode,useAddDashboardLink,useRemoveDashboardLink,useUpdateDashboardLinks - src/hooks/useReports.ts — хуки отчётов:
useReportConverse,useReportSave,useReports,useDeleteReport,useUpdateReport,useUpdateReportSchedule,useRunReport,useToggleReportPin,useReportRuns,useReportPromptTemplate,useUpdateReportPromptTemplate,usePublishReport,usePublishedReport,usePublishedReports,useDeletePublishedReport,useChangePublishedReportPassword,useAddPublishedReportLink,useRemovePublishedReportLink - src/hooks/useSelectors.ts —
useDashboardSelectors,useCreateSelector,useUpdateSelector,useDeleteSelector,useSelectorOptions,useChartColumns,useFilterPreview - src/hooks/useAuth.ts — хук авторизации
- DashboardPage.tsx — обзор статистики и сущностей
- ConfigPage.tsx — управление конфигурацией синхронизации
- MonitoringPage.tsx — мониторинг и логи синхронизации
- ValidationPage.tsx — валидация данных
- ChartsPage.tsx — AI генерация чартов, сохранённые чарты, кнопка "Publish Dashboard", список опубликованных дашбордов (подтаб AISubTabs)
- ReportsPage.tsx — AI отчёты: чат-интерфейс генерации, сохранение отчёта (title/description), список сохранённых отчётов с карточками, секция опубликованных отчётов с кнопкой "Опубликовать" и списком PublishedReportCard, редактор промпта
- SchemaPage.tsx — браузер схемы БД с AI описанием
- LoginPage.tsx — авторизация
- EmbedChartPage.tsx — standalone embed одного чарта (без навигации, публичный)
- EmbedDashboardPage.tsx — публичный дашборд с password gate, JWT в sessionStorage, grid чартов, auto-refresh по интервалу (setInterval), индикатор обновления и "last updated", табы для связанных дашбордов (кеширование загруженных табов, auto-refresh для активного таба), SelectorBar с фильтрами (POST с FilterValue[] при активных фильтрах, сброс при переключении таба), footer с версией UI
- EmbedReportPage.tsx — публичная страница опубликованного отчёта: PasswordGate → JWT в sessionStorage, header (title + description), табы для связанных отчётов (кеш), список runs в виде аккордеона (ReactMarkdown + remarkGfm + markdownTableComponents для таблиц с рамками)
- DashboardEditorPage.tsx — редактор дашборда: drag & drop + resize чартов (react-grid-layout v2), inline редактирование title/description, удаление чартов, смена пароля, копирование ссылки, секция SelectorEditorSection (CRUD селекторов через wizard-модалку из 3 шагов), секция "Linked Dashboards" (добавление/удаление/перестановка связей)
- Layout.tsx — навигация, health индикатор, outlet, footer с версией UI
- SyncCard.tsx — карточка синхронизации сущности с обнаружением OPERATION_TIME_LIMIT и интеграцией FilterDialog
- FilterDialog.tsx — модальное окно фильтра для повторной синхронизации с ограничением по дате (поле, оператор, значение)
- ReferenceCard.tsx — карточка справочника
- charts/ChartRenderer.tsx — рендер чартов (bar, line, pie, area, scatter) через recharts с поддержкой настроек отображения (legend, grid, axes, line/area/pie параметры). Опциональный проп
fontScale?: number— масштабирует все текстовые элементы (data labels, ticks, axis labels, legend, pie label, indicator, table) через helperfs(base) = max(8, round(base * fontScale)); приfontScale == nullhelper возвращает исходные константы,IndicatorRendererиспользуетpy-8,TableRendererсохраняет Tailwindtext-smна<table>— non-TV режим байт-стабилен относительно master. ВнутренниеIndicatorRendererиTableRendererтакже принимаютfontScale - charts/ChartSettingsPanel.tsx — панель настроек чарта (visual, data format, line/area/pie settings) с PATCH сохранением в chart_config
- charts/ChartCard.tsx — карточка сохранённого чарта (pin, refresh, settings, SQL, edit-SQL, embed, delete). Кнопка «Изменить» открывает
SqlEditorModal - charts/SqlEditorModal.tsx — модалка редактирования SQL сохранённого чарта: textarea с текущим SQL, кнопка «Предпросмотр» (POST
/charts/execute-sql) с табличным превью первых 50 строк, AI-панель «Что изменить» (POST/charts/{id}/refine-sql-ai— вставляет результат в редактор), кнопка «Сохранить» (PATCH/charts/{id}/sql) - charts/IframeCopyButton.tsx — кнопка "Embed" для копирования iframe HTML
- dashboards/PublishModal.tsx — модалка публикации дашборда (выбор чартов, title, description, refresh interval → пароль + URL)
- dashboards/DashboardCard.tsx — карточка дашборда в списке (open, edit, link, delete)
- dashboards/PasswordGate.tsx — форма ввода пароля для публичного дашборда
- dashboards/HeadingItem.tsx — полиморфный заголовок дашборда (h1–h6) с inline-редактированием, panel настроек (level, align, color, bg_color, divider). Опциональный
fontScale?: number— при!= 1применяет inlinefontSizeчерезbaseRem[level] * fontScalerem-единицами, иначе fallback на Tailwind text-3xl..text-sm - ai/AISubTabs.tsx — горизонтальные подтабы "Графики" | "Отчёты" (используется в ChartsPage и ReportsPage)
- reports/ReportChat.tsx — чат-интерфейс диалога с LLM: список сообщений, поле ввода, индикатор генерации, кнопка нового чата
- reports/ReportCard.tsx — карточка отчёта: статус, расписание, кнопки (запустить, результаты, SQL, Prompt, расписание, закрепить, удалить), просмотр/редактирование SQL-запросов и промпта
- reports/ScheduleSelector.tsx — редактор расписания: тип (once/daily/weekly/monthly), время, день недели/месяца, статус
- reports/ReportRunViewer.tsx — просмотр запусков отчёта: список с бейджами статуса, 4 таба (Markdown через react-markdown + remarkGfm + markdownTableComponents, SQL запросы, сырые данные, полный промпт)
- reports/markdownComponents.tsx — общие кастомные компоненты ReactMarkdown для таблиц с рамками (table, thead, th, td)
- reports/ReportPromptEditorModal.tsx — модалка редактирования системного промпта для отчётов
- reports/PublishReportModal.tsx — модалка публикации отчёта (выбор отчёта, title, description → URL + пароль)
- reports/PublishedReportCard.tsx — карточка опубликованного отчёта (title, report_title, кнопки open/link/связи/смена пароля/delete), управление связями (linked reports): список текущих связей с удалением, dropdown для добавления новых; смена пароля с отображением нового
- selectors/SelectorBar.tsx — горизонтальная полоса фильтров для публичного дашборда: загрузка опций, 5 типов виджетов, кнопки "Применить"/"Сбросить"
- selectors/SelectorEditorSection.tsx — секция управления селекторами в редакторе дашборда: список с сортировкой, кнопки edit/delete, открытие SelectorBoardDialog. AI-панель генерации (кнопка "AI: сгенерировать"): textarea с пожеланием пользователя + чек-лист чартов с кнопками "Выбрать все"/"Снять все" (по умолчанию выбраны все чарты, headings исключены) — выбранные dashboard_chart_id передаются в
dashboardsApi.generateSelectors(dashboardId, userRequest?, chartIds?); если выбраны все, chartIds не передаётся (backend использует все чарты) - selectors/SelectorModal.tsx — (legacy) wizard из 3 шагов: основные настройки (тип, имя, оператор), источник данных (static/DB с JOIN), привязка к графикам (чекбоксы + выбор колонки)
- selectors/SelectorBoardDialog.tsx — интерактивная доска (React Flow) для настройки маппингов фильтра к графикам: drag-to-connect от селектора к колонкам чартов, edge popup для operator_override, SQL preview
- selectors/SelectorConfigPanel.tsx — левая панель 280px: настройки типа, имени, оператора, источника данных (static/database) — всё на одном экране
- selectors/SqlPreviewPanel.tsx — нижняя сворачиваемая панель: оригинальный и модифицированный SQL с подсветкой WHERE clause
- selectors/nodes/SelectorNode.tsx — кастомный React Flow node: голубая карточка селектора с label, type, operator, source handle справа
- selectors/nodes/ChartNode.tsx — кастомный React Flow node: белая карточка чарта с заголовком и списком колонок, каждая колонка — target handle слева
- selectors/nodes/MappingEdge.tsx — кастомный React Flow edge (Bezier) с label на середине: target_column + operator_override, кнопка удаления при выделении
- selectors/DropdownSelector.tsx — select с кнопкой очистки
- selectors/MultiSelectSelector.tsx — dropdown с чекбоксами, поиском, select all/deselect all
- selectors/DateRangeSelector.tsx — два input[date] + пресеты (сегодня, 7 дней, месяц, квартал)
- selectors/SingleDateSelector.tsx — input[date] с кнопкой очистки
- selectors/TextSelector.tsx — input[text] с debounce 300ms
- src/version.ts — константа
UI_VERSION, обновляется при каждом изменении UI
- src/store/authStore.ts — Zustand store авторизации
- src/store/syncStore.ts — Zustand store текущих синхронизаций
/login→ LoginPage (публичный)/embed/chart/:chartId→ EmbedChartPage (вне Layout, публичный)/embed/dashboard/:slug→ EmbedDashboardPage (вне Layout, публичный)/embed/report/:slug→ EmbedReportPage (вне Layout, публичный)/→ DashboardPage,/config,/monitoring,/validation,/schema(внутри Layout, ProtectedRoute)/ai/charts→ ChartsPage,/ai/reports→ ReportsPage,/ai→ redirect на/ai/charts/dashboards/:id/edit→ DashboardEditorPage (внутри Layout, ProtectedRoute)ProtectedRoute— auth guard: проверяет isAuthenticated, редиректит на /login
- types.ts — типизированные ключи переводов: nav, common, dashboard, config, monitoring, validation, charts, schema, references, dashboards, ai, reports, embedReport, selectors, footer
- locales/ru.ts / locales/en.ts — русские и английские переводы
- @tanstack/react-query, axios, react, react-dom, react-router-dom
- recharts, react-markdown, remark-gfm, zustand, react-grid-layout