Telegram bot for managing cleaning schedule in the local.
Go to file
Kamil 'Kamaś' Bruchal 4f9cc6c359 feat: harden rota sync and throttle manual /sync
Resolve the current-year sheet tab per fetch instead of freezing it at
startup, so a long-running process follows the New Year rollover without a
restart. Guard against the regression this introduces: a successful fetch
that returns no duty weeks (e.g. a freshly created, empty next-year tab) now
keeps the last-good cache instead of clobbering it with empty data.

Surface a silently-stale cache — which is not a crash, so process-level
supervision can't catch it — by escalating to a loud error log once no sync
has succeeded for 6h (new Store.LastSynced accessor backs the check).

Throttle manual /sync to once per minute across the chat to avoid spamming
the Google Sheets API; the check-and-set is mutex-guarded since Telegram
dispatches each update in its own goroutine.

Update README accordingly.
2026-06-19 02:05:04 +02:00
cmd/dyzur-bot refactor: address review findings (slog, fetch timeout, Docker) 2026-06-18 21:38:37 +02:00
.dockerignore refactor: address review findings (slog, fetch timeout, Docker) 2026-06-18 21:38:37 +02:00
.gitignore fix: read GOOGLE_SHEETS_ID and default range to current-year tab 2026-06-17 21:16:25 +02:00
.golangci.yml Initial commit 2026-06-17 18:53:54 +02:00
.markdownlint-cli2.yaml Initial commit 2026-06-17 18:53:54 +02:00
.pre-commit-config.yaml Initial commit 2026-06-17 18:53:54 +02:00
Dockerfile refactor: address review findings (slog, fetch timeout, Docker) 2026-06-18 21:38:37 +02:00
README.md feat: harden rota sync and throttle manual /sync 2026-06-19 02:05:04 +02:00
doc.go refactor: address review findings (slog, fetch timeout, Docker) 2026-06-18 21:38:37 +02:00
go.mod chore: track go.mod, go.sum, and missing test files 2026-06-18 21:40:41 +02:00
go.sum chore: track go.mod, go.sum, and missing test files 2026-06-18 21:40:41 +02:00
scheduler.go feat: ping on-duty members by Telegram handle in reminders 2026-06-19 01:40:20 +02:00
scheduler_test.go feat: ping on-duty members by Telegram handle in reminders 2026-06-19 01:40:20 +02:00
service.go feat: harden rota sync and throttle manual /sync 2026-06-19 02:05:04 +02:00
service_test.go feat: harden rota sync and throttle manual /sync 2026-06-19 02:05:04 +02:00
sheet.go feat: ping on-duty members by Telegram handle in reminders 2026-06-19 01:40:20 +02:00
sheet_test.go feat: ping on-duty members by Telegram handle in reminders 2026-06-19 01:40:20 +02:00
store.go feat: harden rota sync and throttle manual /sync 2026-06-19 02:05:04 +02:00
store_test.go fix: lint, interval validation, corrupt-cache tolerance, background init sync, concurrent test 2026-06-17 20:45:29 +02:00
telegram.go feat: harden rota sync and throttle manual /sync 2026-06-19 02:05:04 +02:00
telegram_test.go feat: harden rota sync and throttle manual /sync 2026-06-19 02:05:04 +02:00

README.md

Dyżur-bot

A telegram bot for managing the cleaning rota in hackerspace. Bot offers weekly reminders about cleaning duties as well as on demand informations. Backend read the schedule from a Google sheet, store it in local JSON file.

Running

Requires GOOGLE_API_KEY, GOOGLE_SHEETS_ID, and BOT_TOKEN in the environment or a .env file (see service.go/sheet.go for optional SHEET_RANGE, ROTA_CACHE_PATH, SYNC_INTERVAL). Then:

go run ./cmd/dyzur-bot

The service loads the cached rota, syncs from Google Sheets in the background on SYNC_INTERVAL (default 30m), and runs the Telegram bot via long polling until interrupted (Ctrl-C / SIGTERM).

When SHEET_RANGE is unset, the bot reads the current year's tab (e.g. 2026!A1:G100), resolved on every sync — so it follows the New Year rollover automatically without a restart. A sync that fails, or that returns no duty weeks (e.g. a next-year tab that exists but hasn't been filled in yet), keeps the last-good cache instead of clearing it; if no sync succeeds for 6h the bot logs a loud stale-cache error.

Run exactly one instance per bot token. The bot uses long polling (getUpdates); two concurrent pollers on the same token make Telegram return HTTP 409 Conflict and updates get dropped. Do not scale this to multiple replicas.

Docker

docker build -t dyzur-bot .
docker run --rm --env-file .env -v dyzur-data:/data dyzur-bot

The image is a static binary on distroless (timezone data is embedded, so reminders work without system tzdata). The rota cache lives at /data/rota.json (ROTA_CACHE_PATH); mount a volume at /data to persist it across restarts.

Commands

  • /kto_sprzata — who is on cleaning duty this week.
  • /sync — refresh the rota from Google Sheets now (throttled to once per minute across the chat to avoid spamming the Sheets API).

Reminders

If GROUP_CHAT_ID is set, the bot posts a weekly duty reminder to that chat. Schedule (all optional, with defaults): REMINDER_WEEKDAY (default Monday), REMINDER_HOUR (default 9, 023), DUTY_AHEAD_DAYS (default 14). The hour is interpreted in Europe/Warsaw time. The reminder announces who is on duty DUTY_AHEAD_DAYS from the fire time — e.g. every Monday 09:00, who cleans two weeks out. Leave GROUP_CHAT_ID unset to disable reminders.