2026-05-12 20:11:12 +09:00
2026-05-12 20:11:12 +09:00
2026-05-12 04:07:52 +09:00
2026-05-12 03:52:13 +09:00
2026-05-12 03:52:13 +09:00
2026-05-12 03:52:13 +09:00
2026-05-12 19:45:08 +09:00

Drivers Bot

Telegram bot + Telegram Mini App для учета автомобилей, заправок, сервиса, жидкостей, напоминаний и стоимости владения.

Состав

  • app/ - FastAPI API, статика Mini App, бизнес-логика и Alembic.
  • bot/ - aiogram 3 бот, который открывает Mini App и работает с API через внутренний токен.
  • web/ - статический frontend Telegram WebApp.
  • alembic/ - миграции PostgreSQL.
  • tests/ - базовые security/API тесты.

Production Mini App

Для production Mini App должен открываться только по публичному HTTPS-домену. Для текущего проекта:

https://drivers.smartsoltech.kr

В BotFather нужно выполнить:

/setdomain
@your_bot_username
drivers.smartsoltech.kr

Важно:

  • в BotFather указывается домен без https://;
  • WEBAPP_URL или PUBLIC_WEBAPP_URL в .env должны быть https://drivers.smartsoltech.kr;
  • нельзя использовать localhost, 127.0.0.1, внутренний IP или http:// для Telegram Mini App в production;
  • если появляется Bot domain invalid, сначала проверь /setdomain и значение WEBAPP_URL в контейнере бота.

Production .env

POSTGRES_DB=drivers
POSTGRES_USER=drivers
POSTGRES_PASSWORD=change-this-db-password
POSTGRES_PORT=5433
DATABASE_URL=postgresql+asyncpg://drivers:change-this-db-password@db:5432/drivers

BOT_TOKEN=123456:telegram-token
BOT_USERNAME=your_bot_username
WEBAPP_URL=https://drivers.smartsoltech.kr
PUBLIC_WEBAPP_URL=https://drivers.smartsoltech.kr
API_BASE_URL=http://api:8000
CORS_ORIGINS=https://drivers.smartsoltech.kr,https://t.me
INTERNAL_API_TOKEN=change-this-long-random-token
APP_ENV=production
ALLOW_DEV_AUTH=false
VAPID_PUBLIC_KEY=

BOT_TOKEN, DATABASE_URL, WEBAPP_URL, API_BASE_URL, CORS_ORIGINS, INTERNAL_API_TOKEN читаются только из env. Секреты не хранятся в коде.

Nginx

Пример reverse proxy:

server {
    listen 80;
    server_name drivers.smartsoltech.kr;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name drivers.smartsoltech.kr;

    ssl_certificate /etc/letsencrypt/live/drivers.smartsoltech.kr/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/drivers.smartsoltech.kr/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_http_version 1.1;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }
}

Запуск

cp .env.example .env
docker compose up -d --build

API локально: http://localhost:8000.

Локальные проверки:

python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/pytest -q
.venv/bin/ruff check app bot tests
docker compose build
docker compose up -d db api
curl http://127.0.0.1:8000/health
docker compose down

Авторизация API

Пользовательские endpoint-ы требуют Telegram WebApp initData в заголовке:

X-Telegram-Init-Data: query_id=...&user=...&auth_date=...&hash=...

Backend проверяет подпись Telegram, создает/обновляет пользователя и разрешает операции только с объектами владельца. Бот использует INTERNAL_API_TOKEN и X-Telegram-User-Id.

Публичное /api/users закрыто внутренним токеном. Для Mini App создание пользователя выполняется через /api/users/webapp-auth.

Основные endpoint-ы

  • GET /api/users/me
  • GET /api/me
  • GET /api/my/vehicles
  • POST /api/my/vehicles
  • PATCH /api/my/vehicles/{vehicle_id}
  • GET /api/my/vehicles/{vehicle_id}/service-history
  • POST /api/my/vehicles/{vehicle_id}/grant-service-access
  • POST /api/cars, GET /api/cars, GET/PATCH/DELETE /api/cars/{id}
  • POST /api/fuel, GET /api/cars/{car_id}/fuel?limit=50&offset=0
  • PATCH /api/fuel/{id}, DELETE /api/fuel/{id}
  • POST /api/service, GET /api/cars/{car_id}/service?limit=50&offset=0
  • PATCH /api/service/{id}, DELETE /api/service/{id}
  • GET /api/cars/{car_id}/stats
  • GET /api/users/{user_id}/reminders?limit=50&offset=0
  • POST /api/service-centers
  • GET /api/service-centers/my
  • POST /api/service-centers/{id}/verification
  • POST /api/service-centers/{id}/employees/invite
  • GET /api/service-centers/{id}/visits
  • POST /api/service-centers/{id}/visits
  • POST /api/service-visits/{id}/work-items
  • POST /api/service-visits/{id}/complete
  • POST /api/service-visits/{id}/confirm
  • POST /api/service-visits/{id}/dispute
  • POST /api/service-visits/{id}/vehicle-change-requests
  • POST /api/vehicle-change-requests/{id}/approve
  • POST /api/vehicle-change-requests/{id}/reject
  • GET /api/admin/service-centers/pending
  • POST /api/admin/service-centers/{id}/verify
  • POST /api/admin/service-centers/{id}/reject
  • POST /api/admin/service-centers/{id}/suspend
  • GET /api/admin/audit-log
  • GET /api/admin/disputes
  • POST /api/ocr/parse-text-receipt
  • POST /api/ocr/license-plate
  • POST /api/ocr/vin
  • POST /api/ocr/service-document

Расход топлива считается по интервалам между полными баками (is_full_tank=true). Если данных мало, API возвращает null, а не выдуманную цифру.

OCR

Настоящий OCR по фото/PDF пока не подключен. Endpoint POST /api/ocr/parse-text-receipt честно разбирает только текстовый чек. Старый /api/ocr/fuel-receipt оставлен как deprecated-совместимость.

Новая OCR-архитектура использует заменяемый provider:

  • OCRProvider
  • StubOCRProvider
  • будущие TesseractOCRProvider, cloud OCR или VLM provider

OCR возвращает кандидаты и не меняет данные автомобиля напрямую:

{
  "recognized_text": "VIN KMHCT41BAHU123456",
  "candidates": [
    {"type": "vin", "value": "KMHCT41BAHU123456", "confidence": 0.84}
  ]
}

Platform Roadmap

Проектное расширение в сторону владельцев авто и СТО описано в PROJECT_PLAN.md. В код добавлен первый совместимый слой платформы:

  • расширенный ServiceCenter;
  • верификация СТО;
  • сотрудники СТО;
  • VehicleAccess;
  • ServiceVisit;
  • ServiceWorkItem;
  • VehicleDataChangeRequest;
  • AuditLog;
  • нормализация VIN и госномера.

СТО не получает персональные данные владельца по VIN/номеру. Поиск возвращает только минимальную маскированную карточку и пишет действие в аудит. Критичные изменения автомобиля проходят через запрос подтверждения владельцем.

Description
No description provided
Readme 1.9 MiB
Languages
Python 67.2%
JavaScript 20.4%
HTML 8%
CSS 3.8%
Shell 0.6%