Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Velotor Ride

Telegram-бот + сайт статистики велоклубу: учасники надсилають кілометраж у чат, бот рахує рейтинги, тижневі та річні підсумки й внутрішню валюту Torcoins; сайт показує поточний тиждень, архів, річні рейтинги та профілі учасників.

Це новий проєкт з чистою архітектурою. Старий PHP-проєкт з тією ж назвою використовувався лише як референс бізнес-логіки під час проєктування - код з нього не переносився.

Стек

Laravel 11 (PHP) + Vue 3 + Inertia.js + Tailwind CSS v4 + MySQL. Повне обґрунтування — STACK_DECISION.md. Опис архітектури — PROJECT_PLAN.md. Інструкції по деплою на VPS — DEPLOYMENT.md.

Встановлення (локально)

Вимоги: PHP 8.2+, Composer, Node.js 18+/npm, MySQL.

composer install
npm install

cp .env.example .env
php artisan key:generate

Налаштування .env

Відредагувати:

DB_DATABASE=velotor_ride
DB_USERNAME=root
DB_PASSWORD=

VELOTOR_TIMEZONE=Europe/Kyiv

TELEGRAM_BOT_TOKEN=       # токен від @BotFather
TELEGRAM_WEBHOOK_SECRET=  # будь-який довгий випадковий рядок
TELEGRAM_CHAT_ID=         # id чату клубу для тижневих звітів

Створити базу даних (MySQL має вже бути запущений):

mysql -u root -e "CREATE DATABASE velotor_ride CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"

Міграції та демо-дані

php artisan migrate --seed

Сидер створює: адмін-акаунт (admin@velotor.ride / passwordобов'язково змінити пароль на проді), базові налаштування, ~14 учасників і суцільний ланцюжок тижнів за останні ~60 тижнів (з переходом через Новий рік) із випадковими результатами — щоб інтерфейс одразу був наповнений даними.

Запуск локально

composer run dev

Ця команда одночасно піднімає php artisan serve, чергу (queue:listen — не використовується логікою проєкту, але йде в комплекті зі стандартним скриптом Laravel), логи (pail) і Vite dev-сервер. Сайт буде доступний на http://localhost:8000.

Щоб локально перевірити закриття тижня без очікування понеділка, просто викликайте команду вручну: php artisan week:close.

Якщо потрібен лише сайт без hot-reload:

npm run build
php artisan serve

Логіка тижнів і років

Тиждень клубу — окрема сутність weekly_periods, а не голий номер: у неї є start_date/end_date (понеділок 00:00 → наступний понеділок 00:00 за VELOTOR_TIMEZONE), і саме діапазон дат визначає "поточний тиждень", а не лічильник. Пара (year, week_number) унікальна; при переході через Новий рік week_number автоматично скидається на 1, а year — оновлюється, без ручного втручання. Усі результати завжди прив'язані до weekly_period_id (FK) — це структурно виключає змішування даних різних років на стику тижня 1.

Щопонеділка о 00:00 (php artisan week:close, через Laravel Scheduler) система: рахує підсумки активного тижня, формує топ-5, надсилає звіт у Telegram, закриває тиждень і відкриває наступний. Дія ідемпотентна: якщо scheduler випадково запуститься двічі поспіль, повторний виклик нічого не зробить (звіт не продублюється).

Torcoins

Torcoins нараховуються пропорційно дистанції: 100 км = 1 Torcoin. Перший учасник із результатом у кожному новому тижні додатково отримує 0.1 Torcoin. Баланс рахується окремо за весь час і за поточний рік.

Telegram-бот

Розпізнає повідомлення виду результат 10, результат 10 км, результат 10.5, результат 10,5, result 10, +10 км (крапка або кома як розділювач, одиниця виміру необов'язкова після ключового слова). Усі інші повідомлення в чаті ігноруються. Команди: /start, /help, /me, /top, /week, /year, /alltime, /admin.

/admin відкриває кнопки для ручного додавання результату за поточний або попередній тиждень, фіксації тижня та відкату останньої фіксації. Доступ мають адміністратори Telegram-чату. Для роботи в приватному чаті можна вказати їхні Telegram user ID через кому в TELEGRAM_ADMIN_IDS.

Налаштування вебхука

Локально Telegram не може достукатись до localhost напряму — для розробки використовуйте тунель (ngrok/Cloudflare Tunnel) і вкажіть публічну URL:

curl -X POST "https://api.telegram.org/bot<TOKEN>/setWebhook" \
  -d "url=https://<ваш-домен-або-тунель>/telegram/webhook" \
  -d "secret_token=<TELEGRAM_WEBHOOK_SECRET>"

Для продакшену — див. DEPLOYMENT.md.

Налаштування cron

* * * * * cd /path/to/project && php artisan schedule:run >> /dev/null 2>&1

Перевірити, що команда закриття тижня запланована:

php artisan schedule:list

Адмінка

/admin/login (сидер створює admin@velotor.ride / password). Дозволяє: переглядати учасників і результати, редагувати/видаляти помилковий результат (з автоматичним перерахунком статистики тижня), запускати повний перерахунок статистики, дивитись логи Telegram-бота, дивитись статус поточного тижня і закривати його вручну, змінювати telegram_chat_id та часовий пояс.

Тести

php artisan test

83 тести (unit + feature) покривають: розпізнавання всіх форматів результату, захист від дублів, розрахунок Torcoins, логіку тижнів/років (включно з переходом через Новий рік), ідемпотентність закриття тижня, Telegram-вебхук (усі команди, некоректні payload, перевірку секретного токена), публічні сторінки сайту та адмінку.

Як перевірити, що бот працює

  1. Написати боту /start у чаті — має відповісти коротким описом.
  2. Написати результат 15 км — бот має відповісти підсумком (км за тиждень/усього/Torcoins) і зберегти результат.
  3. Написати щось не по темі — бот не повинен відповідати взагалі.
  4. /me, /top, /week, /year, /alltime — мають відповідати коротким рейтингом/статистикою.
  5. /admin/bot-logs — кожне повідомлення має з'явитись у логах зі статусом ok/ignored/error.

Як перевірити закриття тижня

php artisan week:close

Перший запуск закриває активний тиждень (якщо він уже закінчився, або завжди — через адмінку з примусовим закриттям), надсилає звіт у TELEGRAM_CHAT_ID і створює наступний тиждень. Повторний виклик одразу після цього нічого не робить — це і є ідемпотентність, покрита тестом WeeklyCloseActionTest.

About

Telegram bot for tracking cycling club statistics, ride distances, and weekly leaderboards. Built with pure PHP and Telegram Bot API for the «VeloTor» community.

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Contributors

Languages