Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Byobu Laravel Package

fof/byobu

Byobu is a Flarum extension that adds private discussions, letting users create and manage discussions visible only to selected users or groups. It includes permissions, recipient management, and integration with Flarum's discussion list for controlled, private conversations.

View on GitHub
Deep Wiki
Context7

Getting Started

Byobu is a private discussions layer for Flarum: it adds recipients to discussions, a is_private flag on the discussion, permission gates around who can create/invite/leave, and visibility scoping so non-recipients can't see the thread through the API, search, or the discussion list.

Minimal setup:

composer require fof/byobu
php flarum migrate
php flarum cache:clear

Then enable it in Admin → Extensions → Private Discussions (Byobu) and grant the private-discussion permissions on the Groups page — by default nobody can start one. The extension's own settings page controls the softer behaviours (whether recipients may add/remove others, whether they may leave, whether they can edit their own posts, and the default "who can be invited" rules).

Read these in order before writing any code:

  1. src/Discussion/Recipients.php — the value object you will interact with most. It wraps the discussion↔user / discussion↔group relationships and is the only sane way to read or mutate recipients.
  2. migrations/ — the pivot table backing recipients. You need to know its columns (added_by, removed_at/removed_by, timestamps) before you write any reporting or cleanup query.
  3. src/Listeners/ — the lifecycle hooks (SaveDiscussion, StartDiscussion, ShowDiscussion, API attribute injection). This is where Byobu enforces its invariants; your code should sit next to them, not in front of them.
  4. js/src/forum/ — the composer flow, the recipients modal, and the Discussion model extensions (isPrivate(), recipient relationships). That's your template for any custom UI.

First use case: gate a custom feature on privacy. If you're adding a "share this thread externally" button, an analytics export, or a webhook, the first check is always the same — is this discussion private, and is the acting user actually a recipient?

use Flarum\Discussion\Discussion;

if ($discussion->is_private && ! $discussion->recipientUsers->contains($actor)) {
    abort(403);
}

Implementation Patterns

Treat Recipients as the API, not the pivot table. Every read/write of recipients should go through FoF\Byobu\Discussion\Recipients (obtained from the discussion). It knows about added-by, removed-at semantics, and group recipients; hand-rolled attach()/detach() calls will desync the flags Byobu's UI relies on. If you're building an invitation endpoint or a "grant access to team" action, load the discussion, get its recipients, add, save.

Creating private discussions programmatically. For an integration that opens a thread on a user's behalf (support ticket, moderation note), construct the discussion normally, set is_private before save, and attach recipients inside a Discussion\Saving or Discussion\Started listener so Byobu's own listeners see a consistent state. Don't set is_private = true with zero recipients and expect anyone but the author to see it — decide explicitly who the fallback audience is.

Query scoping. The extension registers visibility scoping on the Discussion model, so Discussion::whereVisibleTo($actor) is the correct filter and is what you should use in any custom controller or relation. For "show me only threads I'm a recipient of":

$discussions = Discussion::whereVisibleTo($actor)
    ->where('is_private', true)
    ->whereHas('recipientUsers', fn ($q) => $q->where('users.id', $actor->id))
    ->get();

whereHas('recipientUsers', ...) is also the join you want for list building; a raw join on the pivot table will work but will break when the schema changes and won't respect group recipients.

API surface. Byobu serializes privacy onto the discussion resource — an isPrivate attribute plus recipientUsers / recipientGroups relationships. On the frontend, extend Flarum's Discussion model (Discussion.prototype.isPrivate = function () { return this.attribute('isPrivate'); }) and read recipients the same way, rather than re-fetching from your own endpoint. If you need extra data (recipient count, "you were added by X"), inject it through an ApiController extender on the discussion show/index endpoints and keep the shape consistent with Byobu's.

Permission gating in depth. Byobu adds private-discussion permissions to the Groups page; check them with $actor->can('discussion.startPrivateDiscussion') (verify exact permission keys in the extension's extend.php / permission listener, they're namespaced like core discussion permissions). For anything that changes the audience — a "forward to moderator" action, an escalation flow — check the recipient-editing permission and whether the actor is still a recipient with rights (a user who was removed from a thread must not be able to re-add themselves).

Notifications. Byobu hooks recipient changes into Flarum's notification pipeline. If you add a new recipient-manipulating action, dispatch through the normal Discussion events so Byobu's listeners can queue the added to private discussion notification; firing raw DB inserts silently loses that.

Gotchas and Tips

  • Never bypass visibility scoping. Discussion::find($id) does not respect privacy. Any new endpoint must go through whereVisibleTo() or an explicit $actor->can('view', $discussion) check. This is the number one way people leak private content with this extension installed.
  • is_private and "has recipients" are two different things. A discussion can be flagged private with an empty recipient set (author-only), and a recipient list can exist on a non-private discussion after a "make public" action. Always check both, and pick a deliberate fallback.
  • User recipients are snapshotted; group recipients are live. Adding a group means everyone who later joins that group gains access retroactively; adding a user does not follow them if they're removed from a group. Model this consciously — it's a common source of "why can this person see the thread?" tickets.
  • Removals are soft. The pivot table keeps removed_at / removed_by for audit and for the "you were removed" UI. Queries that filter on the relation automatically exclude removed recipients; queries against the raw table do not — you must filter removed_at IS NULL yourself.
  • User deletion leaves orphan rows. When cleaning up, handle recipient rows for deleted users (and null on added_by / removed_by) or your audit views will throw on eager-loaded relations.
  • Search and gambits. Byobu's scoping flows into Flarum's search, but any custom gambit or indexer you add must apply the same visibility filter, otherwise full-text results expose titles and excerpts. Test with a non-recipient actor, not just as admin.
  • Caches and permissions. Permission and setting changes are cached aggressively — php flarum cache:clear after changing group permissions or extension settings, or you'll debug a "permission not honoured" ghost. Test visibility with a fresh non-admin session.
  • Do not depend on the recipients modal's internals. js/src/forum/ component class names and prop shapes are the least stable part of the package across minor releases. Hook at the Discussion model / API attribute layer if you need something durable.
  • Migrations from core privacy. Core Flarum already had an is_private flag on discussions. If you're importing from a forum that used core's version, backfill recipient rows explicitly; a discussion that is is_private with no Byobu recipients will render as a broken private thread.
  • Extension points worth knowing: the Recipients value object, Byobu's lifecycle listeners (Saving/Started), the discussion API attributes/relations, and Flarum's standard permission and notification extenders. Prefer composing around those over forking the extension — at ~59 stars and a single maintainer, upstream drift is the main long-term risk, so keep your customisations in your own extension's listeners.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle