laravel-notification-channels/bearychat
Send Laravel notifications to BearyChat with this channel driver. Post messages to BearyChat webhooks through Laravel's built-in notification system, keeping your team chat in sync with app events using a simple, familiar API.
Architecture fit. This is a textbook laravel-notification-channels driver and nothing more: a single BearyChatChannel implementing Laravel's NotificationChannel contract, a BearyChatMessage value object with a shallow fluent builder (text(), markdown()), and an incoming-webhook POST. Roughly 150 lines total. It slots into Laravel's existing notification pipeline cleanly — via() returns 'bearychat', the notification class exposes toBearyChat(), and routeNotificationForBearyChat() gives you per-notifiable routing. No models, migrations, service providers beyond the standard channel registration, or background infrastructure. From an architecture-review standpoint that's a positive: the integration surface is small enough to reason about completely in one sitting.
Integration feasibility. The code is easy; the Composer resolution is not. An archived repo with zero dependents and no maintainers means no illuminate/* or guzzlehttp/guzzle constraint bumps for Laravel 10/11/12. Expect composer require to conflict, and treat --ignore-platform-reqs or constraint pinning as the signal to stop depending and start vendoring. Time-to-first-notification is genuinely 15–30 minutes after you've resolved the dependency question — budget the resolution as the real task, not the code.
Technical risk. Four concrete risks, in priority order:
throw()/throwIf(). If send() doesn't check response status, a 400/401/403 completes "successfully" and the notification vanishes. This must be verified in source before adoption, not assumed.failed_jobs, so the URL lands in your jobs table unless scrubbed — an easy audit finding.BearyChatMessage.php before anyone designs a notification around rich cards.Product-level risk sits on top of these: BearyChat is a niche, apparently declining platform. Any request to integrate should be treated as a named, customer- or team-specific deliverable, not a platform feature to productize.
Key questions.
BearyChatChannel::send() throw on non-2xx, or do we wrap it?Stack fit. Purely additive to the Laravel notification stack. It assumes queued notifications, the HTTP client, and config-driven webhook storage in config/services.php + env('BEARYCHAT_WEBHOOK'). There is no database footprint, no event sourcing, no queue topology change beyond adding a dedicated queue name. It composes with existing notification classes without touching them.
Migration path — vendor, don't depend. The defensible path is to copy BearyChatChannel and BearyChatMessage into app/Notifications/Channels/BearyChat, retain the MIT copyright header, pin constraints to your supported PHP/Laravel ranges, and delete the Composer dependency. This is the primary migration decision and it should be made up front, not after a failed composer require. Rationale: zero maintainers, no upgrade path, and you will read the source to debug it anyway — at this size, owning it is cheaper than the dependency review.
Compatibility. Before writing code, run composer show laravel-notification-channels/bearychat --all and read composer.json constraints against your PHP/Laravel versions. Expect conflicts on modern Laravel. If you vendor, this step becomes a one-time port rather than a recurring upgrade negotiation. Also verify the HTTP client usage matches your Laravel version's Http facade API.
Sequencing. The order matters because each step de-risks the next:
src/BearyChatChannel.php and src/BearyChatMessage.php (10 minutes — it's the whole package). Check status handling and the exact payload fields emitted.curl the webhook directly with a {"text":"hello"} body. If that fails, the problem is endpoint or egress, not code.send() with Http::timeout(10)->retry(3, 200)->post($webhook, $payload)->throw() if status isn't already checked.Http::fake() contract tests asserting the payload shape and destination URL.ChatChannel/ChatMessage abstraction only when a second chat destination (Slack, Teams, DingTalk, Feishu) enters scope — not before.NotificationFailed listener filtering on channel === 'bearychat', logging notification class but never the webhook URL.Estimating the roadmap. The pattern is the reusable asset, not the package: channel class + send(), fluent message builder, routeNotificationFor*() hook. That lets you size each additional chat channel at roughly 0.5–1 dev-day and defend it in planning. The archived-upstream facts are what let you say, correctly, that a "just one more channel" ask is not a one-day build but a permanent small ownership line.
Maintenance. You own it permanently. No upstream will ship a fix for a Guzzle bump, a Laravel version change, or a payload drift. Mitigate by (a) naming an accountable engineer, (b) writing a one-page runbook covering where the channel lives, how to rotate the webhook, and how to run the contract test, and (c) subclassing the channel rather than editing vendored code in place, so patches stay mergeable if you ever re-sync against the original.
Support. No vendor, no issue tracker with a response, no security advisories. Support is entirely internal triage: failed jobs, NotificationFailed events, and the contract test. The NotificationFailed listener is the closest thing to a pager for this integration — feed it into existing alerting so a rotated or revoked webhook surfaces as a metric, not as silence.
Scaling. Delivery scales with your queue workers, not the package. Two hard requirements: run it on a dedicated queue (notifications-chat) so a BearyChat outage or a 30-second timeout can't back up the mail/primary notification pool, and set timeout, tries, and backoff explicitly. Note what's absent: no rate limiting, no idempotency keys, no dead-letter handling, no delivery observability beyond what you add. If those are requirements, this package doesn't meet them — build the wrapper yourself.
Failure modes to design against.
->throw() and the contract test.tries = 3; exhausted jobs land in failed_jobs and look like a database problem hours later unless the failed-jobs queue is monitored.failed_jobs and exception context; scrub both.Http::fake() left registered in tests — the classic "code works, delivery doesn't" red herring; the real-curl smoke test disambiguates.Ramp-up. Onboarding cost is genuinely low by design: ~10 minutes to read the source, 15–30 minutes to a first working notification, under a day to vendor and wrap it properly. The thing that makes ramp-up expensive over time is tribal knowledge — hence the one-page runbook. For the product side, the ramp-up framing is: a single chat channel is cheap to build and expensive to own, and the roadmap unit for "add chat notifications" should be a permanent small ownership line, not a sprint task.
How can I help you explore Laravel packages today?