## Summary - turn the Monitoring audit log placeholder into a real workspace-scoped audit review surface - introduce a shared audit recorder, richer audit value objects, and additive audit log schema evolution - add audit outcome and actor badges, permission-aware related navigation, and durable audit retention coverage ## Included - canonical `/admin/audit-log` list and detail inspection UI - audit model helpers, taxonomy expansion, actor/target snapshots, and recorder/builder services - operation terminal audit writes and purge command retention changes - spec 134 design artifacts and focused Pest coverage for audit foundation behavior ## Validation - `vendor/bin/sail bin pint --dirty --format agent` - `vendor/bin/sail artisan test --compact tests/Unit/Audit tests/Unit/Badges/AuditBadgesTest.php tests/Feature/Filament/AuditLogPageTest.php tests/Feature/Filament/AuditLogDetailInspectionTest.php tests/Feature/Filament/AuditLogAuthorizationTest.php tests/Feature/Monitoring/AuditCoverageGovernanceTest.php tests/Feature/Monitoring/AuditCoverageOperationsTest.php tests/Feature/Console/TenantpilotPurgeNonPersistentDataTest.php` ## Notes - Livewire v4.0+ compliance is preserved within the existing Filament v5 application. - No provider registration changes were needed; panel provider registration remains in `bootstrap/providers.php`. - No new globally searchable resource was introduced. - The audit page remains read-only; no destructive actions were added. - No new asset pipeline changes were introduced; existing deploy-time `php artisan filament:assets` behavior remains unchanged. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #163
281 lines
11 KiB
Markdown
281 lines
11 KiB
Markdown
# Data Model: Audit Log Foundation
|
|
|
|
**Feature**: 134-audit-log-foundation | **Date**: 2026-03-11
|
|
|
|
## Overview
|
|
|
|
This feature extends an existing persisted entity rather than introducing a second audit-history store. The design adds a first-class event model, normalized actor and target snapshots, and a canonical read model for the Monitoring audit page.
|
|
|
|
The main model layers are:
|
|
|
|
1. `AuditLog` as the durable event record,
|
|
2. normalized event taxonomy and outcome semantics,
|
|
3. actor and target snapshots captured at write time,
|
|
4. structured context payloads with redaction,
|
|
5. a workspace-scoped audit list and detail read model.
|
|
|
|
## Existing Persistent Entity to Evolve
|
|
|
|
### AuditLog
|
|
|
|
Current persisted shape already includes:
|
|
|
|
| Attribute | Type | Notes |
|
|
|-----------|------|-------|
|
|
| `id` | int | Existing primary key |
|
|
| `tenant_id` | int nullable | Existing tenant scope field |
|
|
| `workspace_id` | int nullable | Added later for workspace-scoped events |
|
|
| `actor_id` | int nullable | Existing actor identifier |
|
|
| `actor_email` | string nullable | Existing actor display fallback |
|
|
| `actor_name` | string nullable | Existing actor display fallback |
|
|
| `action` | string | Existing event key |
|
|
| `resource_type` | string nullable | Existing target-type precursor |
|
|
| `resource_id` | string nullable | Existing target-id precursor |
|
|
| `status` | string | Existing outcome precursor |
|
|
| `metadata` | json nullable | Existing structured payload precursor |
|
|
| `recorded_at` | timestamp | Existing event time |
|
|
|
|
Planned first-class audit semantics to add or formalize:
|
|
|
|
| Target Semantic | Likely Storage Shape | Purpose |
|
|
|-----------------|----------------------|---------|
|
|
| `event_type` or normalized action | existing `action` reused or renamed semantically | Stable taxonomy key |
|
|
| `summary` | new string/text column | Human-readable list/detail summary |
|
|
| `outcome` | new column or normalized use of `status` | Explicit success/failure/partial/info/blocked state |
|
|
| `actor_type` | new string column | Human/system/scheduled/integration distinction |
|
|
| `actor_label` | derived from existing name/email or new snapshot field | Stable readable actor label |
|
|
| `target_type` | existing `resource_type` reused or normalized | Stable target taxonomy key |
|
|
| `target_id` | existing `resource_id` reused or normalized | Structured target identity |
|
|
| `target_label` | new string column | Stable readable target label |
|
|
| `operation_run_id` | optional relation shortcut | Operational cross-linking |
|
|
| `context` | existing `metadata` reused or renamed semantically | Structured supporting metadata |
|
|
| `occurred_at` | existing `recorded_at` reused or normalized | Canonical event timestamp |
|
|
|
|
**Core rules**:
|
|
- Every row is append-only in normal product flows.
|
|
- Every row must remain understandable even when the source object is deleted or renamed later.
|
|
- Every row must be scoped at least to a workspace; tenant scope remains nullable for workspace-only events.
|
|
|
|
## Supporting Domain Concepts
|
|
|
|
### AuditEventType
|
|
|
|
| Field | Type | Description |
|
|
|------|------|-------------|
|
|
| `key` | string | Stable registry key such as `baseline_capture.completed` |
|
|
| `family` | string | Domain grouping such as `baseline`, `finding`, `backup`, `restore`, `workspace_membership` |
|
|
| `verb` | string | Normalized operator-facing action verb |
|
|
| `supports_target_link` | bool | Whether target drill-down is meaningful |
|
|
|
|
**Rules**:
|
|
- Must come from a shared canonical registry.
|
|
- Must cover both legacy migrated keys and new first-wave keys.
|
|
|
|
### AuditOutcome
|
|
|
|
| Value | Meaning |
|
|
|-------|---------|
|
|
| `success` | Action completed successfully |
|
|
| `failed` | Action failed |
|
|
| `partial` | Action completed partially |
|
|
| `info` | Informational/non-mutating event |
|
|
| `blocked` | Action was intentionally prevented |
|
|
|
|
**Rules**:
|
|
- Badge rendering is centralized.
|
|
- Existing historical values like `success` and `failure` need compatibility mapping where required.
|
|
|
|
### AuditActorSnapshot
|
|
|
|
| Field | Type | Description |
|
|
|------|------|-------------|
|
|
| `actor_type` | string enum | `human`, `system`, `scheduled`, `integration`, `platform` if compatibility requires |
|
|
| `actor_id` | string or int nullable | Stable identifier when available |
|
|
| `actor_label` | string nullable | Display label captured at event time |
|
|
| `actor_email` | string nullable | Secondary identity where useful |
|
|
|
|
**Rules**:
|
|
- Human and non-human actors must be distinguishable in storage and UI.
|
|
- Historical readability must not depend on the actor record continuing to exist.
|
|
|
|
### AuditTargetSnapshot
|
|
|
|
| Field | Type | Description |
|
|
|------|------|-------------|
|
|
| `target_type` | string nullable | Canonical target kind such as `finding`, `baseline_profile`, `backup_set` |
|
|
| `target_id` | string nullable | Stable identity |
|
|
| `target_label` | string nullable | Display label captured at write time |
|
|
| `workspace_id` | int | Scope guard |
|
|
| `tenant_id` | int nullable | Tenant guard for tenant-owned targets |
|
|
|
|
**Rules**:
|
|
- Target label should be snapped at write time whenever practical.
|
|
- Related links remain optional and permission-aware.
|
|
|
|
### AuditContext
|
|
|
|
| Field | Type | Description |
|
|
|------|------|-------------|
|
|
| `context` | JSON-like object | Structured metadata for interpretation |
|
|
|
|
Expected content patterns:
|
|
|
|
| Pattern | Example |
|
|
|---------|---------|
|
|
| before/after lifecycle change | `before_status`, `after_status` |
|
|
| related run identity | `operation_run_id` |
|
|
| workflow rationale | `reason`, `reason_code` |
|
|
| ownership reassignment | `from_assignee_user_id`, `to_assignee_user_id` |
|
|
| summary counts | `items_succeeded`, `items_failed` |
|
|
|
|
**Rules**:
|
|
- Context must remain intentionally shaped.
|
|
- `AuditContextSanitizer` or equivalent must redact secrets, tokens, and sensitive fields.
|
|
- Raw policy payloads and oversized blobs are not first-class audit context.
|
|
|
|
## Read Models for the Monitoring Page
|
|
|
|
### AuditLogListRow
|
|
|
|
| Field | Type | Description |
|
|
|------|------|-------------|
|
|
| `id` | int | Event identity |
|
|
| `occurred_at` | datetime | Default sort field |
|
|
| `summary` | string | Primary row text |
|
|
| `event_type` | string | Secondary technical key |
|
|
| `outcome` | string | Badge-rendered state |
|
|
| `actor_label` | string | Who or what caused the event |
|
|
| `actor_type` | string | Actor-kind indicator |
|
|
| `target_label` | string nullable | Affected object |
|
|
| `target_type` | string nullable | Secondary target hint |
|
|
| `tenant_label` | string nullable | Only when safe to show |
|
|
| `workspace_id` | int | Scope |
|
|
| `has_related_link` | bool | Whether drill-down is available to this viewer |
|
|
|
|
**Rules**:
|
|
- Summary-first ordering is mandatory.
|
|
- Rows remain understandable without opening the detail view.
|
|
|
|
### AuditLogFilterState
|
|
|
|
| Field | Type | Description |
|
|
|------|------|-------------|
|
|
| `search` | string nullable | High-signal summary search |
|
|
| `tenant_id` | string nullable | Defaulted from active tenant when entitled |
|
|
| `event_type` | string nullable | Taxonomy filter |
|
|
| `outcome` | string nullable | Outcome filter |
|
|
| `actor` | string nullable | Actor-label or actor-kind filter |
|
|
| `target_type` | string nullable | Target kind filter |
|
|
| `date_from` | date nullable | Range lower bound |
|
|
| `date_until` | date nullable | Range upper bound |
|
|
|
|
**Rules**:
|
|
- Filter options must come only from the active workspace and authorized tenant subset.
|
|
- Empty results are valid and intentional.
|
|
|
|
### AuditLogDetailViewModel
|
|
|
|
| Field | Type | Description |
|
|
|------|------|-------------|
|
|
| `summary` | string | Primary heading |
|
|
| `occurred_at` | datetime | Event timestamp |
|
|
| `actor` | AuditActorSnapshot | Who/what caused the event |
|
|
| `target` | AuditTargetSnapshot nullable | Affected object |
|
|
| `outcome` | string | Result state |
|
|
| `context_items` | list | Readable context facts |
|
|
| `technical_metadata` | list | Secondary raw identifiers or event key |
|
|
| `related_link` | object nullable | Canonical target destination when permitted |
|
|
|
|
**Rules**:
|
|
- Readable context facts come before raw JSON.
|
|
- The event must stay intelligible if `related_link` is absent.
|
|
|
|
## Existing Domain Relations Important for Coverage
|
|
|
|
### Finding
|
|
|
|
Relevant persisted fields already include status, severity, assignee and owner users, due dates, and closed or resolved timestamps.
|
|
|
|
**Audit significance**:
|
|
- status changes
|
|
- assignee or owner changes
|
|
- risk acceptance via `STATUS_RISK_ACCEPTED`
|
|
- reopen, resolve, close transitions
|
|
|
|
### BaselineProfile
|
|
|
|
Relevant persisted fields already include workspace ownership, status, capture mode, active snapshot, and creator.
|
|
|
|
**Audit significance**:
|
|
- create or update or archive actions
|
|
- capture and compare lifecycle events through related jobs and operation context
|
|
|
|
### BackupSet
|
|
|
|
Relevant persisted fields already include tenant ownership, metadata, completion time, and restore-run relation.
|
|
|
|
**Audit significance**:
|
|
- create or update or archive events
|
|
- restore initiation linkages and backup-scope summaries
|
|
|
|
### RestoreRun
|
|
|
|
Relevant persisted fields already include status, preview, results, group mapping, completion timestamps, and operation-run relation.
|
|
|
|
**Audit significance**:
|
|
- restore started, completed, failed, partial outcomes
|
|
- assignment outcome summaries and preview/execute distinctions when meaningful
|
|
|
|
### OperationRun
|
|
|
|
Remains the canonical operational record for long-running workflows.
|
|
|
|
**Audit significance**:
|
|
- high-value completion/failure/retry evidence
|
|
- optional `operation_run_id` shortcut from `AuditLog`
|
|
|
|
## State and Transition Notes
|
|
|
|
### AuditLog lifecycle
|
|
|
|
```text
|
|
Created
|
|
-> persisted as historical fact
|
|
-> never user-edited or user-deleted in normal flows
|
|
-> may be superseded or corrected only by later audit events
|
|
```
|
|
|
|
### Workflow-to-audit relationship
|
|
|
|
```text
|
|
User/system action occurs
|
|
-> domain service or job performs authorization and mutation
|
|
-> shared audit recorder writes one meaningful event with actor/target/context
|
|
-> canonical Monitoring page surfaces the event in reverse chronological order
|
|
```
|
|
|
|
## Validation Rules
|
|
|
|
| Rule | Result |
|
|
|------|--------|
|
|
| Every audit row has workspace scope | Required |
|
|
| Tenant-scoped events must belong to the same workspace | Required |
|
|
| Actor kind is explicit for new rows | Required |
|
|
| Summary is human-readable and non-empty for new rows | Required |
|
|
| Context is sanitized and shaped | Required |
|
|
| No user-facing edit/delete path exists | Required |
|
|
| Related links are permission-aware and optional | Required |
|
|
|
|
## Schema Impact
|
|
|
|
Schema changes are expected. The preferred migration strategy is additive evolution of `audit_logs` with compatibility-safe backfills and indexes for:
|
|
|
|
- occurred-at or recorded-at descending review,
|
|
- workspace + occurred-at,
|
|
- tenant + occurred-at,
|
|
- event type,
|
|
- outcome,
|
|
- actor lookup,
|
|
- target lookup,
|
|
- optional operation-run shortcuts.
|