The default handler fired for every update the command matchers didn't
claim, so plain chatter, service messages, media, and replies to the bot
all drew a "Nieznana komenda" response — spammy in group chats. Gate the
fallback on a leading bot_command entity so only real (unrecognized)
commands get the help reply.
In group chats Telegram appends the bot addressee to the bot_command
entity (/sync@hs_dyzur_bot), and the library's MatchTypeCommand compares
the whole token verbatim, so commands never matched. Replace it with
custom MatchFuncs that read the bot_command entity span and strip any
@suffix before comparing the command name.
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.
- add per-request timeout to the Sheets fetch so a hung call can't block /sync
- stop leaking raw sync errors to chat; log detail, reply generically
- migrate logging from log to structured log/slog
- drop duplicate godotenv.Load from ReadSheet (LoadConfig loads .env at startup)
- add multi-stage distroless Dockerfile + .dockerignore; embed tzdata via import
- document single-instance long-polling constraint in README
- translate sheet.go comments to English
- move package doc to doc.go; remove superseded root main.go and live_test.go