baton/README.md

166 lines
6.5 KiB
Markdown
Raw Normal View History

# Baton — Экстренный сигнал
PWA-приложение для отправки экстренных сигналов с геолокацией через Telegram-бота.
## Стек
- **Backend:** Python 3.12+, FastAPI, aiosqlite, httpx
- **Frontend:** Vanilla JS PWA (Service Worker, Web Push)
- **База данных:** SQLite (WAL mode)
- **Уведомления:** Telegram Bot API
## Запуск
```bash
# Зависимости
pip install -r requirements.txt
# Переменные окружения (см. .env.example)
cp .env.example .env
# Запуск
uvicorn backend.main:app --host 0.0.0.0 --port 8000
```
## Переменные окружения
| Переменная | Обязательна | Описание |
|---|---|---|
| `BOT_TOKEN` | да | Токен Telegram-бота |
| `CHAT_ID` | да | ID чата для уведомлений |
| `WEBHOOK_SECRET` | да | Секрет для верификации Telegram webhook |
| `WEBHOOK_URL` | да | Публичный URL `/api/webhook/telegram` |
| `DB_PATH` | нет | Путь к SQLite-файлу (по умолчанию `baton.db`) |
| `FRONTEND_ORIGIN` | нет | Разрешённый origin для CORS (по умолчанию `http://localhost:3000`) |
| `WEBHOOK_ENABLED` | нет | Регистрировать webhook при старте (по умолчанию `true`) |
| `APP_URL` | нет | Публичный URL приложения для keep-alive (например `https://baton.fly.dev`) |
## API
| Метод | Путь | Описание |
|---|---|---|
| `GET` | `/health` | Health check: `{"status": "ok", "timestamp": <unix_ts>}` |
| `POST` | `/api/register` | Регистрация пользователя |
| `POST` | `/api/signal` | Отправка экстренного сигнала |
| `POST` | `/api/webhook/telegram` | Telegram webhook |
## Hosting & Keep-Alive
### Проблема cold start
На бесплатных хостингах (Render, fly.io free tier, Railway и подобных) приложение **засыпает** после периода неактивности (обычно 1530 минут). Следующий входящий запрос ждёт пока процесс поднимется заново — **cold start занимает 35 секунд**. Для экстренного приложения это критично.
### Решения по вариантам хостинга
| Вариант | Стоимость | Cold start | Рекомендация |
|---|---|---|---|
| **fly.io Hobby** | $5/мес | Нет (всегда активен) | Оптимально для прода |
| **fly.io free tier** | Бесплатно | 35 сек | Только для разработки |
| **Render free** | Бесплатно | 35 сек | Только для разработки |
| **Самохостинг (VPS)** | От $35/мес | Нет | Полный контроль |
> **Финальный выбор хостинга зависит от решения по OQ-004** (открытый вопрос по бюджету и масштабированию проекта).
### Keep-alive механизм (asyncio background task)
Приложение запускает фоновый asyncio-таск, который каждые **10 минут** пингует собственный `/health` endpoint. Это предотвращает засыпание на платформах, которые реагируют на активность процесса.
**Активация:** установите переменную `APP_URL`:
```bash
APP_URL=https://your-app.fly.dev
```
Без `APP_URL` таск не запускается (keep-alive отключён).
**Ограничение:** self-ping работает пока процесс жив. Если платформа убивает процесс при нулевом трафике — нужен внешний пингер (см. ниже).
### Keep-alive для самохостинга (cron / systemd timer)
Если приложение на VPS и нужен мониторинг извне:
**Вариант 1 — crontab:**
```bash
# Редактируем cron
crontab -e
# Добавляем запись (каждые 10 минут):
*/10 * * * * curl -sf https://your-app.example.com/health > /dev/null
```
**Вариант 2 — systemd timer:**
Создайте два файла:
`/etc/systemd/system/baton-keepalive.service`:
```ini
[Unit]
Description=Baton keep-alive ping
[Service]
Type=oneshot
ExecStart=curl -sf https://your-app.example.com/health
```
`/etc/systemd/system/baton-keepalive.timer`:
```ini
[Unit]
Description=Run Baton keep-alive every 10 minutes
[Timer]
OnBootSec=1min
OnUnitActiveSec=10min
[Install]
WantedBy=timers.target
```
Активация:
```bash
systemctl daemon-reload
systemctl enable --now baton-keepalive.timer
systemctl list-timers baton-keepalive.timer
```
## Nginx deployment
Для проксирования через nginx используйте готовый шаблон `nginx/baton.conf`.
### Применение
```bash
# 1. Скопировать шаблон и заменить домен
sudo cp nginx/baton.conf /etc/nginx/sites-available/baton
sudo sed -i 's/<YOUR_DOMAIN>/baton.example.com/g' /etc/nginx/sites-available/baton
# 2. Получить TLS-сертификат (если ещё нет)
sudo certbot certonly --nginx -d baton.example.com
# 3. Включить конфиг
sudo ln -s /etc/nginx/sites-available/baton /etc/nginx/sites-enabled/baton
# 4. Проверить и применить
sudo nginx -t && sudo systemctl reload nginx
```
### Защита BOT_TOKEN в логах
Конфиг включает `map`-блок, который автоматически маскирует токен бота в `access_log`:
```
# В логе вместо реального токена:
GET /bot<TOKEN>/sendMessage → GET /bot[REDACTED]/sendMessage
```
Это защита по принципу «defence in depth»: текущий webhook-эндпоинт (`/api/webhook/telegram`) токен в URL не содержит, но маскировка сработает, если в будущем появится маршрут вида `/bot<TOKEN>/...`.
Заголовок `X-Telegram-Bot-Api-Secret-Token` не попадает в `access_log` — nginx не логирует заголовки запросов в стандартном `log_format`.
## Тесты
```bash
pip install -r requirements-dev.txt
pytest
```