savagedb_bot/wiki/Development.md

9.5 KiB
Raw Permalink Blame History

Подробное руководство для разработчиков SalvageDB Telegram Bot.

Архитектура бота

Бот построен на aiogram 3.x с Oracle Database для хранения данных о транспорте.

Основные компоненты

  • main.py - основная логика бота (1700+ строк)
  • db.py - класс для работы с Oracle DB (470+ строк)
  • middlewares/db.py - middleware для БД подключения

Схема работы

User Input → FSM States → Database Query → Response → Telegram API

Переменные окружения

Обязательные

BOT_TOKEN=токен_от_BotFather
BOT_NAME=имя_бота  
db_user=пользователь_oracle
db_password=пароль_oracle
db_dsn=строка_подключения_oracle
ADMIN_USER_ID=id_администратора

Опциональные

DEBUG=1                # Детальное логирование
DECODE_PRICE=1        # Цена декодирования (звезды)
CHECK_PRICE=10        # Цена проверки salvage (звезды)
IMG_PRICE=100         # Цена фотографий (звезды)

FSM Состояния

class VinStates(StatesGroup):
    waiting_for_vin = State()         # Ожидание VIN для декодирования
    waiting_for_check_vin = State()   # Ожидание VIN для проверки salvage
    waiting_for_photo_vin = State()   # Ожидание VIN для поиска фото

Переходы состояний

  • Startwaiting_for_vin (кнопка "Decode VIN")
  • Startwaiting_for_check_vin (кнопка "Check VIN")
  • Startwaiting_for_photo_vin (кнопка "Car photo")
  • Any StateStart (кнопка "Back to Main Menu")

Основные функции

Системные утилиты

def get_operating_system() -> str:
    """Возвращает: Windows, Linux, macOS или Unknown"""

def is_windows() -> bool:
def is_linux() -> bool: 
def is_macos() -> bool:
    """Быстрые проверки ОС"""

def log_system_info():
    """Логирует информацию о системе при запуске"""

Обработка данных

def get_us_state_name(state_code: str) -> str:
    """TX → Texas"""

def format_sale_date(date_str: str) -> str:
    """3/2023 → March 2023"""

def parse_location(location_str: str) -> str:
    """TX/DALLAS → Dallas, Texas"""

def escape_markdown(text: str) -> str:
    """Экранирует Markdown символы"""

Работа с фотографиями

def convert_photo_path(db_path: str) -> str:
    """
    Конвертирует путь БД в полный путь с учетом ОС:
    Windows: D:\SALVAGEDB\salvagedb_bot\images\20250530\vin\photo.jpg
    Linux: /images/20250530/vin/photo.jpg
    """

async def send_vehicle_photos(message, vin, photo_paths, make, model, year):
    """
    Отправляет фото группами по 10 штук
    - Пауза 0.5 сек между группами
    - Обработка ошибок для каждого фото
    - Итоговое сообщение с количеством
    """

Callback Handlers

Навигация

@dp.callback_query(lambda c: c.data == "decode_vin")
async def decode_vin_callback():
    """Переход в состояние waiting_for_vin"""

@dp.callback_query(lambda c: c.data == "check_vin") 
async def check_vin_callback():
    """Переход в состояние waiting_for_check_vin"""

@dp.callback_query(lambda c: c.data == "search_car_photo")
async def search_car_photo_callback():
    """Переход в состояние waiting_for_photo_vin"""

@dp.callback_query(lambda c: c.data == "main_menu")
async def main_menu_callback():
    """Возврат в главное меню, очистка состояния"""

Платежи (Telegram Stars)

@dp.callback_query(lambda c: c.data.startswith("pay_detailed_info:"))
async def pay_detailed_info_callback():
    """Payload: detailed_vin_info:{vin}, Цена: DECODE_PRICE"""

@dp.callback_query(lambda c: c.data.startswith("pay_check_detailed:"))
async def pay_check_detailed_callback():
    """Payload: detailed_salvage_check:{vin}, Цена: CHECK_PRICE"""

