feat(beheer): admin audit view at /beheer/audit (finishes WP-42)
The WP-41 GET /admin/audit trail now has an FE view: a beheer audit page (domain AuditEntry + adapter/parse + store) rendering the data-minimised trail as a read-only table, capability-gated on cases:manage. Added to ADMIN_LINKS (header nav + dashboard Beheer section) and to the role.interceptor ROLE_AWARE list so the admin-gated call carries X-Role. Closes WP-42's audit half. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
import { Injectable, inject } from '@angular/core';
|
||||
import { Result, ok, err } from '@shared/kernel/fp';
|
||||
import { ApiClient } from '@shared/infrastructure/api-client';
|
||||
import type { AuthzAuditDto } from '@shared/infrastructure/api-client';
|
||||
import { AuditEntry } from '@beheer/domain/audit-entry';
|
||||
|
||||
/**
|
||||
* Infrastructure adapter for the admin authz/PII-reveal audit trail (`GET /admin/audit`,
|
||||
* WP-41). The single place the ApiClient lives for audit; the store parses at the boundary.
|
||||
*/
|
||||
@Injectable({ providedIn: 'root' })
|
||||
export class AuditAdapter {
|
||||
private client = inject(ApiClient);
|
||||
|
||||
list(): Promise<AuthzAuditDto[]> {
|
||||
return this.client.audit();
|
||||
}
|
||||
}
|
||||
|
||||
/** Trust-boundary parse of the audit rows. */
|
||||
export function parseAuditEntries(json: unknown): Result<string, AuditEntry[]> {
|
||||
if (!Array.isArray(json)) return err('audit: not an array');
|
||||
const out: AuditEntry[] = [];
|
||||
for (const item of json) {
|
||||
if (typeof item !== 'object' || item === null) return err('audit: row not an object');
|
||||
const d = item as AuthzAuditDto;
|
||||
if (
|
||||
typeof d.at !== 'string' ||
|
||||
typeof d.action !== 'string' ||
|
||||
typeof d.resource !== 'string' ||
|
||||
typeof d.role !== 'string' ||
|
||||
typeof d.correlationId !== 'string'
|
||||
)
|
||||
return err('audit: missing fields');
|
||||
out.push({
|
||||
at: d.at,
|
||||
action: d.action,
|
||||
resource: d.resource,
|
||||
decision: d.decision === 'allow' ? 'allow' : 'deny',
|
||||
role: d.role,
|
||||
correlationId: d.correlationId,
|
||||
});
|
||||
}
|
||||
return ok(out);
|
||||
}
|
||||
Reference in New Issue
Block a user