Auditify is an easy-to-use, high-performance audit logging and threat detection package for Laravel.
🔗 Official Landing Page & Demo: arpa12.github.io/laravel-auditify-landingPage
Unlike standard logging libraries, Auditify uses a decoupled database design to separate logs into three distinct tables. This optimizes database table indexing, reduces write congestion, and guarantees clean scale organization as your application grows.
- Requirements
- Features
- Installation
- Configuration
- Manual Logging & Helper Methods
- Artisan Commands
- Routes Reference
- Testing
- Author
- License
| Laravel | PHP |
|---|---|
| 13.x | 8.3 – 8.4 |
| 11.x, 12.x | 8.2 – 8.4 |
| 10.x | 8.2 – 8.3 |
URL: /auditify
The main glassmorphic dashboard aggregates action logs, page visits, and threat alerts into an interactive screen:
- Metrics counters — total action logs, activity logs, and security logs with unread indicators.
- Log summaries — breakdowns of operations (Create, Update, Delete) and authentication events (Login, Logout).
- 7-day trend graph — comparative daily counts of Actions vs Activities plotted on Chart.js.
- Top active users & top modified modules — lists of most active user IDs and frequently changed models.
- Live recent logs — lists of the most recent visitor actions and security alerts.
URL: /auditify/reports
A comprehensive reporting panel offering detailed statistical breakdowns over custom timeframes (Last 7 Days, Last 30 Days, or Last 90 Days) featuring interactive Chart.js charts:
- Overview Analytics: System log activity trends mapped using multi-line charts.
- Action Reports: Actions by type (Doughnut Chart) and most changed models (Horizontal Bar Chart), coupled with a detailed database modifications table and CSV/Excel/PDF download options.
- Activity Reports: Top visited pages/URLs (Horizontal Bar Chart) and peak activity hours (Bar Chart), coupled with a detailed activity table and CSV/Excel/PDF download options.
- Security Reports: Alerts by severity (Doughnut Chart), top threat origin IPs (Bar Chart), and resolution status distribution (Pie Chart), coupled with a detailed security incident table and CSV/Excel/PDF download options.
- Format Exports: Support for exporting timeframe-filtered reports in CSV, Excel (xlsx), and clean printable PDF formats.
Auditify separates data logging into three target models under Auditify\Models to avoid write bottlenecks. Here is the exact database schema and attributes captured for each log type:
- Table Name:
audit_action_logs - Purpose: Tracks Eloquent database modifications (inserts, updates, deletes, and restores).
- Captured Attributes / Database Columns:
id(BigInt, Primary Key)user_id&user_type(Nullable Morphs) — Polymorphic relationship to the user making the database modification.subject_id&subject_type(Nullable Morphs) — Polymorphic relationship to the actual model being modified.action(String) — The query event (created,updated,deleted,restored).module(String) — Name of the affected model module/class (e.g.,Post,User,Role).description(Text, Nullable) — Friendly readable log summary description.old_values(JSON, Nullable) — Casted array of model attribute values before the operation.new_values(JSON, Nullable) — Casted array of model attribute values after the operation.ip_address(String, Nullable) — IP address of the client triggering the event.url(Text, Nullable) — HTTP Request URL where the change originated.user_agent(Text, Nullable) — HTTP User-Agent string.created_at&updated_at(Timestamps)
- Table Name:
audit_activity_logs - Purpose: Logs visitor requests, navigation, custom application actions, and auth flows. Features a dedicated detail page view (
GET /activity-logs/{id}) to inspect logged metadata. - Captured Attributes / Database Columns:
id(BigInt, Primary Key)user_id&user_type(Nullable Morphs) — Polymorphic relationship to the visitor (if authenticated).activity(String) — The type of operation/activity (e.g.,Page Visit,Login,Logout,Failed Login, or custom events).properties(JSON, Nullable) — Casted array storing context metadata or custom event payloads.url(Text, Nullable) — Request URL path.ip_address(String, Nullable) — Visitor IP address.user_agent(Text, Nullable) — Visitor User-Agent string.created_at&updated_at(Timestamps)
- Table Name:
audit_security_logs - Purpose: Logs alerts generated by the XSS protection middleware, rate limits, or automated threat rules.
- Captured Attributes / Database Columns:
id(BigInt, Primary Key)user_id&user_type(Nullable Morphs) — Polymorphic relationship to the user (if authenticated).severity(String) — Alert priority (low,medium,high,critical).title(String) — Brief name of the incident (e.g.,XSS Attack Blocked,Failed Logins Peak).description(Text, Nullable) — In-depth details regarding why the threat was flagged.is_read(Boolean) — Read/unread toggle flag for admin dashboard alerts.status(String) — Alert resolution state (pendingorresolved).resolved_at(DateTime, Nullable) — Timestamp when the incident was marked resolved/read.resolution_notes(Text, Nullable) — Text explaining the resolution strategy.method(String, Nullable) — Request HTTP method (GET,POST, etc.).route_name(String, Nullable) — Named route where the attack/alert occurred.payload(JSON, Nullable) — Casted request body payload parameters scanned by the security shield.ip_address(String, Nullable) — Origin IP address of the incident.user_agent(Text, Nullable) — Incident Client User-Agent.created_at&updated_at(Timestamps)
Auditify automatically monitors activity logs and logs high-priority Security entries when rules are broken:
- Mass Delete Shield: Fires a
criticalsecurity log if a user deletes 5 or more records (default) in a single model within 5 minutes. - Bulk Update Shield: Fires a
highsecurity log if a user updates 10 or more records (default) in a single model within 5 minutes. - Failed Logins monitor: Tracks failed logins. Fires a
highsecurity log if 3 or more failed login attempts are recorded within 5 minutes. - Sensitive Module monitor: Triggers a
mediumsecurity log whenever models listed insensitive_modules(e.g.User,Role,Permission,Setting,Config) are modified. - Permission Changes: Triggers a
highsecurity log whenever a permission, role, or gate mapping is added, modified, or deleted.
Auditify has built-in XSS protection. It automatically scans all incoming request parameters (such as $_GET or $_POST) and route variables.
If it detects common XSS patterns (like <script>, javascript:, or SVG events), it:
- Logs a critical security log entry.
- Returns an HTTP
403 Forbiddenresponse to block the request.
If you have pages that require rich text input (e.g. admin markdown or HTML editors), exclude them in your config/auditify.php file:
'xss_protection' => [
'enabled' => true,
'block' => true,
'exclude_routes' => [
'admin/articles/*',
'posts/*/edit',
],
],Note
What is this for? Standard backend code (like Laravel/PHP) cannot see what happens inside the user's browser. Out-of-the-box, it cannot track when a user clicks a button, closes a modal, or downloads a file.
This API provides a built-in route (/auditify/api/events) so you can easily send browser actions straight into your Activity Logs via JavaScript—without needing to write your own custom API controllers and routes. You can ignore this if you don't need to track frontend actions.
- Create a reusable JavaScript helper to send a
POSTrequest (which automatically attaches Laravel's CSRF security token):
function logEvent(eventName, description) {
fetch('/auditify/api/events', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
},
body: JSON.stringify({
event_name: eventName,
description: description
})
})
.then(response => response.json())
.then(data => console.log('Event logged:', data))
.catch(error => console.error('Error logging event:', error));
}- Trigger it on user actions (like clicking a button or a download link):
<!-- Example 1: Track a File Download -->
<a href="/downloads/guide.pdf" onclick="logEvent('File Download', 'User downloaded the User_Guide.pdf document')">
Download User Guide
</a>
<!-- Example 2: Track a checkout button click -->
<button onclick="logEvent('Checkout Init', 'User clicked the Checkout button')">
Proceed to Payment
</button>If your application uses a frontend framework like React or Vue.js:
- Same-domain or Laravel Inertia: You can call the
/auditify/api/eventsendpoint directly usingaxiosorfetch. Session cookies and CSRF security are handled automatically by the browser. - Decoupled Setup (Different Domains): If your React/Vue frontend is hosted separately from your Laravel API:
- Add your frontend domain to the allowed origins list in Laravel's CORS configuration (
config/cors.php). - Authenticate requests via Laravel Sanctum or standard authorization headers so Auditify can link the logged events to the correct user.
- Add your frontend domain to the allowed origins list in Laravel's CORS configuration (
import React, { useState } from 'react';
import axios from 'axios';
// IMPORTANT: Enable session cookie sharing across domains if your frontend
// runs on a different port/subdomain from your Laravel backend (e.g. localhost:3000 vs localhost:8000).
axios.defaults.withCredentials = true;
// Configure this URL to match your Laravel application route
const AUDITIFY_API_URL = 'http://localhost:8000/auditify/api/events';
export default function UpgradeButton() {
// Track loading state to prevent double clicks and duplicate event logging
const [isLoading, setIsLoading] = useState(false);
const handleUpgrade = async () => {
setIsLoading(true);
try {
// 1. Run your standard application business logic (e.g. payment gateway checkout)
console.log("Upgrading plan...");
// 2. Fetch the CSRF validation token from the host HTML meta tag.
// Note: If running decoupled (CORS), you may need to fetch the token via Sanctum.
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
// 3. Log the frontend event directly to the Auditify package
await axios.post(AUDITIFY_API_URL, {
event_name: 'Upgrade Plan Clicked',
description: 'User initiated subscription upgrade to Gold tier.'
}, {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': csrfToken // Pass the CSRF token to pass Laravel's VerifyCsrfToken middleware
}
});
alert('Plan upgraded successfully and logged in Auditify!');
} catch (error) {
console.error('Error logging event to Auditify backend:', error);
} finally {
// Reset the loading state
setIsLoading(false);
}
};
return (
<button onClick={handleUpgrade} disabled={isLoading}>
{isLoading ? 'Processing...' : 'Upgrade to Gold Plan 🚀'}
</button>
);
}<template>
<div class="pricing-card">
<!-- Bind disabled state to loading to prevent double submissions -->
<button @click="handleUpgrade" :disabled="isLoading">
{{ isLoading ? 'Processing...' : 'Upgrade to Gold Plan 🚀' }}
</button>
</div>
</template>
<script setup>
import { ref } from 'vue';
// Reactive state to manage user action processing
const isLoading = ref(false);
// Configure this URL to match your Laravel application route
const AUDITIFY_API_URL = 'http://localhost:8000/auditify/api/events';
const handleUpgrade = async () => {
isLoading.value = true;
try {
// 1. Run your standard application business logic (e.g. payment gateway checkout)
console.log("Upgrading plan...");
// 2. Retrieve the CSRF token from the meta tag to authenticate the session request
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') || '';
// 3. Dispatch the event payload to the Auditify package logs endpoint
const response = await fetch(AUDITIFY_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-CSRF-TOKEN': csrfToken // Pass the CSRF token to pass Laravel's VerifyCsrfToken middleware
},
body: JSON.stringify({
event_name: 'Upgrade Plan Clicked',
description: 'User initiated subscription upgrade to Gold tier in Vue application.'
})
});
if (response.ok) {
alert('Plan upgraded successfully and logged in Auditify!');
} else {
console.error('Auditify endpoint returned an error response:', await response.text());
}
} catch (error) {
console.error('Network error attempting to log event:', error);
} finally {
// Reset status
isLoading.value = false;
}
};
</script>Important
Who should access the logs?
The Auditify log database and visual dashboard (/auditify) contain highly sensitive information including user IP addresses, request payloads, model modifications, and security alert histories.
Regular application users must never have access to this package. It is designed exclusively for system administrators, super-admins, and security officers.
By default, the package enables access control if configured in config/auditify.php. You should register an authorization callback inside your application so developers can custom-define exactly who is classified as an authorized admin.
To restrict dashboard views and log downloads to administrators only, register an authorization callback inside the boot method of your app/Providers/AppServiceProvider.php:
use Auditify\Facades\Auditify;
public function boot()
{
// Restrict all Auditify dashboard and API routes to Admin users
Auditify::auth(function ($request) {
// Option A: Check user role (e.g. if using Spatie Role package)
return $request->user() && $request->user()->hasRole('admin');
// Option B: Check simple is_admin database flag
// return $request->user() && $request->user()->is_admin;
// Option C: Check a specific company email domain
// return $request->user() && str_ends_with($request->user()->email, '@yourcompany.com');
});
}Run this command in your project root:
composer require arpanihan/auditifyRun the installation command to publish configuration files, copy migrations, and set up your database automatically (this command will also automatically clear your application cache using optimize:clear):
php artisan auditify:installIf needed, you can manually clear all cached configuration, routes, views, and other cached data to ensure Auditify loads the latest settings:
php artisan optimize:clearIf your application is not already running, start the Laravel development server:
php artisan serveOnce the installer completes successfully, open your web browser and navigate to the Auditify dashboard URL:
http://your-domain.local/auditify(Note: If you change the 'route_prefix' config setting inside config/auditify.php, this route URL will update accordingly).
By default, Auditify automatically audits all Eloquent models globally without any manual setup.
However, if you turn off global auditing ('auto_audit_models' => false) and prefer to manually select which models to audit, add the Auditable trait:
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Auditify\Traits\Auditable;
class Product extends Model
{
use Auditable;
}After publishing, customize your settings in config/auditify.php:
return [
// Base URL route prefix: https://your-domain.com/auditify
'route_prefix' => 'auditify',
// Dashboard visual layout theme: 'dark' or 'light'
'theme' => 'dark',
// Middlewares applied to the dashboard routes
'middleware' => [
'web',
],
// Log entries shown per page
'pagination' => 20,
// Track details
'track_ip' => true,
'track_user_agent' => true,
'track_url' => true,
// Authorization configuration
'authorization' => [
'enabled' => false,
'gate' => 'view-auditify',
],
// Automatic tracking configurations
'track_auth_events' => true, // Login, Logout, Failed logins
/*
* Mappings of user attributes for email, username, and phone numbers.
* These will be dynamically extracted from your User model/login credentials.
*/
'user_fields' => [
'email' => 'email',
'username' => 'username',
'phone' => 'phone',
],
'track_page_visits' => true, // Page visits
// Threat alerting configurations & thresholds
'alerts' => [
'enabled' => false,
'recipients' => ['admin@example.com'],
'channels' => ['mail', 'log'],
'sensitive_modules' => ['User', 'Role', 'Permission', 'Setting', 'Config'],
'thresholds' => [
'failed_logins' => 3,
'failed_logins_timeframe' => 5, // minutes
'mass_delete' => 5,
'mass_delete_timeframe' => 5, // minutes
'bulk_update' => 10,
'bulk_update_timeframe' => 5, // minutes
],
],
// Firewall scanning
'xss_protection' => [
'enabled' => true,
'block' => true, // Abort requests with HTTP 403 when script is found
'exclude_routes' => [
// 'admin/rich-text/*',
],
],
// Global model auditing
'auto_audit_models' => true, // Tracks all model lifecycle changes globally
/*
* Interval (in seconds) for frontend auto-polling of new unread security alerts.
* Set to 60 or higher for better performance, or set to 0 to disable polling entirely.
*/
'security_polling_interval' => 0,
'exclude_models' => [ // Model classes to exclude from global auditing
// App\Models\Session::class,
],
// Pruning configuration
'pruning' => [
'keep_days' => 90, // Default age in days for keeping historical log rows
],
];You can manually trigger Auditify logs or temporarily pause auditing from your own Laravel controllers, background jobs, or seeders using the Auditify facade.
Tip
Why use manual logging?
- Capture Intent over CRUD: Automated auditing only tracks database changes (inserts/updates). It cannot know when a user performs a non-CRUD action like downloading a PDF report, requesting a password reset, or opening a modal.
- Standardize Multi-step Workflows: Instead of cluttering logs with 10 automated database change entries during a checkout flow, you can pause automatic logging and write a single, clean entry (e.g.,
User Completed Purchase). - Log Custom Threat Metrics: Manually document custom suspicious behaviors (like rate-limit hits, coupon code abuse, or restricted API probes) using
Auditify::logSecurity. - Optimize Seeding & Imports: Turn off auditing during massive database seeding or CSV user imports to prevent database write congestion, performance lags, and log spam.
Import the facade in your file:
use Auditify\Facades\Auditify;Auditify::logAction(
action: 'PUBLISH',
module: 'Article',
description: 'User published a new article',
oldValues: ['status' => 'draft'],
newValues: ['status' => 'published'],
userId: auth()->id(), // optional, defaults to current authenticated user
subject: $article // optional, polymorphic eloquent model instance
);Auditify::logActivity(
activity: 'Exported Reports (PDF)',
url: request()->fullUrl(), // optional, defaults to request URL
userId: auth()->id(), // optional
properties: ['timeframe' => '30_days'] // optional metadata payload
);Auditify::logSecurity(
title: 'Suspicious Endpoint Access',
description: 'Blocked access attempt to restricted legacy endpoint',
severity: 'high', // options: low, medium, high, critical
payload: request()->all() // optional JSON request context
);Here is a practical example of how to implement manual logging inside a standard Laravel controller, complete with code comments:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Order;
use Auditify\Facades\Auditify; // Import the Auditify facade
class OrderController extends Controller
{
/**
* Cancel a customer order and log the audit trail.
*/
public function cancel(Request $request, $id)
{
// 1. Retrieve the order record from the database
$order = Order::findOrFail($id);
// Capture the original status for audit comparison
$oldStatus = $order->status;
// 2. Perform the cancellation business logic
$order->update([
'status' => 'cancelled',
'cancelled_at' => now(),
'cancellation_reason' => $request->input('reason')
]);
// 3. Manually Log a database Action showing the status transition
Auditify::logAction(
action: 'CANCEL_ORDER',
module: 'Order',
description: "Order #{$order->id} cancelled by user due to: " . $request->input('reason'),
oldValues: ['status' => $oldStatus],
newValues: ['status' => 'cancelled'],
userId: auth()->id(), // Associate log with the logged-in administrator
subject: $order // Link the polymorphic subject relation to this order model
);
// 4. Log a general user activity for dashboard stats tracking
Auditify::logActivity(
activity: 'Cancelled Order',
properties: [
'order_id' => $order->id,
'total_amount' => $order->total_price
]
);
// 5. Send a redirect response back to the admin portal
return redirect()->back()->with('success', 'Order cancelled and action audited.');
}
}When running data migrations, database seeders, or large CSV imports, you should temporarily disable logging:
- Prevent Database Congestion (Performance): Auditing bulk inserts doubles database queries (100k records = 200k queries). Pausing logs prevents database lockups and speeds up imports.
- Prevent Table Bloat (Log Spam): Seeders generate fake mock data. Pausing auditing prevents these fake records from filling up your audit log tables and slowing down search speeds.
Where to use: In database/seeders/DatabaseSeeder.php or data migration files.
This helper automatically pauses auditing for the duration of the callback execution and safely restores the previous auditing state.
Tip
Why Option A is recommended (Exception Safe):
If an error occurs inside your import/seeder logic, this helper uses an underlying PHP finally block to guarantee that auditing is safely re-enabled for all subsequent requests.
use Auditify\Facades\Auditify;
// Pauses auditing automatically for the duration of the callback function
Auditify::withoutAuditing(function () {
// Generate 1,000 dummy articles silently without log spam
Article::factory()->count(1000)->create();
});Where to use: In custom Artisan console commands (app/Console/Commands/ImportData.php) or PHPUnit test setups (tests/TestCase.php).
Directly turns the auditing flag on or off.
Warning
Use Option B with caution:
If your code throws an exception after calling disableAuditing(), it will crash before reaching enableAuditing(), leaving auditing permanently disabled on that PHP worker/process. Only use this option when a closure structure cannot be used.
use Auditify\Facades\Auditify;
// 1. Manually disable auditing
Auditify::disableAuditing();
// 2. Perform sequential operations...
User::insert($massiveCsvData);
// 3. Manually re-enable auditing
Auditify::enableAuditing();Auditify provides dedicated commands to automate installation and database size optimization:
| Command | Description |
|---|---|
auditify:install |
Runs migrations and publishes configuration files automatically. |
auditify:prune {--days=} |
Deletes old audit log records older than N days (defaults to keep_days config value). |
auditify:install(Simpler Onboarding): Eliminates manual setup. Rather than forcing developers to copy configurations, move migration files, and migrate tables separately, this sets up the entire package in a single terminal line.auditify:prune(Optimize DB Speed & Storage): High-traffic production systems generate millions of logs. Storing logs indefinitely slows down database queries, increases backup sizes, and increases storage costs. Pruning deletes outdated entries, ensuring instant dashboard rendering and compliance retention alignment (e.g., GDPR, SOC2).
To keep database tables small and performant automatically, schedule the pruning command in your application's task scheduler in routes/console.php (or app/Console/Kernel.php):
Tip
Set It and Forget It: Automating the pruning command to run daily ensures your database size remains constrained and healthy without manual administrator intervention. It is recommended to schedule it during low-traffic night hours.
use Illuminate\Support\Facades\Schedule;
Schedule::command('auditify:prune --days=90')->daily();All routes are grouped under the configured route_prefix (default: auditify) with the configured middleware.
| Method | URI | Controller Action | Description |
|---|---|---|---|
| GET | / |
DashboardController@index |
Main logs dashboard index |
| GET | /action-logs |
ActionLogController@index |
View list of database action logs |
| GET | /action-logs/{id} |
ActionLogController@show |
View details with side-by-side attributes difference |
| GET | /action-logs/export/csv |
ActionLogController@exportCsv |
Export action logs in CSV format |
| GET | /action-logs/export/excel |
ActionLogController@exportExcel |
Export action logs in Excel format |
| GET | /action-logs/export/pdf |
ActionLogController@exportPdf |
Export action logs in PDF format |
| GET | /activity-logs |
ActivityLogController@index |
View list of activity logs |
| GET | /activity-logs/{id} |
ActivityLogController@show |
View activity log details |
| GET | /activity-logs/export/csv |
ActivityLogController@exportCsv |
Export activity logs in CSV format |
| GET | /activity-logs/export/excel |
ActivityLogController@exportExcel |
Export activity logs in Excel format |
| GET | /activity-logs/export/pdf |
ActivityLogController@exportPdf |
Export activity logs in PDF format |
| GET | /security-logs |
SecurityLogController@index |
View list of security logs |
| GET | /security-logs/unread-check |
SecurityLogController@checkUnreadAlerts |
Live alert poll check |
| GET | /security-logs/{id} |
SecurityLogController@show |
View security log details |
| POST | /security-logs/{id}/read |
SecurityLogController@markAsRead |
Toggle log read state |
| GET | /security-logs/export/csv |
SecurityLogController@exportCsv |
Export security logs in CSV format |
| GET | /security-logs/export/excel |
SecurityLogController@exportExcel |
Export security logs in Excel format |
| GET | /security-logs/export/pdf |
SecurityLogController@exportPdf |
Export security logs in PDF format |
| POST | /api/events |
ActivityLogController@storeFrontendEvent |
Frontend client-side interaction logging |
| GET | /reports |
ReportController@index |
View detailed log analytics and reports |
The package features a comprehensive PHPUnit test suite covering models, middlewares, controller endpoints, and Artisan commands. Standalone tests run via orchestra/testbench without requiring a parent Laravel installation.
Clone the repository and install development dependencies:
git clone https://github.com/arpa12/laravel-auditify.git
cd laravel-auditify
composer installRun all tests:
./vendor/bin/phpunit
Arpa Nihan
Full Stack Developer
Released under the MIT License.
MIT License
Copyright (c) 2026 Arpa Nihan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
⭐ If Auditify saves you time, please give it a star on GitHub! ⭐
Made with ❤️ for the Laravel Community
Copyright © 2026 Arpa Nihan. All rights reserved.
