Features
Activity & notifications
Externa records domain and auth events with Spatie Activitylog, exposes an Activity Log admin page (and an AI query tool), and delivers file job outcomes through database notifications in the sidebar bell.

Related
Privacy / hosting: Threat model & hosting. Team chat events: Chat (hub & items). Dashboard widgets that read activity: Dashboard. File jobs that emit notifications: File manager. Realtime bell / presence: Reverb & Echo. AI logging helpers: AI assistant model.
Spatie Activitylog
| Item | Detail |
|---|---|
| Package model | Spatie\Activitylog\Models\Activity |
| Config | config/activitylog.php |
| Env toggle | ACTIVITYLOG_ENABLED |
| Retention | clean_after_days = 365 |
| Default log name | default |
| Cleanup | Schedule::command('activitylog:clean')->daily() |
LogsApplicationActivity
Trait: App\Concerns\LogsApplicationActivity (wraps Spatie LogsActivity).
Options: logAll(), logOnlyDirty(), dontLogEmptyChanges(), useLogName('default').
Used on: User, UserGroup, Role, Collection, CollectionField, CollectionItem, File, FileVersion, FileUpload, ApiKey (with secret exclusions where applicable).
Item editors surface a compact activity strip (last update + revisions/activity links). Field-level history remains in Item History, not Spatie attribute diffs.
Privacy defaults
Activity properties and chat bodies are plaintext in the database (no column encryption). Chat create/delete events store a lean body_preview (≤ 120 characters) plus counts — not a full encrypted transcript. Restrict who has can-show-activity-logs. Operators should encrypt DB volumes and backups; see Threat model & hosting.
Auth login / logout / failed
Registered in AppServiceProvider::registerAuthActivityListeners():
| Event | Log name | Activity event | Description / notes |
|---|---|---|---|
Illuminate\Auth\Events\Login | auth | login | User logged in; also updates last_login_at / last_login_ip |
Logout | auth | logout | User logged out |
Failed | auth | failed | Failed login attempt; causedByAnonymous(), property identifier |
AI activity
App\Ai\Support\AiActivityLogger writes log_name=ai with events ai_prompt, ai_response, ai_tool, ai_mutation.
Activity Log UI
| Item | Detail |
|---|---|
| Controller | App\Http\Controllers\Admin\ActivityLogController |
| Route | GET /activity-logs (activity-logs.index) |
| Middleware | auth, verified, permission:can-show-activity-logs |
| Permission | can-show-activity-logs |
| Page | resources/js/pages/admin/activity-logs/index.tsx |
Filters: search, user_ids[] (multi; legacy user_id still accepted), event, log_name, date_from, date_to, optional subject_type + subject_id (used by the item form Activity link).
Log names include default, auth, ai, chat, settings.
Filterable events (App\Support\Activity\FilterableActivityEvents):
created | updated | deleted | restored
login | logout | failed
ai_prompt | ai_response | ai_tool | ai_mutation
settings_updated
chat_message | chat_message_deleted
permissions_synced | roles_synced | groups_synced | members_synced
collection_permissions_synced | file_permissions_synced
Expanded rows show Spatie attribute_changes when present, otherwise manual properties.meta (e.g. chat body_preview).
AI QueryActivityLogs
| Item | Detail |
|---|---|
| Tool | App\Ai\Tools\QueryActivityLogs |
| Gate | can-show-activity-logs |
| Limits | Default 25, max 50 |
| Dates | YYYY-MM-DD only |
| Events | Same set as the UI filters |
Registered on AppAssistant when the user has can-show-activity-logs.
Notifications (database + bell)
Most use trait BroadcastsWithDatabase: via(['database']), plus broadcast when BROADCAST_CONNECTION is not log/null.
| Class | data.type | Emitted from |
|---|---|---|
App\Notifications\FileZipReadyNotification | file_zip_ready | PrepareFilesZipJob |
App\Notifications\FileZipFailedNotification | file_zip_failed | PrepareFilesZipJob |
App\Notifications\FileDuplicationCompletedNotification | file_duplication_completed | DuplicateFilesJob |
App\Notifications\FileDuplicationFailedNotification | file_duplication_failed | DuplicateFilesJob |
App\Notifications\ItemChatNotification | chat | Team chat mentions / notify-me |
Zip-ready notifications point at download route files.zips.download. Chat bell rows deep-link into the hub / item thread.
Realtime delivery (Echo private channel App.Models.User.{id}) is documented in Reverb & Echo. When BROADCAST_CONNECTION is log/null, the sidebar bell keeps its 60s unread poll; with Reverb enabled there is no periodic poll — Echo .notification() updates the badge.
Bell API
| Item | Detail |
|---|---|
| Controller | App\Http\Controllers\NotificationController |
| Routes | routes/web.php |
| Middleware | auth + verified only — no activity-log permission |
| UI | NotificationsBell + NotificationsDrawer in the sidebar |
| Client | resources/js/lib/notifications-api.ts |
| Method | Path | Name | Behavior | | --- | --- | --- | | GET | /notifications | notifications.index | Paginate 20 | | GET | /notifications/unread-count | notifications.unread-count | Unread count | | POST | /notifications/read | notifications.read | Mark read (ids and/or all unread) | | POST | /notifications/unread | notifications.unread | Mark unread (ids required, non-empty) |
Drawer UX
- Opening the drawer does not auto-mark page-1 notifications as read (badge stays until the user acts).
- Mark all as read is an explicit header action (
data-test="notifications-mark-all-read"). - Mark as unread appears on already-read rows (
data-test="notifications-mark-unread") and restores the badge count from the API response.
There is no dedicated notification permission in PermissionEnum; any authenticated verified user can use the bell API for their own notifications.
Permissions summary
| Surface | Permission |
|---|---|
Activity Log page + QueryActivityLogs | can-show-activity-logs |
| Notifications bell / API | Authenticated + verified (no enum gate) |
Source map
| Concern | Location |
|---|---|
| Activity controller | app/Http/Controllers/Admin/ActivityLogController.php |
| Logging trait | app/Concerns/LogsApplicationActivity.php |
| Auth listeners | AppServiceProvider::registerAuthActivityListeners |
| AI query tool | app/Ai/Tools/QueryActivityLogs.php |
| Notifications | app/Notifications/FileZip*Notification.php, FileDuplication*Notification.php, ItemChatNotification.php |
| Bell API | app/Http/Controllers/NotificationController.php |
