Day 5 – Explaining Audit Logs by Role and Department#LaravelGPTAudit #RoleBasedAudit #TeamActivityReport #LaravelAI


Today we’ll take our audit system to the next level by grouping logs by user role and department, then asking GPT to summarize team activity clearly — useful for manager-level reporting or compliance review.


🧩 Step 1: Ensure roles and departments are accessible

Assuming each User has:

  • roles() relationship (many-to-many or Spatie roles)
  • department() relationship

In User.php:

public function roles()
{
    return $this->belongsToMany(Role::class);
}

public function department()
{
    return $this->belongsTo(Department::class);
}

🧠 Step 2: Update GPT helper for role/department grouping

Extend AuditSummaryHelper.php:

public static function summarizeByRole(array $logs): string
{
    $grouped = collect($logs)->groupBy(function ($log) {
        $user = $log->causer;
        $role = optional($user)->roles->pluck('name')->join(', ') ?? 'Unknown';
        $dept = optional($user)->department->name ?? 'No Dept';
        return "$role / $dept";
    });

    $output = $grouped->map(function ($group, $key) {
        $lines = $group->map(fn($log) =>
            "- {$log->created_at->format('Y-m-d H:i')} | " .
            (optional($log->causer)->name ?? 'System') . " | {$log->description}"
        )->implode("\n");

        return "## $key\n$lines";
    })->implode("\n\n");

    $prompt = <<<PROMPT
You are a Laravel audit analyst. Summarize the following user activity logs by team (role and department). Provide a clear summary per group.

$output

Team Summary:
PROMPT;

    $response = OpenAI::chat()->create([
        'model' => 'gpt-4o',
        'messages' => [
            ['role' => 'user', 'content' => $prompt],
        ],
        'max_tokens' => 500,
    ]);

    return $response->choices[0]->message->content ?? 'No team summary generated.';
}

🔁 Step 3: Add route and controller method

In web.php:

Route::post('/audit-logs/roles-summary', [\App\Http\Controllers\AuditLogController::class, 'rolesSummary'])->name('audit.logs.roles.summary');

In AuditLogController.php:

public function rolesSummary(Request $request)
{
    $logs = \Spatie\Activitylog\Models\Activity::with('causer.roles', 'causer.department')->latest()->take(50)->get();
    $summary = \App\Helpers\AuditSummaryHelper::summarizeByRole($logs);

    return back()->with('role_summary', $summary);
}

📄 Step 4: Add button and output to view

In index.blade.php:

<form method="POST" action="{{ route('audit.logs.roles.summary') }}" class="mb-4 inline-block">
    @csrf
    <button class="bg-indigo-500 text-white px-3 py-1 rounded">Summarize by Role/Department</button>
</form>

@if(session('role_summary'))
    <div class="bg-indigo-100 text-indigo-900 p-3 rounded mb-4 whitespace-pre-wrap">
        <strong>GPT Role/Department Summary:</strong><br>
        {!! nl2br(e(session('role_summary'))) !!}
    </div>
@endif

✅ Example Output

GPT Role/Department Summary:
Admin / SOC

  • Admin created 4 vehicle renewals and edited 2 payment plans.

Finance Manager / Finance

  • Finance Manager deleted 3 expired customer plans and added 1 discount.

✅ Tomorrow (Day 6), we’ll automate weekly/monthly audit reports with GPT-generated summaries and email them directly to stakeholders.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.