Учёт таблеток и прививок собаки: Rust-бэкенд (API + Telegram-бот + iCal) и десктоп-клиент на Tauri.
Бэкенд для учёта таблеток и прививок собаки (Rust). Лёгкий бинарь для Raspberry Pi:
- PostgreSQL как основной источник данных.
- HTTP API на axum с защитой через service-токен (для десктоп-клиента и интеграций).
- Telegram-бот для семейных напоминаний и подтверждений.
- iCal-подписка для Google Calendar / Apple Calendar.
- CSV-отчёт с датами, когда дозы были приняты.
Раньше проект был на Python (FastAPI + aiogram); переписан на Rust ради меньшего
потребления памяти. Исходный код — в каталоге server/.
axum · sqlx (PostgreSQL) · teloxide · chrono/chrono-tz · icalendar — всё на rustls (без OpenSSL).
server/— Rust-бэкенд: HTTP API (axum), Telegram-бот, iCal, шедулер.desktop/— десктоп-клиент на Tauri 2 + Vue 3 (см.desktop/README.md).scripts/— вспомогательные скрипты (например,set-version.sh)..github/workflows/— CI (ci.yml) и сборка релизов (release.yml).
copy .env.example .env # затем впишите SERVICE_TOKEN и TELEGRAM_BOT_TOKEN
docker compose up -d postgres
cd server
cargo runОткрыть:
- API health:
http://localhost:8000/health - ссылка календаря: команда бота
/calendarилиGET /api/v1/households/{id}/calendar-url
Нужен Rust (stable). Сборка релиза: cargo build --release — бинарь в
server/target/release/corgitrack.
copy .env.example .env
docker compose up --buildПриложение доступно на http://localhost:8000. Внутри Compose база — хост postgres,
при локальном cargo run в .env оставьте localhost.
Для Raspberry Pi (arm64) образ собирается прямо на устройстве (docker compose up --build) или кросс-сборкой: docker buildx build --platform linux/arm64 ./server.
При старте сервис идемпотентно создаёт типы/таблицы/индексы
(server/migrations/0001_bootstrap.sql) — повторяет схему прежней Python-версии,
поэтому существующую базу на Pi можно использовать без потери данных.
Можно через защищённый API (см. ниже) или SQL:
insert into households (name, calendar_token) values ('Семья', md5(random()::text));
insert into dogs (household_id, name)
select id, 'Корги' from households where name = 'Семья';
insert into family_members (household_id, display_name, telegram_user_id)
select id, 'Я', 111111111 from households where name = 'Семья';
insert into treatments
(dog_id, name, kind, dose_label, cycle_days, start_at, reminder_time, instructions, active)
select d.id, 'Таблетка от паразитов', 'pill', '1 таблетка', 90, now(), '09:00', 'Дать после еды', true
from dogs d
join households h on h.id = d.household_id
where h.name = 'Семья';cycle_days задаёт период приёма. Прививки — та же модель с kind = 'vaccine' и
обычно более длинным циклом.
| Переменная | По умолчанию | Назначение |
|---|---|---|
DATABASE_URL |
postgres://corgitrack:corgitrack@localhost:5432/corgitrack |
строка подключения (схема postgres://) |
SERVICE_TOKEN |
change-me |
Bearer-токен для /api/v1/** |
PUBLIC_BASE_URL |
http://localhost:8000 |
базовый URL в ссылках календаря |
APP_TIMEZONE |
Europe/Astrakhan |
таймзона для расчёта времени приёма |
BIND_ADDR |
0.0.0.0:8000 |
адрес HTTP-сервера |
TELEGRAM_BOT_TOKEN |
— | если пусто, бот отключён |
TELEGRAM_API_SERVER_URL |
https://tgproxy.advsrvone.pw/ |
кастомный Bot API server; очистите для прямого доступа |
RUST_LOG |
info |
уровень логирования |
Тайминги эскалации, окно напоминаний и период шедулера вынесены из env в БД (таблица
app_settings) и правятся на лету черезGET/PATCH /api/v1/settings— см. ниже. Шедулер перечитывает их каждый тик, перезапуск не нужен.
Публичные (без токена):
GET /healthGET /calendar/{token}.ics— iCal-подписка поcalendar_tokenсемьиGET|POST /api/doses/{id}/taken?key=…— отметка приёма по ссылке из календаря
Защищённые — заголовок Authorization: Bearer <SERVICE_TOKEN>, префикс /api/v1:
households·dogs·members·treatments— CRUD (GETсписок,POSTсоздать,GET|PATCH|DELETE /{id})GET /doses?household_id=&from=&to=&status=— список дозPOST /doses/{id}/status— тело{ "status": "taken|skipped|...", "note"?, "member_id"? }GET /households/{id}/due?lookahead_hours=24— ближайшие дозыGET /households/{id}/report.csv— CSV принятых дозGET /households/{id}/calendar-url— готовая ссылка iCalGET /settings— текущие операционные настройки (тайминги эскалации и т.д.)PATCH /settings— частичное обновление настроек; тело, например,{ "escalation_first_delay_minutes": 30, "escalation_step_minutes": 5, "reminder_lookahead_minutes": 30, "scheduler_tick_seconds": 60 }
Пример:
curl -H "Authorization: Bearer $SERVICE_TOKEN" http://localhost:8000/api/v1/householdsCORS разрешён для всех источников (включая будущий десктоп на Tauri).
По умолчанию клиент ходит через кастомный Bot API server
(TELEGRAM_API_SERVER_URL).
/start— привязывает Telegram-пользователя, если его ID уже есть вfamily_members.telegram_user_id; иначе бот сообщает ваш ID./today— дозы, которые скоро нужно принять (с кнопкой «Принято»)./calendar— ссылка iCal для Google/Apple Calendar./report— CSV с датами принятых доз.
Напоминания рассылаются не всем сразу, а по очереди — в порядке
family_members.escalation_order (0 уведомляется первым). Шаги:
- В момент приёма первое напоминание получает только участник с
escalation_order = 0. - Если за
escalation_first_delay_minutes(по умолчанию 30 мин) никто не нажал «Принято» — тому же участнику приходит повторный вопрос. - Далее каждые
escalation_step_minutes(по умолчанию 5 мин) уведомляется следующий участник по списку. - Когда список исчерпан, доза помечается пропущенной (
missed), а первому участнику уходит уведомление об этом.
Любое нажатие «Принято» закрывает дозу и останавливает эскалацию для всей семьи.
Учитываются только участники с notify = true и заданным telegram_user_id.
Тайминги (escalation_first_delay_minutes, escalation_step_minutes,
reminder_lookahead_minutes, scheduler_tick_seconds) хранятся в таблице
app_settings и правятся через PATCH /api/v1/settings без перезапуска сервиса.
cd server
cargo testЮнит-тесты (server/tests/schedules.rs) проверяют расчёт времени приёма и ссылки
календаря и не требуют базы данных.
MVP использует ссылку подписки iCal — работает в Apple/Google Calendar без OAuth. Telegram остаётся интерфейсом для действий «принято»/«пропущено».
Issues и pull request'ы приветствуются! Перед началом загляните в:
- CONTRIBUTING.md — настройка окружения, стиль кода и процесс PR.
- CODE_OF_CONDUCT.md — правила общения в проекте.
- SECURITY.md — как сообщить об уязвимости.
Коротко: форкните репозиторий, создайте ветку, убедитесь, что cargo fmt --all --check,
cargo clippy --all-targets -- -D warnings и cargo test проходят, и откройте PR с описанием.
MIT © Sergey Novik