- Что показывает: customer ABC/XYZ, RFM, churn by segments, логистику и возвраты, продуктовый и региональный ABC-анализ
- Скриншот
flowchart LR
data_csv["data.csv"] --> etl["jobs/ etl
parsers / validators / extract / transform / load to db"]
events_csv["events.csv"] --> etl
etl --> clean["PostgreSQL очищенные таблички"]
clean --> marts["jobs/marts_builder"]
marts --> mart["PostgreSQL: витринные таблички"]
mart --> features_job["jobs/feature_builder"] & backend["apps/backend"] & superset["Superset"]
features_job --> feature["PostgreSQL: таблички с дополнительными показателями (под ML)"]
feature --> train["jobs/train"] & batch["jobs/batch_scoring"] & mlapi["apps/ml_api"]
train --> artifacts["artifacts/models/*"]
artifacts --> batch & mlapi
batch --> serving["PostgreSQL: итоговые таблички"]
serving --> backend & superset
backend --> frontend["apps/frontend"]
mlapi <---> backend
Это монорепо для хакатонного проекта по retail analytics. Здесь разделены:
- продуктовый backend,
- отдельный ML API,
- frontend,
- batch/jobs,
- SQL-слой для
clean / mart / feature / serving, - локальная инфраструктура через Docker Compose.
В проекте намеренно не используется отдельный task runner. Все основные сценарии ниже описаны прямыми командами
docker compose, чтобы workflow был одинаково понятен на Windows, macOS и Linux. Docker Compose по умолчанию читает.envиз корня репозитория, поэтому отдельный--env-file .envв командах не нужен.
apps/backend: FastAPI backend со stub-роутамиapps/ml_api: отдельный FastAPI сервис под inference contractsapps/frontend: Next.js placeholder frontendjobs/etl: рабочий ETL для загрузкиdata/raw/*.csvвclean.*jobs/marts_builder: рабочий mart refresh runner для полного текущегоmart.*слояjobs/feature_builder,jobs/train,jobs/batch_scoring: scaffold CLI для следующих этапов пайплайнаsql/clean: явный DDL контрактclean.*sql/mart: runnable mart-слой для продаж, customer analytics, ABC/XYZ, логистики, geography и cohortssql/feature,sql/serving: заготовки под признаки и serving-слойapps/backend/alembic: foundational DDL через Alembicinfra/superset: Superset с отдельной metadata DB и read-only подключением к аналитической БД
- дополнительные бизнес-правила и обогащение поверх уже реализованного notebook-backed
clean-слоя - feature / serving SQL и model-serving слой
- реальный SQL runner для
feature_builder - обучение моделей
- batch scoring с реальными моделями
- auth
- реальные dashboard definitions
data/raw/data.csv— широкий денормализованный transactional datasetdata/raw/events.csv— behavioral event log- в
events.csvможет отсутствоватьuser_id - проблемы с encoding возможны и ожидаемы
- raw CSV остаются на диске и не копируются в PostgreSQL как raw replica layer
- целевой жизненный цикл данных:
clean -> mart -> feature -> serving
Текущий ETL берет data/raw/data.csv и data/raw/events.csv и загружает их в typed clean tables:
data.csv->clean.usersdata.csv->clean.ordersdata.csv->clean.order_itemsevents.csv->clean.events
Для data.csv уже встроена логика из notebooks/Анализ_data_csv.ipynb:
- удаление exact duplicate rows
- исключение дублирующих колонок
- исключение
user_geom - исключение
distribution_center_geom - исключение
sold_at - разбиение на сущности
users / orders / order_items - типизация дат, чисел, координат и булевых значений
Для events.csv уже встроена логика из notebooks/Анализ_data_csv.ipynb:
- удаление exact duplicate rows
- сохранение всех event-колонок
- заполнение пропусков в
user_idпоip_address, если в других deduplicated events этотip_addressуже связан с пользователем - заполнение пропусков в
cityпоip_address, если в других deduplicated events этотip_addressуже связан с городом - типизация
created_atиsession_id
Контракт clean.* хранится явно в:
sql/clean/clean_users.sqlsql/clean/clean_orders.sqlsql/clean/clean_order_items.sqlsql/clean/clean_events.sql- ERD
clean-слоя вынесен в docs/architecture/clean_erd.puml - ERD
mart-слоя вынесен в docs/architecture/mart_erd.puml
Текущий marts_builder уже исполняет текущий runnable набор витрин из sql/mart/:
mart.sales_daily: дневные продажи, выручка, число заказов и клиентовmart.behavior_metrics: пользовательские event/session aggregates поclean.eventsmart.customer_360: customer-level срез, который объединяет профиль, заказы и поведениеmart.abc_xyz: notebook-backed ABC/XYZ анализ клиентов и retention strategiesmart.rfm: notebook-backed RFM-сегментацияmart.logistics_metrics: delivery/returns/problem-clients слойmart.cohorts: когорты и retention по месяцамmart.product_xyz: XYZ-анализ стабильности спроса по товарамmart.region_abc: региональный ABC-анализ по выручкеmart.customer_abc_monthly: месячная динамика customer ABC-распределенияmart.customer_category_migration: миграция клиентов между товарными категориямиmart.category_abc: ABC-анализ товарных категорийmart.brand_abc: ABC-анализ брендов
Это уже показывает intended flow:
clean.*хранит очищенные сущностиmart.*хранит reusable аналитические агрегаты для BI, backend и будущих feature tables
apps/: frontend и API-сервисыjobs/: batch и offline jobssql/: SQL-логика по слоямinfra/: bootstrap и локальная инфраструктураlibs/: shared Python utilitiesdata/: локальные входные файлыartifacts/: model artifacts и будущие outputsdocs/: архитектурные заметкиtests/: легкие smoke tests
Создай .env из .env.example.
Вариант для bash:
cp .env.example .envВариант для PowerShell:
Copy-Item .env.example .envЕсли удобнее, файл можно просто создать вручную на основе .env.example.
В репозитории уже есть конфиг .pre-commit-config.yaml с базовыми проверками:
ruffиruff-formatдля Python-кода- базовые git/yaml hooks
prettierдля файлов во frontend
Универсальный способ поставить pre-commit и dev-зависимости:
python -m pip install -r requirements/dev.txtУстановить git hooks локально для репозитория:
python -m pre_commit installЕсли хочешь сразу скачать окружения для hook'ов и проверить, что все работает:
python -m pre_commit install --install-hooks
python -m pre_commit run --all-filesЧто это дает:
- перед каждым
git commitбудут запускаться проверки из.pre-commit-config.yaml - часть проблем будет исправляться автоматически, например formatting через
ruffиprettier - тот же набор проверок можно вручную гонять в любой момент через
python -m pre_commit run --all-files
Для prettier используется локальный pre-commit hook с отдельным Node-окружением, поэтому первый запуск может занять чуть больше времени, пока pre-commit подготовит это окружение.
docker compose up -d --buildЭта команда:
- поднимет
postgresиredis - запустит one-shot
migratorсalembic upgrade head - после успешной миграции поднимет
backend,ml-api,frontendиsuperset - не будет запускать batch/job сервисы из
profiles: ["jobs"]
- Frontend: http://localhost:13000
- Backend docs: http://localhost:18000/docs
- ML API docs: http://localhost:18001/docs
- Superset: http://localhost:18088
docker compose up -d --builddocker compose up -d --builddocker compose downdocker compose logs -f --tail=200docker compose run --rm migratordocker compose run --rm migrator alembic currentdocker compose run --rm etlЭто реально рабочий шаг. После него в БД появятся:
clean.usersclean.ordersclean.order_itemsclean.events
docker compose run --rm marts-builderЭто уже рабочий шаг. Сейчас marts-builder исполняет все реализованные SQL-файлы из sql/mart/ в контролируемом порядке и пересобирает текущий mart-слой целиком.
docker compose run --rm feature-builderdocker compose run --rm traindocker compose run --rm batch-scoringdocker compose run --rm etl
docker compose run --rm marts-builder
docker compose run --rm feature-builder
docker compose run --rm train
docker compose run --rm batch-scoringdocker compose run --rm backend bashdocker compose run --rm ml-api bashdocker compose exec postgres shdocker compose exec postgres sh -lc 'psql -U "$POSTGRES_USER" -d "$POSTGRES_DB"'Если quoting в твоем shell неудобен, можно зайти через sh, а потом уже запустить:
psql -U retail -d retail_analyticsЭта команда удаляет локальные volumes PostgreSQL и Redis.
docker compose down -v
docker compose up -d --buildПосле этого clean.*, mart.*, feature.* и serving.* нужно собирать заново.
pytest -q -s tests/test_backend_health.py tests/test_ml_api_health.pyruff check .ruff format .Работает в:
apps/backend/
Не лезет в:
- ETL ingestion
- SQL витрины
- training logic
Работает в:
apps/ml_api/jobs/train/jobs/batch_scoring/sql/feature/sql/serving/
Работает в:
jobs/etl/jobs/marts_builder/jobs/feature_builder/sql/clean/sql/mart/sql/feature/
Работает в:
infra/superset/sql/mart/sql/serving/
Работает в:
apps/frontend/
После того как clean.* уже собран через ETL, следующий человек работает так:
- Открывает SQL-файлы в
sql/mart/ - Реализует витрины, например:
sql/mart/mart_sales_daily.sqlsql/mart/mart_customer_360.sql
- Прогоняет mart job или выполняет SQL вручную в Postgres
- Проверяет результат через
psqlили Superset
То есть разработчик витрин не должен трогать:
- Alembic
- raw CSV ingestion
- backend API
Его зона ответственности — mart.* как reusable analytical layer поверх clean.*
- Alembic используется только для foundational DDL
- аналитическая логика живет в
sql/ - raw CSV остаются на диске
- backend и BI в норме читают
martиserving clean.*должен быть явным, обозримым и воспроизводимым- prefer boring, explicit, maintainable structure over clever abstractions