initial commit

This commit is contained in:
2026-06-09 14:07:37 +03:30
parent 30ac533800
commit 996a4fcda7
121 changed files with 20557 additions and 3 deletions

12
src/audit/audit.module.ts Normal file
View 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 {}

View 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 ?? {},
});
}
}

View 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 });