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>
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
---
|
||||
phase: 01-data-foundation
|
||||
plan: 02
|
||||
type: execute
|
||||
wave: 2
|
||||
depends_on:
|
||||
- 01-01
|
||||
files_modified:
|
||||
- backend/src/__tests__/models/HealthCheckModel.test.ts
|
||||
- backend/src/__tests__/models/AlertEventModel.test.ts
|
||||
autonomous: true
|
||||
requirements:
|
||||
- INFR-01
|
||||
- INFR-04
|
||||
|
||||
must_haves:
|
||||
truths:
|
||||
- "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)"
|
||||
artifacts:
|
||||
- path: "backend/src/__tests__/models/HealthCheckModel.test.ts"
|
||||
provides: "Unit tests for HealthCheckModel"
|
||||
contains: "HealthCheckModel"
|
||||
- path: "backend/src/__tests__/models/AlertEventModel.test.ts"
|
||||
provides: "Unit tests for AlertEventModel"
|
||||
contains: "AlertEventModel"
|
||||
key_links:
|
||||
- from: "backend/src/__tests__/models/HealthCheckModel.test.ts"
|
||||
to: "backend/src/models/HealthCheckModel.ts"
|
||||
via: "import HealthCheckModel"
|
||||
pattern: "import.*HealthCheckModel"
|
||||
- from: "backend/src/__tests__/models/AlertEventModel.test.ts"
|
||||
to: "backend/src/models/AlertEventModel.ts"
|
||||
via: "import AlertEventModel"
|
||||
pattern: "import.*AlertEventModel"
|
||||
---
|
||||
|
||||
<objective>
|
||||
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.
|
||||
</objective>
|
||||
|
||||
<execution_context>
|
||||
@/home/jonathan/.claude/get-shit-done/workflows/execute-plan.md
|
||||
@/home/jonathan/.claude/get-shit-done/templates/summary.md
|
||||
</execution_context>
|
||||
|
||||
<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
|
||||
</context>
|
||||
|
||||
<tasks>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 1: Create HealthCheckModel unit tests</name>
|
||||
<files>backend/src/__tests__/models/HealthCheckModel.test.ts</files>
|
||||
<action>
|
||||
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 }`
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/jonathan/Coding/cim_summary/backend && npx vitest run src/__tests__/models/HealthCheckModel.test.ts --reporter=verbose 2>&1 | tail -30</automated>
|
||||
</verify>
|
||||
<done>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.</done>
|
||||
</task>
|
||||
|
||||
<task type="auto">
|
||||
<name>Task 2: Create AlertEventModel unit tests</name>
|
||||
<files>backend/src/__tests__/models/AlertEventModel.test.ts</files>
|
||||
<action>
|
||||
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
|
||||
</action>
|
||||
<verify>
|
||||
<automated>cd /home/jonathan/Coding/cim_summary/backend && npx vitest run src/__tests__/models/AlertEventModel.test.ts --reporter=verbose 2>&1 | tail -30</automated>
|
||||
</verify>
|
||||
<done>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.</done>
|
||||
</task>
|
||||
|
||||
</tasks>
|
||||
|
||||
<verification>
|
||||
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
|
||||
</verification>
|
||||
|
||||
<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>
|
||||
|
||||
<output>
|
||||
After completion, create `.planning/phases/01-data-foundation/01-02-SUMMARY.md`
|
||||
</output>
|
||||
Reference in New Issue
Block a user