Issue #3608699 by codeitwisely, marcus_johansson: Add alert channel plugin system with webhook delivery

Closes https://www.drupal.org/project/ai_metering/issues/3608699

What changed

  • AlertService now only DECIDES when an alert fires (threshold crossing); delivery is delegated to @AlertChannel plugins. Email (the previous hardwired behaviour) and Webhook ship with the module; a third-party module adds Slack/Teams/PagerDuty by dropping an annotated class in src/Plugin/AlertChannel/, no patching.
  • AlertChannelPluginManager (DefaultPluginManager, annotation discovery, cached), AlertChannelInterface, AlertChannelBase (ContainerFactoryPluginInterface), mirroring the existing PricingSource plugin pattern.
  • WebhookAlertChannel posts a JSON body with a human-readable text summary plus structured fields (event, uid, pct_used, tokens_used, budget, threshold_pct), so Slack incoming webhooks render it as-is and custom endpoints can read the fields. HTTP client built once with a 5s timeout; delivery failures are logged, never propagated, so one broken channel cannot block another or the AI call.
  • New alerts.webhook_url setting with schema, an opt-in toggle in the settings form (URL field visible and required only when enabled, hidden otherwise), and server-side validation rejecting non-http(s) schemes and loopback/private/reserved hosts (SSRF).
  • hook_update_9020 ensures the new key exists on existing installs.

Testing steps

  1. Settings > AI Metering: enable "Send quota alerts to a webhook", enter an incoming webhook URL (Slack works out of the box).
  2. Push a user over their alert threshold with an AI call.
  3. The alert arrives on the webhook and by email, once per threshold crossing.

Verified live (Drupal 11.3.12, PHP 8.4): a real threshold crossing delivered a message to a Slack channel via the webhook, and an email via the mail collector. Independent architecture review passed (plugin API, DI, decision/delivery separation, SSRF). Suite green (142 tests, 564 assertions), PHPCS and PHPStan clean.

AI assistance

Implemented with AI assistance (Claude Code), reviewed by an automated Drupal architecture review, verified end to end on a live site.

Merge request reports

Loading