Some checks failed
CI/CD Pipeline - Xpeditis PreProd / Frontend - Docker Build & Push (push) Blocked by required conditions
CI/CD Pipeline - Xpeditis PreProd / Deploy to PreProd Server (push) Blocked by required conditions
CI/CD Pipeline - Xpeditis PreProd / Run Smoke Tests (push) Blocked by required conditions
CI/CD Pipeline - Xpeditis PreProd / Backend - Build & Test (push) Failing after 5m53s
CI/CD Pipeline - Xpeditis PreProd / Backend - Docker Build & Push (push) Has been skipped
CI/CD Pipeline - Xpeditis PreProd / Frontend - Build & Test (push) Has been cancelled
- Replace all ../../domain/ imports with @domain/ across 67 files - Configure NestJS to use tsconfig.build.json with rootDir - Add tsc-alias to resolve path aliases after build - This fixes 'Cannot find module' TypeScript compilation errors Fixed files: - 30 files in application layer - 37 files in infrastructure layer
154 lines
3.6 KiB
TypeScript
154 lines
3.6 KiB
TypeScript
/**
|
|
* Audit Service
|
|
*
|
|
* Provides centralized audit logging functionality
|
|
* Tracks all important actions for security and compliance
|
|
*/
|
|
|
|
import { Injectable, Logger, Inject } from '@nestjs/common';
|
|
import { v4 as uuidv4 } from 'uuid';
|
|
import { AuditLog, AuditAction, AuditStatus } from '@domain/entities/audit-log.entity';
|
|
import {
|
|
AuditLogRepository,
|
|
AUDIT_LOG_REPOSITORY,
|
|
AuditLogFilters,
|
|
} from '@domain/ports/out/audit-log.repository';
|
|
|
|
export interface LogAuditInput {
|
|
action: AuditAction;
|
|
status: AuditStatus;
|
|
userId: string;
|
|
userEmail: string;
|
|
organizationId: string;
|
|
resourceType?: string;
|
|
resourceId?: string;
|
|
resourceName?: string;
|
|
metadata?: Record<string, any>;
|
|
ipAddress?: string;
|
|
userAgent?: string;
|
|
errorMessage?: string;
|
|
}
|
|
|
|
@Injectable()
|
|
export class AuditService {
|
|
private readonly logger = new Logger(AuditService.name);
|
|
|
|
constructor(
|
|
@Inject(AUDIT_LOG_REPOSITORY)
|
|
private readonly auditLogRepository: AuditLogRepository
|
|
) {}
|
|
|
|
/**
|
|
* Log an audit event
|
|
*/
|
|
async log(input: LogAuditInput): Promise<void> {
|
|
try {
|
|
const auditLog = AuditLog.create({
|
|
id: uuidv4(),
|
|
...input,
|
|
});
|
|
|
|
await this.auditLogRepository.save(auditLog);
|
|
|
|
this.logger.log(`Audit log created: ${input.action} by ${input.userEmail} (${input.status})`);
|
|
} catch (error: any) {
|
|
// Never throw on audit logging failure - log the error and continue
|
|
this.logger.error(
|
|
`Failed to create audit log: ${error?.message || 'Unknown error'}`,
|
|
error?.stack
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Log successful action
|
|
*/
|
|
async logSuccess(
|
|
action: AuditAction,
|
|
userId: string,
|
|
userEmail: string,
|
|
organizationId: string,
|
|
options?: {
|
|
resourceType?: string;
|
|
resourceId?: string;
|
|
resourceName?: string;
|
|
metadata?: Record<string, any>;
|
|
ipAddress?: string;
|
|
userAgent?: string;
|
|
}
|
|
): Promise<void> {
|
|
await this.log({
|
|
action,
|
|
status: AuditStatus.SUCCESS,
|
|
userId,
|
|
userEmail,
|
|
organizationId,
|
|
...options,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Log failed action
|
|
*/
|
|
async logFailure(
|
|
action: AuditAction,
|
|
userId: string,
|
|
userEmail: string,
|
|
organizationId: string,
|
|
errorMessage: string,
|
|
options?: {
|
|
resourceType?: string;
|
|
resourceId?: string;
|
|
metadata?: Record<string, any>;
|
|
ipAddress?: string;
|
|
userAgent?: string;
|
|
}
|
|
): Promise<void> {
|
|
await this.log({
|
|
action,
|
|
status: AuditStatus.FAILURE,
|
|
userId,
|
|
userEmail,
|
|
organizationId,
|
|
errorMessage,
|
|
...options,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get audit logs with filters
|
|
*/
|
|
async getAuditLogs(filters: AuditLogFilters): Promise<{
|
|
logs: AuditLog[];
|
|
total: number;
|
|
}> {
|
|
const [logs, total] = await Promise.all([
|
|
this.auditLogRepository.findByFilters(filters),
|
|
this.auditLogRepository.count(filters),
|
|
]);
|
|
|
|
return { logs, total };
|
|
}
|
|
|
|
/**
|
|
* Get audit trail for a specific resource
|
|
*/
|
|
async getResourceAuditTrail(resourceType: string, resourceId: string): Promise<AuditLog[]> {
|
|
return this.auditLogRepository.findByResource(resourceType, resourceId);
|
|
}
|
|
|
|
/**
|
|
* Get recent activity for an organization
|
|
*/
|
|
async getOrganizationActivity(organizationId: string, limit: number = 50): Promise<AuditLog[]> {
|
|
return this.auditLogRepository.findRecentByOrganization(organizationId, limit);
|
|
}
|
|
|
|
/**
|
|
* Get user activity history
|
|
*/
|
|
async getUserActivity(userId: string, limit: number = 50): Promise<AuditLog[]> {
|
|
return this.auditLogRepository.findByUser(userId, limit);
|
|
}
|
|
}
|