Files
cim_summary/.planning/milestones/v1.0-phases/01-data-foundation/01-02-PLAN.md
admin 38a0f0619d chore: complete v1.0 Analytics & Monitoring milestone
Archive milestone artifacts (roadmap, requirements, audit, phase directories)
to .planning/milestones/. Evolve PROJECT.md with validated requirements and
decision outcomes. Create MILESTONES.md and RETROSPECTIVE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 10:34:18 -05:00

9.7 KiB

phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
phase plan type wave depends_on files_modified autonomous requirements must_haves
01-data-foundation 02 execute 2
01-01
backend/src/__tests__/models/HealthCheckModel.test.ts
backend/src/__tests__/models/AlertEventModel.test.ts
true
INFR-01
INFR-04
truths artifacts key_links
HealthCheckModel CRUD methods work correctly with mocked Supabase client
AlertEventModel CRUD methods work correctly with mocked Supabase client
Input validation rejects invalid status values and empty service names
Models use getSupabaseServiceClient (not getSupabaseClient or getPostgresPool)
path provides contains
backend/src/__tests__/models/HealthCheckModel.test.ts Unit tests for HealthCheckModel HealthCheckModel
path provides contains
backend/src/__tests__/models/AlertEventModel.test.ts Unit tests for AlertEventModel AlertEventModel
from to via pattern
backend/src/__tests__/models/HealthCheckModel.test.ts backend/src/models/HealthCheckModel.ts import HealthCheckModel import.*HealthCheckModel
from to via pattern
backend/src/__tests__/models/AlertEventModel.test.ts backend/src/models/AlertEventModel.ts import AlertEventModel import.*AlertEventModel
Create unit tests for both monitoring model classes to verify CRUD operations, input validation, and correct Supabase client usage.

Purpose: Ensure model layer works correctly before Phase 2 services depend on it. Verify INFR-04 compliance (models use existing Supabase connection) and that input validation catches bad data before it hits the database.

Output: Two test files covering all model static methods with mocked Supabase client.

<execution_context> @/home/jonathan/.claude/get-shit-done/workflows/execute-plan.md @/home/jonathan/.claude/get-shit-done/templates/summary.md </execution_context>

@.planning/PROJECT.md @.planning/ROADMAP.md @.planning/STATE.md @.planning/phases/01-data-foundation/01-RESEARCH.md @.planning/phases/01-data-foundation/01-01-SUMMARY.md

Test patterns

@backend/src/tests/mocks/logger.mock.ts @backend/src/tests/utils/test-helpers.ts @.planning/codebase/TESTING.md

Models to test

@backend/src/models/HealthCheckModel.ts @backend/src/models/AlertEventModel.ts

Task 1: Create HealthCheckModel unit tests backend/src/__tests__/models/HealthCheckModel.test.ts Create unit tests for HealthCheckModel using Vitest. This is the first model test in the project, so establish the Supabase mocking pattern.

Supabase mock setup:

  • Mock ../config/supabase module using vi.mock()
  • Create a mock Supabase client with chainable methods: .from() returns object with .insert(), .select(), .single(), .order(), .limit(), .eq(), .lt(), .delete()
  • Each chainable method returns the mock object (fluent pattern) except terminal methods (.single(), .select() at end) which return { data, error }
  • Mock getSupabaseServiceClient to return the mock client
  • Also mock '../utils/logger' using the existing logger.mock.ts pattern

Test suites:

describe('HealthCheckModel'):

describe('create'):

  • test('creates a health check with valid data') — call with { service_name: 'document_ai', status: 'healthy', latency_ms: 150 }, verify Supabase insert called with correct data, verify returned record matches
  • test('creates a health check with minimal data') — call with only required fields (service_name, status), verify optional fields not included
  • test('creates a health check with probe_details') — include JSONB probe_details, verify passed through
  • test('throws on empty service_name') — expect Error thrown before Supabase is called
  • test('throws on invalid status') — pass status 'unknown', expect Error thrown before Supabase is called
  • test('throws on Supabase error') — mock Supabase returning { data: null, error: { message: 'connection failed' } }, verify error thrown with descriptive message
  • test('logs error on Supabase failure') — verify logger.error called with error details

describe('findLatestByService'):

  • test('returns latest health check for service') — mock Supabase returning a record, verify correct table and filters used
  • test('returns null when no records found') — mock Supabase returning null/empty, verify null returned (not thrown)

