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) <[email protected]>
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) <[email protected]>
| 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?
There was a problem hiding this comment.
Resolved in faec63d: TG_WEBHOOK_URL was removed and the webhook URL is now derived from BodhiWeb.Endpoint.url/0 in config/runtime.exs, so it stays in sync with Phoenix settings automatically.
| config = | ||
| Application.get_env(:bodhi, Bodhi.TgHookHandler, []) | ||
|
|
||
| if authorized?(conn, config[:secret_token]) do |
There was a problem hiding this comment.
Resolved in faec63d: auth now lives in BodhiWeb.Plugs.TelegramWebhookAuth, a dedicated plug in the router pipeline, instead of inline controller code. Now covered by test/bodhi_web/plugs/telegram_webhook_auth_test.exs.
| Telegex.Type.Update | ||
| ) | ||
|
|
||
| Task.start(fn -> |
There was a problem hiding this comment.
Async task is not needed here
There was a problem hiding this comment.
Resolved in faec63d: the Task.start wrapper was dropped, the controller now calls TgUpdateHandler.on_update/1 synchronously. Covered by test/bodhi_web/controllers/telegram_webhook_controller_test.exs.
- 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) <[email protected]>
Extend Bodhi.Behaviours.TelegramClient with delete_webhook/0 and set_webhook/2 so Bodhi.TgHookHandler goes through the same Bodhi.Telegram indirection as every other Telegram call, making webhook registration mockable with Bodhi.TelegramMock. Add tests for the previously-untested TgHookHandler, TgPollingHandler, TelegramWebhookAuth plug, and TelegramWebhookController, and document the polling/webhook handler split in AGENTS.md and the required TG_WEBHOOK_SECRET env var in README.md. Co-Authored-By: Claude Sonnet 5 <[email protected]>
…down # Conflicts: # README.md
…tests
start_supervised/1 starts children under a Supervisor, so a permanent
child's init failure surfaces as {:error, {reason, child_spec}}, not
{:error, reason} directly. CI caught the mismatch since Postgres (and
therefore mix test) isn't available in this sandbox.
Co-Authored-By: Claude Sonnet 5 <[email protected]>
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