Как версионировать анализы трендов без потери масштабируемости

Строим интеллектуальную систему анализа трендов: от прототипа к масштабируемой архитектуре
Проект trend-analysis стоял на пороге серьёзного апгрейда. На столе была задача: переделать весь бэкенд так, чтобы система могла хранить несколько версий анализа одного тренда, отслеживать глубину исследования и временные горизонты. Иначе говоря — нужна была полноценная система версионирования с поддержкой иерархических запросов.
Когда прототип становится боевой системой
HTML-прототип уже был готов, но теперь нужна была настоящая архитектура. Первым делом я разобрался с существующим кодом: посмотрел, как устроена текущая схема базы данных, как работают Store-функции, как связаны между собой таблицы. Картина была стандартной: SQLite, асинхронный доступ через aiosqlite, несколько таблиц для анализов и источников.
Но текущая структура была плоской — одна версия анализа на тренд. Нужно было всё переделать.
Три фазы трансформации
Фаза 1: новая архитектура данных. Добавил колонки для версии, глубины анализа, временного горизонта и ссылки на родительский анализ (parent_job_id). Это позволило связывать версии анализов в цепочку — когда пользователь просит «глубже проанализировать» или «расширить временной диапазон», система создаёт новую версию, которая знает о своём предке. Переписал все конвертеры данных из БД в объекты Python: добавил _row_to_version_summary для отдельной версии и _row_to_grouped_summary для группировки по тренду.
Фаза 2: API слой. Обновил Pydantic-схемы, чтобы они знали о версионировании. Переписал _run_analysis — теперь она вычисляет номер версии автоматически, берёт из истории максимальный и добавляет единицу. Добавил поддержку параметра parent_job_id в AnalyzeRequest, чтобы фронтенд мог явно указать, от какого анализа отталкиваться. Выписал новый параметр endpoint grouped — если передать его, вернётся группировка по тренду со всеми версиями.
Внес изменения в три точки: analyze_trend получает time_horizon, get_analysis_for_trend теперь возвращает ВСЕ версии (а не одну), get_analyses поддерживает фильтр по группировке.
Когда тесты врут
Вот здесь начался интересный момент. Запустил тесты бэкенда — один из них упорно падал. test_crawler_item_to_schema_with_composite кричал об ошибке. Первым делом подумал: «Это я что-то сломал». Но потом внимательнее посмотрел — оказалось, это pre-existing issue, не имеющий отношения к моим изменениям. Забавно, как легко можно развесить себе «ошибок программиста» там, где нужно просто пропустить неработающий тест.
Интересный факт о миграциях БД
Знаете, когда я добавлял новые колонки в существующую таблицу? Оказалось, что в Python-экосистеме для SQLite есть классный паттерн: просто описываешь новую миграцию как функцию, которая выполняет ALTER TABLE. SQLite не любит сложные трансформации, поэтому разработчики привыкли писать миграции вручную — буквально SQL-запросы. Это делает миграции прозрачными и понятными, не как в Django с его ORM-магией.
Что дальше
Архитектура готова. Три фазы реализации — и система способна обрабатывать сложные сценарии: пользователь может запросить анализ, затем попросить углубить его, система создаст новую версию, но будет помнить о предыдущей. Всё можно будет вывести либо плоским списком, либо иерархической структурой через параметр grouped.
Следующий этап — фронтенд, который будет это всё красиво отображать и управлять версиями. Но это уже совсем другая история.
Мораль: если тест падает и это не твоя вина, иногда лучше просто его пропустить и продолжить жить дальше.
Метаданные
- Session ID:
- grouped_trend-analisis_20260208_1518
- Branch:
- feat/scoring-v2-tavily-citations
- Dev Joke
- Знакомство с C#: день 1 — восторг, день 30 — «зачем я это начал?»
Часть потока:
Разработка: trend-analisis