feat: Phase 1 – Plattform-Grundgerüst (Docker, NestJS, React, Auth)
This commit is contained in:
52
apps/platform-backend/src/audit/audit.service.ts
Normal file
52
apps/platform-backend/src/audit/audit.service.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { DatabaseService } from '../database/database.service';
|
||||
|
||||
/** Definierte Audit-Aktionen der Plattform. */
|
||||
export const AUDIT_ACTIONS = {
|
||||
LOGIN_SUCCESS: 'LOGIN_SUCCESS',
|
||||
LOGIN_FAILED: 'LOGIN_FAILED',
|
||||
LOGIN_LOCKED: 'LOGIN_FAILED_LOCKED',
|
||||
LOGOUT: 'LOGOUT',
|
||||
} as const;
|
||||
|
||||
export type AuditAction = (typeof AUDIT_ACTIONS)[keyof typeof AUDIT_ACTIONS];
|
||||
|
||||
/**
|
||||
* Zentrales Audit-Logging: Sicherheitsrelevante Ereignisse werden
|
||||
* nachvollziehbar aufgezeichnet. Es werden niemals Passwörter,
|
||||
* Tokens oder personenbezogene Daten geloggt.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AuditService {
|
||||
private readonly logger = new Logger('Audit');
|
||||
|
||||
constructor(private readonly database: DatabaseService) {}
|
||||
|
||||
async record(input: {
|
||||
userId: string | null;
|
||||
username: string;
|
||||
action: AuditAction;
|
||||
details?: Record<string, unknown>;
|
||||
ipAddress?: string | null;
|
||||
}): Promise<void> {
|
||||
try {
|
||||
await this.database.query(
|
||||
`INSERT INTO audit_logs (user_id, username, action, details, ip_address)
|
||||
VALUES ($1, $2, $3, $4::jsonb, $5)`,
|
||||
[
|
||||
input.userId,
|
||||
input.username,
|
||||
input.action,
|
||||
JSON.stringify(input.details ?? {}),
|
||||
input.ipAddress ?? null,
|
||||
],
|
||||
);
|
||||
} catch (error) {
|
||||
// Audit-Fehler dürfen den eigentlichen Request niemals blockieren.
|
||||
this.logger.error(
|
||||
`Audit-Log fehlgeschlagen (${input.action})`,
|
||||
error instanceof Error ? error.stack : String(error),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user