# Quick File Reference for Admin Module Audit Logging

## MUST READ FIRST (15 min total)

### 1. Main Controllers (Define what actions need audit)
- ✅ `apps/api/src/modules/admin/presentation/controllers/admin.controller.ts` (155 lines)
  - User management: ban, update status, adjust subscription
  - All endpoints have @CurrentUser() decorator to capture admin ID
  
- ✅ `apps/api/src/modules/admin/presentation/controllers/admin-moderation.controller.ts` (157 lines)
  - Listing approval/rejection
  - KYC approval/rejection
  - Bulk moderation

### 2. Command Handlers (Where to hook audit logging)
Each command publishes a domain event. Audit logging listener should listen to these events.

**Ban User Flow:**
- Input: `apps/api/src/modules/admin/presentation/dto/ban-user.dto.ts`
- Command: `apps/api/src/modules/admin/application/commands/ban-user/ban-user.command.ts`
- Handler: `apps/api/src/modules/admin/application/commands/ban-user/ban-user.handler.ts` (70 lines)
  - Line 62: `this.eventBus.publish(new UserBannedEvent(...))`

**Approve Listing Flow:**
- Input: `apps/api/src/modules/admin/presentation/dto/approve-listing.dto.ts`
- Command: `apps/api/src/modules/admin/application/commands/approve-listing/approve-listing.command.ts`
- Handler: `apps/api/src/modules/admin/application/commands/approve-listing/approve-listing.handler.ts` (52 lines)
  - Line 42-44: `this.eventBus.publish(new ListingApprovedEvent(...))`

### 3. Domain Events (What information is published)
```
apps/api/src/modules/admin/domain/events/
  ├── user-banned.event.ts
  ├── user-unbanned.event.ts
  ├── listing-approved.event.ts
  ├── listing-rejected.event.ts
  ├── subscription-adjusted.event.ts
  ├── kyc-approved.event.ts
  └── kyc-rejected.event.ts
```

Each event has:
- `eventName` (e.g., 'user.banned')
- `occurredAt` (timestamp)
- `aggregateId` (userId or listingId)
- `adminId` (the admin who performed the action)
- Additional context (reason, notes, etc.)

### 4. Existing Event Listener Pattern (Template)
- ✅ `apps/api/src/modules/admin/application/listeners/user-banned.listener.ts` (52 lines)
  - Shows @OnEvent() decorator
  - Shows how to access event data
  - Shows side effects (deactivate listings, send notification)
  - **THIS IS YOUR TEMPLATE FOR AUDIT LOGGING LISTENER**

### 5. Logger Service (Where to log)
- ✅ `apps/api/src/modules/shared/infrastructure/logger.service.ts` (65 lines)
  - Pino-based structured logging
  - Auto PII redaction
  - Methods: log(), error(), warn(), debug(), verbose()

### 6. Exception Filter (For error logging)
- ✅ `apps/api/src/modules/shared/infrastructure/filters/global-exception.filter.ts` (145 lines)
  - Catches all exceptions
  - Logs with correlationId
  - Could capture failed admin actions

---

## ARCHITECTURE REFERENCES

### Repository Pattern
- Domain Interface: `apps/api/src/modules/admin/domain/repositories/admin-query.repository.ts`
- Prisma Implementation: `apps/api/src/modules/admin/infrastructure/repositories/prisma-admin-query.repository.ts`
- **FOLLOW THIS PATTERN** for AuditLog repository

### Module Bootstrap
- `apps/api/src/modules/admin/admin.module.ts` (64 lines)
  - Shows how to register repositories via DI
  - Shows how to register listeners
  - Shows how to import CQRS module

### Global App Setup
- `apps/api/src/app.module.ts` (100+ lines)
  - Shows APP_FILTER, APP_GUARD, APP_INTERCEPTOR registration
  - Shows CqrsModule.forRoot() setup
  - Shows middleware configuration

---

## PRISMA SCHEMA

### Current Models (What we're auditing)
- `prisma/schema.prisma` (602 lines total)

**User Model** (lines 34-71):
- Fields to audit: isActive, kycStatus, role

**Listing Model** (lines 227-276):
- Fields to audit: status, moderationScore, moderationNotes

**NO AUDIT MODEL YET** - Opportunity to create from scratch

---

## EXACT ENDPOINTS TO AUDIT (From Controllers)

### AdminController Actions:
1. `PATCH /admin/users/status` - Update user active status
2. `POST /admin/users/ban` - Ban/unban user
3. `POST /admin/subscriptions/adjust` - Adjust subscription

### AdminModerationController Actions:
1. `POST /admin/moderation/approve` - Approve listing
2. `POST /admin/moderation/reject` - Reject listing
3. `POST /admin/moderation/bulk` - Bulk moderate listings
4. `POST /admin/kyc/approve` - Approve KYC
5. `POST /admin/kyc/reject` - Reject KYC

Each action:
- Already captures admin ID from JWT
- Already publishes a domain event
- Already has a command handler
- Needs: Audit logging listener to capture to database

---

## DEPENDENCIES ALREADY IMPORTED

