Files
stack/docs/scratchpads/169-job-events-audit.md
Jason Woltje efe624e2c1 feat(#168): Implement job steps tracking
Implement JobStepsModule for granular step tracking within runner jobs.

Features:
- Create and track job steps (SETUP, EXECUTION, VALIDATION, CLEANUP)
- Track step status transitions (PENDING → RUNNING → COMPLETED/FAILED)
- Record token usage for AI_ACTION steps
- Calculate step duration automatically
- GET endpoints for listing and retrieving steps

Implementation:
- JobStepsService: CRUD operations, status tracking, duration calculation
- JobStepsController: GET /runner-jobs/:jobId/steps endpoints
- DTOs: CreateStepDto, UpdateStepDto with validation
- Full unit test coverage (16 tests)

Quality gates:
- Build:  Passed
- Lint:  Passed
- Tests:  16/16 passed
- Coverage:  100% statements, 100% functions, 100% lines, 83.33% branches

Also fixed pre-existing TypeScript strict mode issue in job-events DTO.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-01 21:16:23 -06:00

3.5 KiB

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

  • Create scratchpad
  • Review existing schema (JobEvent model)
  • Define event type constants
  • Write tests for JobEventsService
  • Implement JobEventsService
  • Write tests for JobEventsController
  • Implement JobEventsController
  • Create JobEventsModule
  • Register modules in app.module.ts
  • Run quality gates (typecheck, lint, build, test)
  • 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)