Real World Example

Audit Logging for Admin Actions

Banks, fintechs and marketplaces must record who changed what (RBI and SOC 2 audits ask for it). An @Audit('product.delete') decorator plus an interceptor writes an audit row for every admin action, without touching the handlers.

src/audit/audit.decorator.ts and src/audit/audit.interceptor.ts

import { applyDecorators, CallHandler, ExecutionContext, Injectable, NestInterceptor, UseInterceptors } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable, tap } from 'rxjs';
import { AuditService } from './audit.service';

export const AuditAction = Reflector.createDecorator<string>();

export const Audit = (action: string) => applyDecorators(AuditAction(action), UseInterceptors(AuditInterceptor));

@Injectable()
export class AuditInterceptor implements NestInterceptor {
  constructor(private readonly reflector: Reflector, private readonly audit: AuditService) {}

  intercept(ctx: ExecutionContext, next: CallHandler): Observable<unknown> {
    const action = this.reflector.get(AuditAction, ctx.getHandler());
    const req = ctx.switchToHttp().getRequest();
    return next.handle().pipe(
      tap(() =>
        this.audit.record({
          action,
          actorId: req.user.id,
          target: req.params.id ?? null,
          ip: req.ip,
          payload: req.body,
        }),
      ),
    );
  }
}

// products.controller.ts
// @Auth(Role.Admin)
// @Audit('product.delete')
// @Delete(':id') remove(@Param('id', ParseIntPipe) id: number) { ... }

Example

curl -H "Authorization: Bearer <admin-token>" "http://localhost:3000/admin/audit?limit=1"

Example output

[{"id":90211,"action":"product.delete","actorId":1,"target":"7","ip":"10.0.4.17","createdAt":"2026-01-15T10:00:00.000Z"}]