guanguans/notify
Send notifications through dozens of channels—DingTalk, WeChat Work, Feishu, Bark, Slack, Telegram, and more—via one unified, framework-agnostic PHP API. Clean, extensible SDK with Laravel support for fast, consistent integration.
Architecture fit. guanguans/notify is a standalone, Guzzle-backed SDK with a fluent, one-class-per-provider design (Notify::dingTalk()->send(...)). It is not built on Laravel's Illuminate\Notifications contracts — there is no NotificationChannel, no Notifiable trait integration, no toDingTalk() convention. That is the single most important architectural fact for us: the package is a transport library, not a framework citizen. It slots in cleanly if we treat it as an outbound gateway behind our own port interface, and poorly if we expect it to replace our existing Notifiable/queued-notification stack. Given the breadth (30+ providers), the realistic role is "swappable egress adapter for third-party push webhooks," not "core notification system."
Integration feasibility. Composer-installable, MIT licensed, no service or daemon required — it is pure HTTP fan-out, so a spike is hours, not days. The blockers are mundane and checkable: PHP version constraint against our runtime, Guzzle major-version compatibility with our existing HTTP-client usage, and whether it hard-depends on Guzzle vs. accepting a PSR-18 client (relevant for central observability/mocking). We should validate that it does not collide with laravel-notification-channels/* packages already in the tree.
Technical risk.
Key questions for the maintainer/spike.
Stack fit. Best treated as an egress adapter layer, not a notification framework. Concretely: define an internal PushGateway interface (send(Channel, Payload): Result), implement a GuanguansPushGateway that delegates to the SDK, and bind it in the container. Laravel Notification classes then use a single custom channel that resolves the target provider from config. This keeps the vendor behind a seam we can replace with direct HTTP calls for the 3–5 providers we actually use, and prevents provider-specific builder calls from leaking into domain code.
Migration path. Do not migrate all channels. Pick the one or two providers already in production (most likely DingTalk, Slack, or Telegram), build the adapter, and dual-run: existing code path stays primary, SDK path sends in shadow mode to a test channel with payload diffing for a week. Cut over per-provider behind a config flag. Keep the legacy path intact until the new path has a clean two-week error budget.
Compatibility. Pin to an exact minor version with a lockfile; add a Composer conflict guard for Guzzle majors we do not support. Verify PHP constraint against every runtime (web, queue workers, scheduler) — queue workers are the usual place a version skew surfaces. Confirm it coexists with our existing notification-channel packages and does not double-register an HTTP client or config namespace.
Sequencing.
PushGateway interface + container binding + config schema (provider → credentials, timeout, retry policy).Maintenance. Owned by whoever owns notifications — assign explicitly. Commit to a monthly dependency review plus a dependabot PR lane; pin and upgrade deliberately rather than tracking latest, because a minor bump can silently change a provider's payload shape. Budget a small recurring allowance for provider-side breakage (tokens, deprecations, rate-limit policy changes) that arrives without a package release. Treat the dependency as replaceable: the adapter seam is the real asset, and we should be able to drop the package for our top three providers in under a sprint.
Support. Community-only. No SLA, no vendor escalation. Our internal on-call is the support tier, so the runbook must cover: how to identify which provider failed, how to rotate a webhook/token, and how to disable a channel without a deploy (config flag). Documentation is largely Chinese-language; budget translation effort for the two or three providers we depend on, and capture our own internal docs rather than relying on upstream.
Scaling. Fan-out is per-message HTTP; there is no batching. Throughput ceiling is provider rate limits, not our PHP processes: Slack tiered limits, Telegram ~30 msg/s per bot, DingTalk per-webhook throttles. Enforce per-provider concurrency caps and backoff in our queue layer, not in the SDK. Memory footprint is negligible; the real scaling concern is the notification queue becoming a shared bottleneck — isolate push-sending onto its own queue and worker pool so a provider slowdown does not starve transactional mail or other jobs. Secrets scale poorly: 30 providers × environments means a secrets-management story (vault-backed config, not .env sprawl) before the third provider is enabled.
Failure modes.
Ramp-up. Sending a message is roughly an hour of ramp — the API is genuinely simple. Full production readiness (adapter, error taxonomy, retry policy, canaries, secrets, runbook, fallback) is realistically 2–4 engineer-days for a two-provider scope, and the cost scales with provider count, not with code complexity. Restrict enabled channels to the 3–5 we actually use; the remaining 25+ are discovery value only and should be treated as untested surface.
How can I help you explore Laravel packages today?