ИИ-программа лояльности с персональными челленджами, прогрессией аватара и отслеживанием экономии.
/x5mobile— мобильное приложение на React Native + Expo (iOS/Android)/web— Python бэкенд (FastAPI + PostgreSQL)
web/
├── pyproject.toml # Зависимости (Poetry)
├── poetry.lock
├── alembic.ini # Конфиг Alembic
├── alembic/
│ ├── env.py # Читает Base из entities, DATABASE_URL из env
│ └── versions/ # Ревизии миграций
└── src/webx5/
├── main.py # Точка входа: load_dotenv + logging + uvicorn
├── core/
│ ├── db.py # Инстанс Database
│ ├── server.py # FastAPI app + роутеры
│ └── logging_config.py
├── database/
│ └── database.py # class Database (get_db, get_sync_session)
├── entities/ # SQLAlchemy DeclarativeBase + таблицы
├── crud/ # Репозитории (доступ к данным)
├── services/ # Бизнес-логика
├── routes/ # FastAPI endpoints
│ └── health.py # GET /health
├── schemas/ # Pydantic request/response модели
├── dependencies/
│ └── db.py # SessionDep
└── utils/
tests/webx5/
└── routes/
└── test_health.py
- Docker Desktop установлен и запущен
# 1. Скопировать .env (значения по умолчанию работают без правок)
cp .env.example .env
# 2. Собрать и запустить весь стек (db + redis + web + mobile + worker + beat)
docker compose up --build
# Для работы AI-ассистента корзины (POST /basket/assistant) нужен реальный
# OPENROUTER_API_KEY в .env — с плейсхолдером по умолчанию этот один
# эндпоинт не работает, остальное приложение — без изменений.
# API: http://localhost:8000
# Мобильный UI: http://localhost:8080 (Expo Web в рамке телефона)
# Проверка: curl http://localhost:8000/health → {"status":"ok"}
# Документация: http://localhost:8000/docs (Scalar UI)
# GET /challenges/current → 4 персональных задания пользователя (Bearer JWT)
# GET /points/balance → баланс кешбека (Bearer JWT)
# POST /receipts с полем points_to_spend → списание баллов при оплатеНаграда за выполненное задание начисляется в баллах (не в скидке) по тому же курсу, что и
списание: points = round(reward_rub * rate / 10) * 10, где rate — PointsSettings.rate_points_per_rub
(singleton, по умолчанию 10). Баллы можно тратить при оплате чека — их конвертация в рубли идёт
по тому же курсу. Кешбек засчитывается как экономия и суммируется со скидочной экономией в
GET /receipts/economy. Детали — в specs/007-cashback-points/.
docker compose up -d # Запуск в фоне
docker compose down # Остановить стек
docker compose down -v # Остановить и удалить данные БД
docker compose logs -f web # Логи веб-сервера
docker compose build # Пересобрать образ без запускаМиграции БД применяются автоматически при каждом старте контейнера.
x5mobile собирается как статический Expo Web и отдаётся nginx на http://localhost:8080.
Телефон на демо не нужен: интерфейс открывается в браузере.
Режим в .env / compose: MOBILE_LAYOUT=phone (рамка телефона) или MOBILE_LAYOUT=fullscreen
(на весь браузер). Смена режима — перезапуск контейнера, без пересборки:
# рамка телефона (по умолчанию)
MOBILE_LAYOUT=phone docker compose up -d mobile
# весь экран
MOBILE_LAYOUT=fullscreen docker compose up -d mobileЗапросы к API идут на тот же origin: nginx проксирует /login, /receipts, /basket и остальные
бэкенд-пути на сервис web. Менять EXPO_PUBLIC_API_URL и пересобирать клиент не нужно.
# только клиент, если бэкенд уже поднят
docker compose up --build mobile
# другой порт
MOBILE_PORT=19006 docker compose up --build mobileЛокально без Docker: cd x5mobile && npm install && npm run web
(тогда в x5mobile/.env оставь EXPO_PUBLIC_API_URL=http://localhost:8000).
Все скрипты идемпотентны: повторный запуск не создаёт дубликатов.
docker compose run --rm --entrypoint python \
-v "/абсолютный/путь/к/unique_products.json:/tmp/products_data.json" \
-e SEED_FILE_PATH=/tmp/products_data.json \
web scripts/seed_products.pydocker compose run --rm --entrypoint python \
-e SEED_FILE_PATH=/data/dataset \
web scripts/seed_stores.pyСканирует датасет и создаёт StoreFormat на каждую сеть и Store на каждую (сеть, район) пару.
docker compose run --rm --entrypoint python \
-e SEED_FILE_PATH=/data/dataset \
web scripts/seed_discounts.pyСоздаёт Discount записи для каждой уникальной пары (категория, процент скидки) из промо-товаров.
# Все пользователи (10 000, медленно)
docker compose run --rm --entrypoint python \
-e SEED_FILE_PATH=/data/dataset \
web scripts/seed_receipts.py
# Ограниченная выборка (рекомендуется для теста)
docker compose run --rm --entrypoint python \
-e SEED_FILE_PATH=/data/dataset \
-e SEED_LIMIT=100 \
web scripts/seed_receipts.pyТребует предварительного запуска seed_products.py, seed_stores.py и seed_discounts.py. Также создаёт
Userна каждую синтетическую карту лояльности и в конце печатает несколько демо-логинов (user_id=... phone=...) — по этому телефону можно залогиниться (POST /login) пользователем с реальной историей покупок.
# Магазины: X5-сети × московские округа (24 магазина)
docker compose exec web python scripts/generate_stores.py
# Скидки: акции / лояльность / персональные / уценки (47 записей)
docker compose exec web python scripts/generate_discounts.pyСкрипты идемпотентны и не требуют файла датасета — данные захардкожены. Запускать в порядке: сначала
generate_stores, затемgenerate_discounts(скидки типаby_formatссылаются на форматы магазинов).
seed_products → seed_stores → seed_discounts → seed_receipts → seed_task_statusdocker compose run --rm --entrypoint python web scripts/seed_task_status.pyИдемпотентен. Создаёт 4 строки в
task_status: открыто / выполнено / провалено / истекло.
- Python >= 3.12
- Poetry (
pip install poetry) - PostgreSQL (локально или через Docker)
# 1. Скопировать и заполнить .env
cp .env.example .env
# Отредактировать DATABASE_URL в .env
# 2. Установить зависимости
cd web
poetry install
# 3. Применить миграции
poetry run alembic upgrade head
# 4. Запустить сервер
poetry run python -m webx5
# Сервер доступен на http://localhost:8000
# Проверка: curl http://localhost:8000/health → {"status":"ok"}- Node.js >= 18
- npm или yarn
- Xcode Command Line Tools (для iOS):
xcode-select --install
cd x5mobile
npm installnpm startЗатем выбери платформу:
- Нажми
iдля iOS Simulator - Нажми
aдля Android Emulator - Нажми
wдля веб-версии - Отсканируй QR-код приложением Expo Go (физическое устройство)
npm run ios # iOS Simulator
npm run android # Android Emulator
npm run web # Веб-браузер# Требует полной установки Xcode
cd x5mobile/ios
pod install
cd ..
eas build --platform iosx5mobile/
├── src/
│ ├── app/ # Страницы Expo Router
│ │ ├── _layout.tsx # Корневой layout
│ │ └── index.tsx # Экран приветствия
│ ├── components/ # Переиспользуемые компоненты
│ ├── constants/ # Тема, отступы, etc.
│ └── hooks/ # Кастомные React hooks
├── assets/ # Изображения, иконки, шрифты
├── app.json # Конфиг Expo
├── tsconfig.json # Конфиг TypeScript
└── package.json # Зависимости и скрипты
Уже настроено в .gitignore:
node_modules/— зависимости.env*.local— переменные окруженияios/,android/— сгенерированные нативные папки*.p8,*.p12,*.mobileprovision— сертификаты подписи.DS_Store,*.pem— системные/SSL файлы
Секретов, API ключей и больших файлов не найдено ✓
- Expo — фреймворк для кроссплатформенной разработки
- React Native — фреймворк для мобильного UI
- Expo Router — файловая маршрутизация (как Next.js)
- React Native Reanimated — плавные анимации
- TypeScript — типизация
Горячая перезагрузка:
- Измени любой файл в
src/→ автоматическая перезагрузка в эмуляторе/устройстве - Для изменений нативного кода нужна пересборка
Меню отладки (в Simulator/Emulator):
- iOS:
cmd+d - Android:
cmd+m
claude code
(Паша) для работы со спеккитом юзайте команду ниже
specify init --here --integration claude
без нее, но с указанием пути до репо спеккита у меня не работало + с указнием пути до репо я бы не коммитил .claude/settings.json