feat: webhook mode for production, polling for dev/test#36
Conversation
Split TgWebhookHandler into three modules: - TgUpdateHandler: shared business logic - TgPollingHandler: thin polling wrapper for dev - TgHookHandler: thin webhook wrapper for production Handler selection is driven by :tg_mode config (:polling/:webhook/:disabled). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code ReviewOverviewClean refactor that separates transport concerns (webhook vs. polling) from shared bot logic. The three-way IssuesBug / Crash Risk —
|
| Architecture | ✅ Clean separation of transport vs. business logic |
| Correctness | on_boot crash risk; optional webhook secret |
| Style | |
| Tests | ✅ Existing tests correctly updated; thin wrappers untested (low risk) |
| Security |
The two blocking items are the crash risk in on_boot and the optional webhook secret. Everything else is minor polish.
🤖 Generated with Claude Code
|
Could we integrate webhook into phoenix routes without separate port? |
- Replace Telegex.Hook.GenHandler with a GenServer that registers the webhook on boot + a Phoenix controller that receives updates - Require TG_WEBHOOK_SECRET in production (was silently optional) - Use `with` in webhook setup to handle API errors gracefully - Fix stale file path in AGENTS.md - Revert accidental dev port change (4003 → 4000) - Remove separate webhook port config (TG_WEBHOOK_PORT) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
| config :bodhi, :tg_mode, :webhook | ||
|
|
||
| webhook_url = | ||
| System.get_env("TG_WEBHOOK_URL") || |
There was a problem hiding this comment.
Does this still needed or could be determined from Phoenix settings?
| config = | ||
| Application.get_env(:bodhi, Bodhi.TgHookHandler, []) | ||
|
|
||
| if authorized?(conn, config[:secret_token]) do |
| Telegex.Type.Update | ||
| ) | ||
|
|
||
| Task.start(fn -> |
There was a problem hiding this comment.
Async task is not needed here
- Extract secret-token check into BodhiWeb.Plugs.TelegramWebhookAuth and pipe the webhook scope through it instead of branching in the action - Drop Task.start from controller; the request process already handles the update synchronously - Derive webhook URL from BodhiWeb.Endpoint.url() + route path; remove TG_WEBHOOK_URL env var (TG_WEBHOOK_SECRET still required in prod) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
Bodhi.TgUpdateHandler, replacingBodhi.TgWebhookHandlerBodhi.TgPollingHandler(thin wrapper for dev/test) andBodhi.TgHookHandler(thin wrapper for production webhook mode)Bodhi.Applicationbased on:tg_modeconfig (:polling,:webhook, or:disabled)TG_WEBHOOK_URL,TG_WEBHOOK_SECRET,TG_WEBHOOK_PORTenv vars inruntime.exsTest plan
mix compile— no warningsmix test— 250 tests, 0 failuresmix format— cleanmix dialyzer— 0 errorsiex -S mix🤖 Generated with Claude Code