describe('findAll'):

  • test('returns health checks with default limit') — verify limit 100 applied
  • test('filters by serviceName when provided') — verify .eq() called with service_name
  • test('respects custom limit') — pass limit: 50, verify .limit(50)

describe('deleteOlderThan'):

  • test('deletes records older than specified days') — verify .lt() called with correct date calculation
  • test('returns count of deleted records') — mock returning count

Pattern notes:

  • Use describe/test (not it) to match project convention
  • Use beforeEach to reset mocks between tests: vi.clearAllMocks()
  • Verify getSupabaseServiceClient is called per method invocation (INFR-04 pattern)
  • Import from vitest: { describe, test, expect, vi, beforeEach } cd /home/jonathan/Coding/cim_summary/backend && npx vitest run src/tests/models/HealthCheckModel.test.ts --reporter=verbose 2>&1 | tail -30 All HealthCheckModel tests pass. Tests cover create (valid, minimal, with probe_details), input validation (empty name, invalid status), Supabase error handling, findLatestByService (found, not found), findAll (default, filtered, custom limit), deleteOlderThan.
Task 2: Create AlertEventModel unit tests backend/src/__tests__/models/AlertEventModel.test.ts Create unit tests for AlertEventModel following the same Supabase mocking pattern established in HealthCheckModel tests.

Reuse the same mock setup pattern from Task 1 (mock getSupabaseServiceClient and logger).

Test suites:

describe('AlertEventModel'):

describe('create'):

  • test('creates an alert event with valid data') — call with { service_name: 'claude_ai', alert_type: 'service_down', message: 'API returned 503' }, verify insert called, verify returned record
  • test('defaults status to active') — create without explicit status, verify 'active' sent to Supabase
  • test('creates with explicit status') — pass status: 'acknowledged', verify it is used
  • test('creates with details JSONB') — include details object, verify passed through
  • test('throws on empty service_name') — expect Error before Supabase call
  • test('throws on invalid alert_type') — pass alert_type: 'warning', expect Error
  • test('throws on invalid status') — pass status: 'pending', expect Error
  • test('throws on Supabase error') — mock error response, verify descriptive throw

describe('findActive'):

  • test('returns active alerts') — mock returning array of active alerts, verify .eq('status', 'active')
  • test('filters by serviceName when provided') — verify additional .eq() for service_name
  • test('returns empty array when no active alerts') — mock returning empty array

describe('acknowledge'):

  • test('sets status to acknowledged with timestamp') — verify .update() called with { status: 'acknowledged', acknowledged_at: expect.any(String) }
  • test('throws when alert not found') — mock Supabase returning null/error, verify error thrown

describe('resolve'):

  • test('sets status to resolved with timestamp') — verify .update() with { status: 'resolved', resolved_at: expect.any(String) }
  • test('throws when alert not found') — verify error handling

describe('findRecentByService'):

  • test('finds recent alert within time window') — mock returning a match, verify filters for service_name, alert_type, and created_at > threshold
  • test('returns null when no recent alerts') — mock returning empty, verify null

describe('deleteOlderThan'):

  • test('deletes records older than specified days') — same pattern as HealthCheckModel
  • test('returns count of deleted records') — verify count

Pattern notes:

  • Same mock setup as HealthCheckModel test
  • Same beforeEach/clearAllMocks pattern
  • Verify getSupabaseServiceClient called per method cd /home/jonathan/Coding/cim_summary/backend && npx vitest run src/tests/models/AlertEventModel.test.ts --reporter=verbose 2>&1 | tail -30 All AlertEventModel tests pass. Tests cover create (valid, default status, explicit status, with details), input validation (empty name, invalid alert_type, invalid status), Supabase error handling, findActive (all, filtered, empty), acknowledge, resolve, findRecentByService (found, not found), deleteOlderThan.
1. `cd backend && npx vitest run src/__tests__/models/ --reporter=verbose` — all model tests pass 2. `cd backend && npx vitest run --reporter=verbose` — full test suite still passes (no regressions) 3. Tests mock `getSupabaseServiceClient` (not `getSupabaseClient` or `getPostgresPool`) confirming INFR-04 compliance

<success_criteria>

  • All HealthCheckModel tests pass covering create, findLatestByService, findAll, deleteOlderThan, plus validation errors
  • All AlertEventModel tests pass covering create, findActive, acknowledge, resolve, findRecentByService, deleteOlderThan, plus validation errors
  • Existing test suite continues to pass (no regressions)
  • Supabase mocking pattern established for future model tests </success_criteria>
After completion, create `.planning/phases/01-data-foundation/01-02-SUMMARY.md`