Skip to content

Repository files navigation

endpoint-robot

Бот и мини-приложение хакерспейса Endpoint. Гость оставляет заявку на визит, резидент видит её и хостит; в чате висит доска «кто сегодня в спейсе», в личке бот отмечает присутствие, собирает взносы и показывает статус 3D-принтера.

Бэкенд — TypeScript + mtcute, мини-апп — React + Vite. Весь стейт лежит в одном JSON-файле, базы нет.

Бот отвечает только в чатах из ALLOWED_CHATS, в остальных молчит. Резидент — участник чата RESIDENTS_CHAT_ID.

Мини-апп

Главная поверхность: всё про визиты, ивенты, взносы и статистику живёт здесь, а не в командах. Открывается кнопкой рядом с полем ввода в личке, ссылкой под доской в чате и из меню /start. Авторизация — подпись initData, ни паролей, ни сессий. Оформление — светлая и тёмная темы, свайп-действия по строкам, свой пикер времени вместо нативного.

Гостю

  • Заявка на визит — день из ближайших семи, время и цель. Перед первой заявкой — правила спейса.
  • Мои визиты — статус каждой заявки: ждём резидента или кто именно хостит. Прошедшие визиты остаются в списке.
  • Перенос — резидент может предложить другой день или время, гость соглашается или предлагает своё; так же двигается уже подтверждённый визит.
  • Напоминание — за полчаса, час, два часа, утром в день визита или вечером накануне. Гость выбирает сам, по умолчанию — за два часа; под напоминанием кнопка «Не смогу прийти».
  • В календарь.ics на подтверждённый визит по подписанной ссылке.
  • «Я на месте» — кнопка появляется вокруг времени визита: жмёшь у двери, и бот пишет хосту, а если хоста нет внутри — всем, кто сейчас отмечен в спейсе.
  • Как пройти — адрес с копированием, ближайшее метро, фото двери подъезда и карта.
  • Активность — ивенты ближайших дней и кто на них придёт.

Резиденту

  • Обзор на неделю и экран дня: заявки, «Захостить», отметка «я приду», ивенты дня.
  • Свайп по заявке — заметка о госте (общая память резидентов), предложить перенос, закрыть заявку, заблокировать гостя.
  • Ивенты — то, ради чего в спейс приходят вместе: воркшоп, ремонт-кафе, демо-день. Название, описание, афиша и тумблер «только резидентам». Второй вход — переслать боту в личку пост из канала анонсов: бот разберёт текст с картинкой и откроет редактор с заполненными полями. Ивенты можно подписать календарём — новые приезжают в него сами.
  • Позвать в спейс — список резидентов и знакомых гостей на выбранный день, зов уходит в личку.
  • Взносы — состав текущего периода, карточка человека с историей по месяцам, собираемость и выгрузка таблицы человек × месяц. Резидент жмёт «Я внёс», dev сверяет с выпиской и подтверждает.
  • Статистика — сколько часов спейс работал, когда здесь людно, часы по месяцам, кто держит спейс открытым, таймлайн любого дня и карточка человека. Раздел резидентский; у каждого есть отказ от журнала.
  • Настройки — уведомления о заявках и ивентах, привязка MAC для авто-отметок, подписка на ивенты календарём, тема.
  • Архив — прошедшие недели заявок, только чтение.

Гостю в настройках доступна только тема; чужие заявки, заметки и статистика ему не отдаются ни на одном экране.

В чате и в личке

Доска «кто сегодня в спейсе» — закреплённое сообщение про ближайший день с активностью: ивенты, кто сейчас внутри, кто придёт, кнопка «Хочу прийти». Обновляется сама на каждый чек-ин и каждую заявку. /boardmute выключает её в чате.

Присутствие. /start в личке — меню «Отметиться с ником / без ника», каждые 3 часа бот переспрашивает: 15 минут без ответа — отметка снимается. Авто-отметки по MAC: бот опрашивает роутер Keenetic и отмечает резидента, пока устройство в сети (на телефоне нужно выключить рандомизацию MAC для сети спейса). /inside — разовый список тех, кто внутри, доступен участникам чатов бота. Есть режим «невидимка» и отказ от журнала визитов.

Сборы донатов — один сбор на период (по умолчанию календарный месяц). /goals показывает текущий, /history — прошлые; /donate, /remove, /setgoal, /settitle, /setdesc, /setresetday, /export, /goalsmute — для админов чата. Сообщение сбора перерисовывается на месте и раз в день постится заново.

3D-принтер. /printer в личке резидента: прогресс печати, остаток времени, превью из gcode или кадр с вебки и кнопка «Уведомить по окончании». В группах команды нет — за камерой живой кадр из помещения.

Анонсы. Пуш тега vX.Y.Z собирает GitHub Release из коммитов; дальше текст релиза правится в мини-аппе и рассылается по чатам. /announcemute отключает рассылку в конкретном чате.

Табло. В спейсе висит e-paper табло на микроконтроллере: оно тянет лидерборд текущего сбора и ближайшие ждущие ответа заявки через GET /board со статическим токеном. За этой ручкой лежит только то, что бот и так публикует в чате.

Запуск

cp .env.example .env           # API_ID, API_HASH, BOT_TOKEN, ALLOWED_CHATS
npm install
npm --prefix webapp install
npm --prefix webapp run build  # мини-апп собирается в webapp/dist
npm start                      # npm run dev — watch-режим

Мини-апп включается переменной WEBAPP_URL — это публичный HTTPS-адрес, под которым отдаётся сборка из webapp/dist. Бот поднимает свой HTTP-сервер на WEBAPP_HOST:WEBAPP_PORT, наружу его выставляет реверс-прокси с TLS. Чтобы кнопки из групп открывали мини-апп, включите Main Mini App в BotFather с тем же URL, а для инлайн-режима — /setinline.

Остальные переменные перечислены в .env.example; каждая выключает свою подсистему, если не задана: RESIDENTS_CHAT_ID, PRINTER_URL, KEENETIC_URL/KEENETIC_LOGIN/KEENETIC_PASSWORD, ANNOUNCE_CHANNEL_ID, BOARD_TOKEN, DEV_USER_IDS, HOSTING_TZ_OFFSET_MINUTES.

Стейт — в DATA_FILE (по умолчанию ./data.json), сессия mtcute — в SESSION_FILE. Рядом со стейтом бот держит резервную копию, афиши ивентов, журнал присутствия и журнал действий (audit/: кто захостил, закрыл заявку, перенёс визит, завёл или удалил ивент — в стейте от таких действий следа не остаётся). В Docker оба пути обязаны лежать в примонтированном томе — иначе пересборка образа сотрёт и стейт, и сессию; docker-compose.yaml задаёт их через environment.

Разработка

npm run dev                        # бэкенд в watch-режиме
npm --prefix webapp run dev        # Vite dev-сервер с прокси на бэкенд
npm run typecheck                  # бэкенд
npm --prefix webapp run typecheck  # мини-апп

Бэкенд запускается через tsx, без сборки. Мини-апп — отдельное приложение в webapp/ со своими зависимостями; сервер бота раздаёт готовый webapp/dist, так что перед npm start его нужно собрать. Тестов и линтера нет, в CI гоняются оба тайпчека.

Подсистемы независимы и делят один стейт: src/hosting.ts и src/webapp.ts — визиты и API мини-аппа, src/presence.ts — присутствие, src/dues.ts — взносы, src/events.ts — ивенты, src/fundraiser.ts — сборы, src/storage.ts — тот самый JSON. Подробный разбор архитектуры и неочевидных решений — в CLAUDE.md.

About

Endpoint robot source code

Resources

Stars

5 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages