syriable / laravel-casework
A UI-agnostic trust & safety platform for Laravel: reports, moderation cases, decisions, enforcement, appeals, and an append-only audit trail.
Requires
- php: ^8.3
- illuminate/contracts: ^12.0||^13.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- fakerphp/faker: ^1.24.1
- larastan/larastan: ^3.9.6
- laravel/pint: ^1.18
- mockery/mockery: ^1.6.12
- nunomaduro/collision: ^8.9.4
- orchestra/testbench: ^10.0||^11.0
- pestphp/pest: ^4.7.0
- pestphp/pest-plugin-laravel: ^4.1.0
- pestphp/pest-plugin-type-coverage: ^4.0.4
- phpstan/extension-installer: ^1.4
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- rector/rector: ^2.4.2
This package is auto-updated.
Last update: 2026-07-18 19:01:31 UTC
README
A complete, UI-agnostic moderation platform for Laravel: user reports, moderation cases, decisions, enforcement (restrictions, suspensions, warnings), appeals, and a tamper-evident audit trail — as composable domain operations with no views, routes, or opinions about your stack. You bring the UI; the package brings the workflow integrity.
Features
- Reporting — fluent report filing with reasons-as-data, duplicate guards, anonymous/system origins, and configurable case-opening strategies
- Reporter reputation — opt-in per-reporter scoring that reacts to dismissed/upheld reports, with an optional block threshold and per-reporter rate limiting to blunt report-bombing
- Case management — cases with assignment, investigation, notes, evidence, priorities, and state machine-managed lifecycles
- Decisions — atomic decisions that resolve reports and apply enforcement in one transaction, with supersession chains instead of edits
- Enforcement — typed, scoped, expiring restrictions with a
single-query
isRestricted()hot path honoring expiry in real time - Appeals — appeal windows and limits, independent-reviewer enforcement, and atomic overturns that lift restrictions and record superseding decisions
- Audit — one append-only entry per domain action; no unaudited path exists, from your code or the package's own automation
- Events & automation — an after-commit event per action, a config-registered notifier hook, and intake/triage pipelines for ML scoring, auto-dismissal, and auto-assignment
- Extensible without forking — override models, rebind actions and guards, extend workflows (add-only, boot-validated), swap strategies and scope resolution
Installation
composer require syriable/laravel-casework php artisan migrate
Requires PHP 8.3+ and Laravel 12+.
Reports classify against reasons-as-data, so create at least one reason before filing (idempotent, seeder-friendly):
php artisan casework:make-reason spam
Every config key has a working default. Publishing is optional:
php artisan vendor:publish --tag="casework-config" php artisan vendor:publish --tag="casework-migrations"
See the installation guide for key-type notes (bigint/ULID/UUID all supported) and the morph-map recommendation.
Quickstart
use Syriable\Casework\Facades\Casework; use Syriable\Casework\Support\Outcome; // Mark models: Reportable + InteractsWithReports, // Restrictable + InteractsWithRestrictions. $report = Casework::report($post) ->by($user) ->because('spam') ->comment('Links to a phishing site') ->file(); $case = Casework::openCase($post)->bySystem()->open(); $decision = Casework::decide($case) ->by($moderator) ->outcome(Outcome::UPHOLD) ->withSuspension(days: 30) ->finalize(); // case + reports + restriction + audit, atomically $user->isSuspended(); // one indexed query, expiry honored in real time $appeal = Casework::appeal($decision)->by($user)->submit(); Casework::resolveAppeal($appeal)->by($reviewer)->overturn();
The quickstart guide walks this end to end.
Why
CaseFile? The case entity is namedCaseFilebecausecaseis a reserved word in PHP — everything else (tables, config, docs) still says "case".
Documentation
| Guide | Covers |
|---|---|
| Installation | require, migrate, key types, morph map |
| Quickstart | the full loop, end to end |
| Reporting | reports, reasons, duplicate rules |
| Cases & decisions | case ops, notes, evidence, deciding |
| Enforcement | restrictions, warnings, expiry, the hot path |
| Appeals | windows, limits, independence, overturns |
| Audit | querying history, immutability, pruning |
| Authorization | policies, scopes, self-moderation |
| Events | catalog, after-commit guarantee, notifiers |
| Automation | intake/triage pipelines |
| Extending | all fourteen extension points |
| Workflows | the four state machines |
| Configuration | every key, defaults, validation |
| Exceptions | what throws, when |
| Testing your integration | factories, fakes, assertions |
Architecture decision records live in docs/adr/.
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Please see CONTRIBUTING for details.
Security Vulnerabilities
Please review our security policy on how to report security vulnerabilities.
Credits
License
The MIT License (MIT). Please see License File for more information.