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>
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 |
|
|
true |
|
|
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.mdTest 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/supabasemodule usingvi.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
getSupabaseServiceClientto return the mock client - Also mock
'../utils/logger'using the existinglogger.mock.tspattern
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 matchestest('creates a health check with minimal data')— call with only required fields (service_name, status), verify optional fields not includedtest('creates a health check with probe_details')— include JSONB probe_details, verify passed throughtest('throws on empty service_name')— expect Error thrown before Supabase is calledtest('throws on invalid status')— pass status 'unknown', expect Error thrown before Supabase is calledtest('throws on Supabase error')— mock Supabase returning { data: null, error: { message: 'connection failed' } }, verify error thrown with descriptive messagetest('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 usedtest('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 appliedtest('filters by serviceName when provided')— verify .eq() called with service_nametest('respects custom limit')— pass limit: 50, verify .limit(50)
describe('deleteOlderThan'):
test('deletes records older than specified days')— verify .lt() called with correct date calculationtest('returns count of deleted records')— mock returning count
Pattern notes:
- Use
describe/test(notit) to match project convention - Use
beforeEachto reset mocks between tests:vi.clearAllMocks() - Verify
getSupabaseServiceClientis 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.
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 recordtest('defaults status to active')— create without explicit status, verify 'active' sent to Supabasetest('creates with explicit status')— pass status: 'acknowledged', verify it is usedtest('creates with details JSONB')— include details object, verify passed throughtest('throws on empty service_name')— expect Error before Supabase calltest('throws on invalid alert_type')— pass alert_type: 'warning', expect Errortest('throws on invalid status')— pass status: 'pending', expect Errortest('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_nametest('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 > thresholdtest('returns null when no recent alerts')— mock returning empty, verify null
describe('deleteOlderThan'):
test('deletes records older than specified days')— same pattern as HealthCheckModeltest('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.
<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>