### In AdminModule:
```typescript
// Already available:
- CqrsModule (from @nestjs/cqrs)
- AuthModule (auth guards/decorators)
- ListingsModule (for listing operations)
- SubscriptionsModule (for subscription operations)

// In providers:
- CommandHandlers (8 total)
- QueryHandlers (6 total)
- Event Listeners (2 existing + need to add AuditLoggingListener)
```

### From SharedModule:
- `PrismaService` (database)
- `LoggerService` (logging)
- Exception types (NotFoundException, ValidationException, etc.)

---

## IMPLEMENTATION CHECKLIST

### Phase 1: Database & Repository
- [ ] Create AuditLog Prisma model in schema.prisma
- [ ] Create IAuditLogRepository interface
- [ ] Create PrismaAuditLogRepository implementation
- [ ] Add to AdminModule providers

### Phase 2: Events & Listeners
- [ ] Create AuditEvent domain event (if needed as wrapper)
- [ ] Create AuditLoggingListener to @OnEvent() for all admin events
- [ ] Inject AuditLogRepository into listener
- [ ] Persist audit records on event

### Phase 3: Query & API
- [ ] Create GetAuditLogsQuery
- [ ] Create GetAuditLogsHandler
- [ ] Create IAuditLogQueryRepository method
- [ ] Add to QueryHandlers in module

### Phase 4: Controller Endpoint
- [ ] Add GET /admin/audit-logs endpoint
- [ ] Add filtering DTOs (dateRange, adminId, actionType, resourceId)
- [ ] Add pagination support

### Phase 5: Testing
- [ ] Unit tests for AuditLoggingListener
- [ ] Integration tests for audit persistence
- [ ] E2E tests for audit log retrieval

---

## CRITICAL PATTERNS TO FOLLOW

### 1. Command Pattern (Already Used)
```typescript
// DTOs validate input
// Commands encapsulate business intent
// Handlers execute + publish events
// Events trigger side effects via listeners
```

### 2. DDD Layer Structure
```
Presentation (DTO validation)
    ↓
Application (Command/Query execution + Event publishing)
    ↓
Domain (Event definitions, Repository interfaces)
    ↓
Infrastructure (Database implementation)
```

### 3. Dependency Injection
```typescript
// Always use Symbol for tokens:
export const AUDIT_LOG_REPOSITORY = Symbol('AUDIT_LOG_REPOSITORY');

// Register in module:
{ provide: AUDIT_LOG_REPOSITORY, useClass: PrismaAuditLogRepository }

// Inject in service:
constructor(
  @Inject(AUDIT_LOG_REPOSITORY) private readonly auditRepo: IAuditLogRepository,
) {}
```

### 4. Event Listener Pattern
```typescript
@Injectable()
export class AuditLoggingListener {
  constructor(
    @Inject(AUDIT_LOG_REPOSITORY) private readonly auditRepo: IAuditLogRepository,
    private readonly logger: LoggerService,
  ) {}

  @OnEvent('user.banned', { async: true })
  async handleUserBanned(event: UserBannedEvent): Promise<void> {
    // Extract data from event
    // Persist to database
    // Log if successful/failed
  }
}
```

---

## WHERE TO ADD CODE

```
apps/api/src/modules/admin/
├── domain/
│   ├── events/
│   │   └── audit-logged.event.ts (NEW - optional wrapper)
│   └── repositories/
│       ├── audit-log.repository.ts (NEW - interface)
│       └── index.ts (update exports)
│
├── application/
│   ├── queries/
│   │   ├── get-audit-logs/ (NEW)
│   │   │   ├── get-audit-logs.query.ts
│   │   │   └── get-audit-logs.handler.ts
│   │   └── index.ts (update exports)
│   │
│   └── listeners/
│       ├── audit-logging.listener.ts (NEW)
│       └── index.ts (update if needed)
│
├── infrastructure/
│   └── repositories/
│       ├── prisma-audit-log.repository.ts (NEW)
│       └── index.ts (update exports)
│
└── presentation/
    ├── controllers/
    │   ├── admin.controller.ts (ADD ENDPOINT)
    │   └── admin-moderation.controller.ts (UPDATE if needed)
    │
    └── dto/
        ├── get-audit-logs-query.dto.ts (NEW)
        └── index.ts (update exports)

prisma/
└── schema.prisma (ADD AuditLog MODEL)
```

---

## EVENTS TO LISTEN TO

1. 'user.banned' - from UserBannedEvent
2. 'user.unbanned' - from UserUnbannedEvent  
3. 'listing.approved' - from ListingApprovedEvent
4. 'listing.rejected' - from ListingRejectedEvent
5. 'kyc.approved' - from KycApprovedEvent
6. 'kyc.rejected' - from KycRejectedEvent
7. 'subscription.adjusted' - from SubscriptionAdjustedEvent
8. 'user.deactivated' - (if exists in auth module)

Each gets logged with:
- Admin ID (from event)
- Resource ID (aggregateId from event)
- Resource Type (derived from eventName)
- Timestamp (from event.occurredAt)
- Additional context (reason, notes, etc.)

