forked from Shared/esg
initial commit
This commit is contained in:
12
src/audit/audit.module.ts
Normal file
12
src/audit/audit.module.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { MongooseModule } from '@nestjs/mongoose';
|
||||
import { AuditService } from './audit.service';
|
||||
import { AuditLog, AuditLogSchema } from './schemas/audit-log.schema';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [MongooseModule.forFeature([{ name: AuditLog.name, schema: AuditLogSchema }])],
|
||||
providers: [AuditService],
|
||||
exports: [AuditService],
|
||||
})
|
||||
export class AuditModule {}
|
||||
37
src/audit/audit.service.ts
Normal file
37
src/audit/audit.service.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectModel } from '@nestjs/mongoose';
|
||||
import { Model, Types } from 'mongoose';
|
||||
import { AuditEvent } from '../common/enums/audit-event.enum';
|
||||
import { AuditLog, AuditLogDocument } from './schemas/audit-log.schema';
|
||||
|
||||
export interface AuditContext {
|
||||
userId?: string;
|
||||
actorId?: string;
|
||||
username?: string;
|
||||
ip?: string;
|
||||
userAgent?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Central audit writer — all security-sensitive actions flow through here.
|
||||
*/
|
||||
@Injectable()
|
||||
export class AuditService {
|
||||
constructor(
|
||||
@InjectModel(AuditLog.name)
|
||||
private readonly auditModel: Model<AuditLogDocument>,
|
||||
) {}
|
||||
|
||||
async log(event: AuditEvent, context: AuditContext = {}): Promise<void> {
|
||||
await this.auditModel.create({
|
||||
event,
|
||||
userId: context.userId ? new Types.ObjectId(context.userId) : undefined,
|
||||
actorId: context.actorId ? new Types.ObjectId(context.actorId) : undefined,
|
||||
username: context.username,
|
||||
ip: context.ip,
|
||||
userAgent: context.userAgent,
|
||||
metadata: context.metadata ?? {},
|
||||
});
|
||||
}
|
||||
}
|
||||
37
src/audit/schemas/audit-log.schema.ts
Normal file
37
src/audit/schemas/audit-log.schema.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
|
||||
import { HydratedDocument, Types } from 'mongoose';
|
||||
import { AuditEvent } from '../../common/enums/audit-event.enum';
|
||||
|
||||
export type AuditLogDocument = HydratedDocument<AuditLog>;
|
||||
|
||||
/**
|
||||
* Immutable security audit trail — separate from inquiry_logs (business audit).
|
||||
*/
|
||||
@Schema({ timestamps: { createdAt: true, updatedAt: false }, collection: 'audit_logs' })
|
||||
export class AuditLog {
|
||||
@Prop({ required: true, enum: AuditEvent, index: true })
|
||||
event!: AuditEvent;
|
||||
|
||||
@Prop({ type: Types.ObjectId, ref: 'User', index: true })
|
||||
userId?: Types.ObjectId;
|
||||
|
||||
@Prop({ type: Types.ObjectId, ref: 'User' })
|
||||
actorId?: Types.ObjectId;
|
||||
|
||||
@Prop()
|
||||
username?: string;
|
||||
|
||||
@Prop()
|
||||
ip?: string;
|
||||
|
||||
@Prop()
|
||||
userAgent?: string;
|
||||
|
||||
@Prop({ type: Object, default: {} })
|
||||
metadata!: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export const AuditLogSchema = SchemaFactory.createForClass(AuditLog);
|
||||
|
||||
AuditLogSchema.index({ createdAt: -1 });
|
||||
AuditLogSchema.index({ event: 1, createdAt: -1 });
|
||||
Reference in New Issue
Block a user