Задача
TotoMondiale — бесплатная игра-прогноз, которую я провожу на крупных футбольных турнирах с середины 2000-х. В её зале славы — TotoEuropeo 2008, TotoEuropeo 2012, TotoMondiale 2014 и TotoEuropeo 2016. Правила почти не менялись: на каждый матч вы заполняете купон, очки начисляются по коэффициентам, а все купоны публикуются до начала матча, чтобы никто не мог сжульничать. Старый сайт на классическом ASP не мог дать игрокам того, чего они теперь ждут: частных лиг с друзьями, удобной версии для телефона и живых результатов. К чемпионату мира 2026 года я полностью его переписал.
Что я сделал
Новую платформу на Node.js, которая сохраняет старые правила и добавляет лиги, живые данные и немного азарта.
- Купон из 9 позиций: итоговый результат, первый тайм, «обе забьют / нет», тотал меньше/больше, пенальти, тайм/матч, чёт/нечет, точный счёт, общее число голов. Коэффициенты берутся из API-Football, а если их нет, применяются коэффициенты по умолчанию.
- Частные и открытые лиги: у каждой лиги своя таблица, баннер, новостная лента и чат.
- Особые карты: Sesto Senso даёт бонус за точный счёт, Malocchio отнимает очки у другого игрока, Cornicello отменяет Malocchio.
- Честная игра на уровне кода: купоны и карты других игроков скрыты, пока матч не заблокирован. Это правило действует и для администраторов платформы. Если кто-то забыл заполнить купон, система заполняет его случайным образом, как и предписывали исходные правила.
- Матчи в прямом эфире: фоновая задача каждые 30 секунд обращается к API-Football и обновляет счёт по ходу игры.
- Функции ИИ: Claude ежедневно составляет набор рекомендуемых прогнозов, а администраторы лиг могут создать баннер с помощью DALL-E 3 и короткую газету лиги с помощью OpenAI.
- Страницы турнира и языки: команды, стадионы, история, групповой этап и сетка плей-офф на пяти языках, со входом через Google.
Технологии
Node.js 20, Express 4, EJS, MySQL 8, Passport с Google OAuth, Nodemailer и ImapFlow, на Phusion Passenger под cPanel. Я выпускаю обновления небольшими шагами и каждый раз повышаю номер версии: сейчас код в версии 5.1.642, сборка 665. Прежние выпуски работали на классическом ASP с базами данных Access.
Почему именно так
Время начала матчей хранится в UTC, а смещение для отображения — отдельно. API-Football нужно настоящее время UTC, чтобы найти матч, а игроки хотят видеть итальянское время. Разделение этих двух значений исключает целый класс ошибок, когда матч блокируется на час раньше или позже.


