syriable / laravel-converse
Marketplace-grade 1:1 messaging for Laravel: one thread per relationship, per-participant state, governed multi-type messages, and an event for everything.
Fund package maintenance!
Requires
- php: ^8.3
- illuminate/contracts: ^12.0||^13.0
- spatie/laravel-medialibrary: ^11.0
- spatie/laravel-package-tools: ^1.16
- syriable/laravel-casework: ^1.0
- syriable/laravel-user-context: ^1.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.14
- nunomaduro/collision: ^8.8
- orchestra/testbench: ^11.0.0||^10.0.0
- pestphp/pest: ^4.0
- pestphp/pest-plugin-arch: ^4.0
- pestphp/pest-plugin-laravel: ^4.0
- phpstan/extension-installer: ^1.4
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-phpunit: ^2.0
- spatie/laravel-ray: ^1.35
README
Marketplace-grade private messaging between two users — the messaging model behind platforms like Fiverr, generalized into a headless Laravel package: one trusted thread per relationship, private per-side state, governed multi-type messages, presence-aware notifications, and an event for everything.
$buyer->messageTo($seller)->text('Hi! Is this service available?')->send();
No routes, no views, no JavaScript, no broadcasting transport — Converse is a domain layer you build your own UI, API, and real-time transport on top of.
Key features
- One conversation per pair — a unique normalized pair key, safe under concurrent creation, replaceable via the
ConversationResolvercontract. - Per-participant state — read horizon, unread counter, folders, star, hide, mute, notes, labels: every one-sided action is invisible to the other side.
- Governed messages — a send-policy chain, an edit/delete window with an immutable revision log, soft delete only, and a pluggable moderation pipeline with human review.
- Configurable message pipeline — whitespace normalization, exact-duplicate blocking, and opt-in PII masking, all reorderable and extensible with your own stages.
- Structured message types — plain text and system messages built in; register your own validated types (offers, invoices, appointments).
- Blocking & reporting — directional blocks that also stop new conversations from forming, plus message reporting delegated to Laravel Casework (cases, decisions, enforcement, appeals).
- Attachments — Spatie Media Library on messages; MIME allowlist; participant-gated temporary URLs; per-file and per-sender size limits; optional prune retention.
- Presence-aware notifications — online/offline from
syriable/laravel-user-context; an offline recipient gets an email; an online one gets an immediate in-app notification; a recipient already viewing a thread gets no redundant notification. Per-channel preferences, debounced to avoid an email storm. - Event-driven — every domain change fires an event; build response-rate metrics, real-time broadcasts, CRM sync, or anything else as plain listeners.
- Testable —
Converse::fake()plus purpose-built assertions, and every documented notification/presence interaction is testable withNotification::fake()alone.
Requirements
PHP 8.3+, Laravel 12 or 13. Requires syriable/laravel-user-context (presence, locale, timezone, location) and syriable/laravel-casework (reporting, cases, enforcement) — both are first-party companions installed automatically and are not optional.
Installation
composer require syriable/laravel-converse php artisan converse:install # Attachments (Spatie Media Library) php artisan vendor:publish --provider="Spatie\MediaLibrary\MediaLibraryServiceProvider" --tag="medialibrary-migrations" # Reporting (Laravel Casework) php artisan vendor:publish --provider="Syriable\Casework\CaseworkServiceProvider" --tag="casework-migrations" php artisan migrate # Seed the default report reasons Converse offers php artisan db:seed --class="Syriable\Converse\Database\Seeders\ConverseReasonSeeder"
Add the trait to any model that should be able to converse:
use Syriable\Converse\Concerns\HasConversations; class User extends Authenticatable { use HasConversations; }
Full walkthrough, including presence setup: docs/installation.md.
Quick start
// Send a message — resolves or creates the pair's conversation automatically. $message = $buyer->messageTo($seller)->text('Can you design a minimal logo?')->send(); // Reply, attach a file, or send a structured type. $buyer->messageTo($seller)->replyTo($message)->text('Sounds good!')->send(); $buyer->messageTo($seller)->text('Reference image attached')->attach($uploadedFile)->send(); $seller->messageTo($buyer)->custom('offer', ['price' => 120, 'days' => 4])->send(); // Read the inbox. $buyer->conversations()->inbox()->cursorPaginate(20); $message->conversation->messagesFor($buyer)->cursorPaginate(50); $message->conversation->markReadBy($buyer); // Organize. $message->conversation->archiveFor($buyer); $message->conversation->starFor($buyer); // Block, report, moderate. $buyer->block($seller, 'spam'); $message->reportBy($buyer, reason: 'inappropriate'); // Presence-aware notifications — nothing extra to call. An offline // recipient gets emailed; an online one gets a real-time in-app // notification instead, and never both. $buyer->messageTo($seller)->text('Hello!')->send(); // routed automatically
Documentation
Everything beyond this landing page lives in docs/:
| Page | Covers |
|---|---|
| Installation | Setup, requirements, verification |
| Configuration | Every config key, explained |
| Architecture | The mental model — start here for anything deep |
| Conversations | Identity, resolution, listing, membership |
| Messages | Sending, replies, editing, deleting, reading |
| Message Pipeline | Text transformation, duplicate blocking, PII masking |
| Message Types | Structured, validated message types |
| Moderation | Automated moderation, verdicts, human review |
| Blocking | Directional blocks and send refusal |
| Reporting | User-filed reports via Laravel Casework |
| Attachments | Media Library, MIME allowlist, retention, signed links |
| Organizing Conversations | Folders, star, mute, hide, notes, labels |
| Presence & Real-Time | Online/offline detection, active-conversation tracking |
| Notifications | Channel routing, preferences, debounce, mail content |
| Events | The complete domain event catalogue |
| Models | Every Eloquent model, at a glance |
| Database | Every table, column, and index |
| Lifecycle | Message, conversation, attachment, and notification state machines |
| Commands | converse:install, converse:doctor, converse:retention, converse:recount |
| Extension Points | Every contract, in one place |
| Testing | Converse::fake(), factories, testing patterns |
| Security | The full security posture |
| Performance | What's fast, what to watch, and why |
| Upgrading | Version support and first-release adoption notes |
| Troubleshooting | Symptom-first problem index |
| FAQ | Common conceptual questions |
| Contributing | Development setup, house style, PR conventions |
Testing
composer test
Contributing
See docs/contributing.md for development setup, code style, and pull request conventions.
Security
If you discover a security vulnerability, please email the maintainer listed in composer.json directly rather than opening a public issue. See docs/security.md for the package's full security posture.
Credits
License
The MIT License (MIT). See LICENSE.md for more information.