# Issue #169: Job events and audit logging

## Objective

Implement job-events module for immutable audit logging using event sourcing pattern.

## Approach

1. Create module structure (module, service, controller, DTOs)
2. Define event type constants
3. Implement event emission and persistence (PostgreSQL)
4. Add API endpoints for querying events
5. Follow TDD: Write tests first, then implementation

## Event Types

- Job lifecycle: job.created, job.queued, job.started, job.completed, job.failed
- Step lifecycle: step.started, step.progress, step.output, step.completed
- AI events: ai.tool_called, ai.tokens_used, ai.artifact_created
- Gate events: gate.started, gate.passed, gate.failed

## Storage Strategy

- PostgreSQL: Immutable audit log (permanent)
- Valkey Streams: Deferred to future issue
- Valkey Pub/Sub: Deferred to future issue

## API Endpoints

- GET /runner-jobs/:jobId/events - List events for a job
- GET /runner-jobs/:jobId/events/stream - SSE stream (Phase 4, deferred)

## Progress

- [x] Create scratchpad
- [x] Review existing schema (JobEvent model)
- [x] Define event type constants
- [x] Write tests for JobEventsService
- [x] Implement JobEventsService
- [x] Write tests for JobEventsController
- [x] Implement JobEventsController
- [x] Create JobEventsModule
- [x] Register modules in app.module.ts
- [x] Run quality gates (typecheck, lint, build, test)
- [x] Commit changes

## Testing

- Unit tests for service (event emission, persistence, querying)
- Unit tests for controller (endpoint behavior)
- Target: >85% coverage

Results:

- JobEventsService: 13 tests passed
- JobEventsController: 4 tests passed
- Total: 17 tests passed
- All quality gates passed (typecheck, lint, build, test)

## Notes

- Events are immutable once created
- JobEvent model already exists in Prisma schema (from #164)
- RunnerJobsModule available (from #167)
- SSE streaming deferred to Phase 4

## Implementation Details

Files Created:

- /apps/api/src/job-events/event-types.ts - Event type constants
- /apps/api/src/job-events/dto/create-event.dto.ts - DTO for creating events
- /apps/api/src/job-events/dto/query-events.dto.ts - DTO for querying events
- /apps/api/src/job-events/dto/index.ts - DTO exports
- /apps/api/src/job-events/job-events.service.ts - Event service implementation
- /apps/api/src/job-events/job-events.service.spec.ts - Service tests (13 tests)
- /apps/api/src/job-events/job-events.controller.ts - Event controller
- /apps/api/src/job-events/job-events.controller.spec.ts - Controller tests (4 tests)
- /apps/api/src/job-events/job-events.module.ts - Module definition
- /apps/api/src/job-events/index.ts - Module exports

Files Modified:

- /apps/api/src/app.module.ts - Registered JobEventsModule

Event Types Implemented:

- Job lifecycle: job.created, job.queued, job.started, job.completed, job.failed, job.cancelled
- Step lifecycle: step.started, step.progress, step.output, step.completed, step.failed
- AI events: ai.tool_called, ai.tokens_used, ai.artifact_created
- Gate events: gate.started, gate.passed, gate.failed

API Endpoints:

- GET /api/runner-jobs/:jobId/events - List events for a job (with pagination and filtering)

Service Methods:

- emitEvent() - Generic event emission
- getEventsByJobId() - Query events with filters
- Convenience methods: emitJobCreated(), emitJobStarted(), emitStepStarted(), emitAiTokensUsed(), etc.

Quality Gates:

- Typecheck: PASSED
- Lint: PASSED
- Build: PASSED
- Tests: PASSED (17/17 tests)
- Full test suite: PASSED (1327 tests)