@dp.callback_query(lambda c: c.data.startswith("pay_photos:"))
async def pay_photos_callback():
    """Payload: vehicle_photos:{vin}, Цена: IMG_PRICE"""

Message Handlers

Команды

@dp.message(Command("start"))
async def command_start_handler():
    """Главное меню с кнопками:
    - Decode VIN
    - Check VIN
    - Car photo  
    - Help
    """

@dp.message(Command("admin_stats"))
async def admin_stats_handler():
    """Статистика для администратора (только ADMIN_USER_ID)"""

Обработка VIN

@dp.message(VinStates.waiting_for_vin)
async def process_vin_input():
    """
    Декодирование VIN:
    1. Валидация VIN (17 символов)
    2. Поиск в БД по VIN
    3. Базовая информация бесплатно
    4. Детальная информация за плату
    """

@dp.message(VinStates.waiting_for_check_vin)
async def process_check_vin_input():
    """
    Проверка salvage:
    1. Поиск записей о повреждениях
    2. Краткая сводка бесплатно
    3. Детальная информация за плату
    """

@dp.message(VinStates.waiting_for_photo_vin)
async def process_photo_vin_input():
    """
    Поиск фотографий:
    1. Поиск фото по VIN в БД
    2. Превью количества бесплатно
    3. Доступ к фото за плату
    """

База данных (db.py)

Основные методы

class Database:
    async def get_vehicle_info_by_vin(self, vin: str):
        """Базовая информация о транспорте"""
    
    async def get_detailed_vehicle_info(self, vin: str):
        """Детальная информация за плату"""
    
    async def check_salvage_records(self, vin: str):
        """Проверка записей о повреждениях"""
    
    async def get_vehicle_photos(self, vin: str):
        """Получение путей к фотографиям"""
    
    async def save_user(self, user: User, interaction_source: str):
        """Сохранение пользователя для аналитики"""
    
    async def update_user_payment(self, user_id: int, amount: float):
        """Обновление платежных данных"""

Система платежей

Telegram Stars Integration

# Создание платежа
invoice = LabeledPrice(label=description, amount=price)
await message.answer_invoice(
    title=f"Pay {price} ⭐️",
    description=description,
    payload=payload,
    provider_token="",  # Telegram Stars
    currency="XTR",
    prices=[invoice]
)

# Обработка успешного платежа
@dp.pre_checkout_query()
async def pre_checkout_handler(query: PreCheckoutQuery):
    await query.answer(ok=True)

@dp.message(ContentType.SUCCESSFUL_PAYMENT)
async def successful_payment_handler(message: Message):
    # Обработка по payload

Автоматические пути

Система автоматически определяет пути к изображениям:

# Windows
image_path = "D:\\SALVAGEDB\\salvagedb_bot\\images"

# Linux/Docker
image_path = "/images/"

Развертывание для разработки

1. Настройка окружения

# Установка зависимостей
uv install

# Копирование конфигурации
cp env.example .env
# Отредактируйте .env с вашими данными

2. Запуск с автоперезагрузкой

uv run -m watchfiles --filter python 'uv run main.py'

3. Отладка

# Включение DEBUG режима
export DEBUG=1

# Проверка подключения к БД
python -c "from db import Database; import asyncio; asyncio.run(Database().test_connection())"

Middleware

DatabaseMiddleware

# middlewares/db.py
class DatabaseMiddleware:
    """Передает подключение к БД в handlers"""
    
    async def __call__(self, handler, event, data):
        data["db"] = Database()
        return await handler(event, data)

Структура проекта

salvagedb_bot/
├── main.py              # Основная логика (1714 строк)
├── db.py                # База данных (475 строк)
├── middlewares/
│   └── db.py           # Database middleware
├── .gitea/workflows/   # CI/CD конфигурация
├── logs/               # Логи приложения
├── images/             # Фотографии автомобилей
└── requirements.txt    # Python зависимости

Связанные страницы