vlados / laravel-legal-documents
Track legal document versions and user acceptances in Laravel applications
Requires
- php: ^8.2
- illuminate/contracts: ^11.0|^12.0|^13.0
- illuminate/database: ^11.0|^12.0|^13.0
- illuminate/support: ^11.0|^12.0|^13.0
Requires (Dev)
- orchestra/testbench: ^9.0|^10.0|^11.0
- pestphp/pest: ^3.0
Suggests
- filament/filament: Optional admin panel integration (^4.0)
- spatie/laravel-translatable: Optional additional-language storage (^6.0)
Provides
None
Conflicts
None
Replaces
None
README
A Laravel package for managing legal documents (Privacy Policy, Terms of Service, etc.) with version tracking, user acceptance management, and optional Filament admin panel integration.
Features
- Document Types Management - Create and manage different types of legal documents (Privacy Policy, Terms of Service, Cookie Policy, etc.)
- Version Control - Track document versions with full history and publish workflow
- User Acceptance Tracking - Record when users accept documents with audit metadata (IP address, user agent)
- Re-acceptance on Updates - Optionally require users to re-accept documents when they are updated
- Role-Based Requirements - Require specific documents for specific user roles (e.g., Terms of Service only for sellers)
- Middleware Protection - Block access to your application until required documents are accepted
- Email Notifications - Notify users when legal documents are updated
- Filament Integration - Optional admin panel with WordPress-style document editor
- Formal Document Control - Professional legal document layout with revision history
- Frontend Routes - Public pages to view legal documents with version history
- Content Translations - Optional bundled Spatie adapter, custom translation drivers, and preserved source-language content
- Interface Localization - English and Bulgarian labels, independent of content translations
Screenshots
Document Types Management
Manage document types with role-based requirements
Documents List
Track document versions, status, and user acceptances
Document Editor
Rich text editor with publishing controls and version management
Requirements
- PHP 8.2+
- Laravel 11.x, 12.x, or 13.x
- Livewire 3.x for frontend pages
- Filament 4.x for the optional admin panel
Installation
Install the package via Composer:
composer require vlados/laravel-legal-documents
Publish the configuration file:
php artisan vendor:publish --tag=legal-documents-config
Publish and run the migrations:
php artisan vendor:publish --tag=legal-documents-migrations php artisan migrate
Optional content translations
Upgrading from v1? Read the v2 upgrade guide for dependency changes and published configuration/view updates.
Single-language mode is the default and does not require a translation package. To enable additional languages with the bundled Spatie adapter, install Spatie, publish its separate migrations, and configure the fixed source language. Custom TranslationDriver implementations use their own dependencies and storage:
composer require spatie/laravel-translatable:^6.0 php artisan vendor:publish --tag=legal-documents-spatie-migrations php artisan migrate
// config/legal-documents.php 'translations' => [ 'driver' => 'spatie', 'source_locale' => 'en', // The language already stored in your original fields. 'locales' => ['en', 'bg'], 'fallback_locale' => null, ],
$document->title remains source text; $document->localized('bg')->values['title'] resolves translated content. Removing Spatie preserves readable source text and stored translations. Filament uses its own adapter-independent translation tabs; no additional translation UI plugin is required.
See the translation guide for writing translations, fallback, custom adapters, version copying, published views, and dependency removal.
Configuration
After publishing, you can configure the package in config/legal-documents.php:
return [ // Your User model 'user_model' => App\Models\User::class, // Route where users accept pending documents 'acceptance_route' => 'legal.accept', // Routes accessible even with pending documents 'excluded_routes' => [ 'logout', 'legal.*', 'filament.*', 'livewire.*', ], // Notification settings 'notifications' => [ 'channels' => ['mail', 'database'], 'queue' => true, ], // Filament admin panel integration 'filament' => [ 'enabled' => true, 'navigation_group' => 'Settings', ], // Frontend routes configuration 'frontend' => [ 'enabled' => true, 'prefix' => 'legal', 'middleware' => ['web'], 'layout' => 'layouts.app', ], // Role-based document requirements (optional) 'roles' => [ 'enabled' => false, // Set to true to enable role-based requirements 'available' => [], // Leave empty to auto-detect from Spatie Permission 'user_roles_method' => 'getRoleNames', // Method on User model to get roles ], ];
Setup
1. Add the Trait to Your User Model
Add the HasLegalAcceptances trait to your User model:
<?php namespace App\Models; use Illuminate\Foundation\Auth\User as Authenticatable; use Vlados\LegalDocuments\Traits\HasLegalAcceptances; class User extends Authenticatable { use HasLegalAcceptances; // ... }
2. Register the Middleware
Add the middleware alias in bootstrap/app.php:
->withMiddleware(function (Middleware $middleware) { $middleware->alias([ 'legal-documents' => \Vlados\LegalDocuments\Http\Middleware\EnsureLegalDocumentsAccepted::class, ]); })
3. Apply Middleware to Routes
Apply the middleware to routes that require document acceptance:
// Apply to specific routes Route::middleware(['auth', 'legal-documents'])->group(function () { Route::get('/dashboard', DashboardController::class); }); // Or apply globally in bootstrap/app.php ->withMiddleware(function (Middleware $middleware) { $middleware->appendToGroup('web', [ \Vlados\LegalDocuments\Http\Middleware\EnsureLegalDocumentsAccepted::class, ]); })
4. Filament Integration (Optional)
If you're using Filament, register the plugin in your Panel provider:
use Vlados\LegalDocuments\Filament\LegalDocumentsPlugin; public function panel(Panel $panel): Panel { return $panel // ... ->plugins([ LegalDocumentsPlugin::make(), ]); }
Usage
Creating Document Types
Using Filament admin panel or programmatically:
use Vlados\LegalDocuments\Models\LegalDocumentType; LegalDocumentType::create([ 'name' => 'Privacy Policy', 'slug' => 'privacy-policy', 'description' => 'Our privacy policy document', 'is_required' => true, 'sort_order' => 1, ]);
Creating Documents
use Vlados\LegalDocuments\Models\LegalDocument; $document = LegalDocument::create([ 'legal_document_type_id' => $type->id, 'title' => 'Privacy Policy', 'version' => '1.0', 'content' => '<p>Your privacy policy content...</p>', 'summary_of_changes' => null, 'requires_re_acceptance' => true, 'notify_users' => true, ]); // Publish the document $document->publish();
Publishing a Document
When you publish a document, it becomes the current version and optionally notifies users:
$document->publish();
This will:
- Set
published_atto now - Mark as
is_current - Unmark any previous current document
- Send notifications to users (if
notify_usersis true)
Checking User Acceptance
// Check if user needs to accept any documents if ($user->needsToAcceptDocuments()) { // Redirect to acceptance page } // Check if user has accepted a specific document type if ($user->hasAcceptedLatest('privacy-policy')) { // User has accepted the latest privacy policy } // Get all pending documents for a user $pendingDocuments = $user->getPendingDocuments(); // Get user's acceptance history $history = $user->getAcceptanceHistory();
Accepting Documents
// Accept a single document $user->acceptDocument($document, request()->ip(), request()->userAgent()); // Accept multiple documents $user->acceptDocuments($documentIds, request()->ip(), request()->userAgent());
Role-Based Document Requirements
When roles.enabled is set to true, you can require specific documents for specific user roles:
use Vlados\LegalDocuments\Models\LegalDocumentType; // Create a document type required only for sellers LegalDocumentType::create([ 'name' => 'Seller Agreement', 'slug' => 'seller-agreement', 'is_required' => false, // Not required for everyone 'required_for_roles' => ['seller', 'merchant'], // Only required for these roles ]); // Check pending documents for a user based on their roles $pendingDocuments = $user->getPendingDocumentsForRoles(); // Check if user needs to accept documents based on their roles if ($user->needsToAcceptDocumentsForRoles()) { // Redirect to acceptance page } // Get documents required for specific roles $sellerDocs = LegalDocumentType::requiredForRoles(['seller'])->get(); // Check if a document type is required for a specific user if ($documentType->isRequiredForUser($user)) { // This document is required for this user }
The package automatically detects Spatie Permission roles. If you use a different role system, configure the user_roles_method in the config to point to a method on your User model that returns role names.
Frontend Routes
The package provides these public routes (configurable via frontend.prefix):
| Route | Description |
|---|---|
/legal/accept |
Page for authenticated users to accept pending documents |
/legal/{slug} |
View the current version of a document |
/legal/{slug}/version/{version} |
View a specific version of a document |
Customization
Publishing Views
php artisan vendor:publish --tag=legal-documents-views
Views will be published to resources/views/vendor/legal-documents/.
Publishing Translations
php artisan vendor:publish --tag=legal-documents-lang
Translations will be published to lang/vendor/legal-documents/.
Custom Notification
Create your own notification class and configure it:
// config/legal-documents.php 'notifications' => [ 'class' => App\Notifications\CustomLegalDocumentUpdated::class, ],
Custom Layout
Configure the layout used for the document view page:
// config/legal-documents.php 'frontend' => [ 'layout' => 'layouts.app', // Your layout file ],
API Reference
HasLegalAcceptances Trait
| Method | Description |
|---|---|
legalAcceptances() |
HasMany relationship to acceptances |
hasAcceptedDocument(LegalDocument $document) |
Check if user accepted a specific document |
hasAcceptedLatest(string $typeSlug) |
Check if user accepted latest version of a document type |
getPendingDocuments() |
Get all documents pending acceptance |
needsToAcceptDocuments() |
Check if user has pending documents |
acceptDocument($document, $ip, $userAgent) |
Accept a single document |
acceptDocuments($ids, $ip, $userAgent) |
Accept multiple documents |
getAcceptanceHistory() |
Get user's acceptance history |
getDocumentAcceptance(LegalDocument $document) |
Get acceptance record for a specific document |
getPendingDocumentsForRoles() |
Get pending documents filtered by user's roles |
getRequiredDocumentsForRoles(array $roles) |
Get required documents for specific roles |
needsToAcceptDocumentsForRoles() |
Check if user needs to accept documents based on roles |
LegalDocument Model
| Method | Description |
|---|---|
publish() |
Publish the document and notify users |
scopeCurrent($query) |
Query scope for current documents |
scopePublished($query) |
Query scope for published documents |
scopeRequiresAcceptance($query) |
Query scope for documents requiring acceptance |
LegalDocumentType Model
| Method | Description |
|---|---|
currentDocument |
Relationship to current document |
documents |
Relationship to all documents |
scopeRequired($query) |
Query scope for required document types |
scopeOrdered($query) |
Query scope for ordered by sort_order |
scopeRequiredForRoles($query, array $roles) |
Query scope for documents required for specific roles |
scopeRequiredForUser($query, $user) |
Query scope for documents required for a specific user |
isRequiredForUser($user) |
Check if document type is required for a specific user |
isRequiredForRoles(array $roles) |
Check if document type is required for specific roles |
rolesEnabled() |
Check if role-based requirements are enabled |
getAvailableRoles() |
Get available roles (auto-detects Spatie Permission) |
Events
The package dispatches the following events:
- Document published → Sends
LegalDocumentUpdatednotification to users
Testing
composer test
Changelog
Please see CHANGELOG for more information on what has changed recently.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
The MIT License (MIT). Please see License File for more information.