# @loma-portal/em-audit

Two halves of the audit pipeline:

| Side     | Where                                                                     | Class                            |
| -------- | ------------------------------------------------------------------------- | -------------------------------- |
| Producer | every API host (api-nest, .NET via shim, dotnet-side AuditDispatcher TBD) | `AuditDispatcher.emit(event)`    |
| Sink     | `apps/worker-nest`                                                        | `PrismaAuditSink.persist(event)` |

The producer enqueues via BullMQ (key: `audit-events`). The worker consumes and writes to Postgres `audit_logs` via Prisma. Decoupling keeps the request path fast and lets audit absorb spikes.

## Producer wiring (NestJS)

```ts
import { EmAuditModule } from '@loma-portal/em-audit';

@Module({
  imports: [EmAuditModule.forRoot({ redisUrl: process.env.REDIS_URL! })],
})
export class AppModule {}

// in any service:
constructor(private readonly audit: AuditDispatcher) {}
await this.audit.emit({
  action: 'user.create', entityType: 'User', entityId: user.id, userId: actor.userId,
});
```

## Sink wiring (worker-nest)

```ts
import { PrismaAuditSink, AUDIT_QUEUE_NAME, type AuditEvent } from '@loma-portal/em-audit';
import { Worker } from 'bullmq';

const sink = new PrismaAuditSink(prisma);
new Worker<AuditEvent>(AUDIT_QUEUE_NAME, (job) => sink.persist(job.data), { connection });
```

## Why BullMQ + Redis

- The .NET API can publish via Redis pub/sub or a tiny C# BullMQ adapter (Phase 8 evaluation). For now, the Nest hosts produce.
- Backpressure-friendly under load spikes.
- Failures get retried (`attempts: 5`, exponential backoff) without blocking the request.
