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/meGET /api/meGET /api/my/vehiclesPOST /api/my/vehiclesPATCH /api/my/vehicles/{vehicle_id}GET /api/my/vehicles/{vehicle_id}/service-historyPOST /api/my/vehicles/{vehicle_id}/grant-service-accessPOST /api/cars,GET /api/cars,GET/PATCH/DELETE /api/cars/{id}POST /api/fuel,GET /api/cars/{car_id}/fuel?limit=50&offset=0PATCH /api/fuel/{id},DELETE /api/fuel/{id}POST /api/service,GET /api/cars/{car_id}/service?limit=50&offset=0PATCH /api/service/{id},DELETE /api/service/{id}GET /api/cars/{car_id}/statsGET /api/users/{user_id}/reminders?limit=50&offset=0POST /api/service-centersGET /api/service-centers/myPOST /api/service-centers/{id}/verificationPOST /api/service-centers/{id}/employees/inviteGET /api/service-centers/{id}/visitsPOST /api/service-centers/{id}/visitsPOST /api/service-visits/{id}/work-itemsPOST /api/service-visits/{id}/completePOST /api/service-visits/{id}/confirmPOST /api/service-visits/{id}/disputePOST /api/service-visits/{id}/vehicle-change-requestsPOST /api/vehicle-change-requests/{id}/approvePOST /api/vehicle-change-requests/{id}/rejectGET /api/admin/service-centers/pendingPOST /api/admin/service-centers/{id}/verifyPOST /api/admin/service-centers/{id}/rejectPOST /api/admin/service-centers/{id}/suspendGET /api/admin/audit-logGET /api/admin/disputesPOST /api/ocr/parse-text-receiptPOST /api/ocr/license-platePOST /api/ocr/vinPOST /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:
OCRProviderStubOCRProvider- будущие
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/номеру. Поиск возвращает только минимальную маскированную карточку и пишет действие в аудит. Критичные изменения автомобиля проходят через запрос подтверждения владельцем.