6085859874
- Wire lifecycle_hooks.py to NotificationService after event bus publish - Wire health_monitor.py to NotificationService after state changes - Category/severity mapping: instance.* → info, error → error, unhealthy → warning - Extend UserConfig API with notification_mute_categories and notification_toast_level - 6 integration tests for event-to-notification flow - All producer calls wrapped in try/except — failures logged, pipeline continues Quality gates: pytest 41 passed (monitoring + lifecycle), ruff clean
8.9 KiB
8.9 KiB
Apply Progress: Notification Center
TDD Cycle Evidence (PR-1)
| Cycle | Task | Test File | RED | GREEN | Evidence |
|---|---|---|---|---|---|
| 1 | NC-PR1-004 (basic CRUD) | tests/unit/test_notification_service.py |
13 tests written against missing service | All 13 pass | pytest tests/unit/test_notification_service.py → 13 passed |
| 2 | NC-PR1-005 (edge cases) | tests/unit/test_notification_service.py |
Already included in cycle 1 | Added wrong-owner, mute-categories, cross-user isolation | Same 13 tests pass |
| 3 | NC-PR1-007 (basic endpoints) | tests/integration/test_notifications_api.py |
10 tests written against missing router | All 10 pass | pytest tests/integration/test_notifications_api.py → 10 passed |
| 4 | NC-PR1-008 (API edge cases) | tests/integration/test_notifications_api.py |
Already included in cycle 3 | Pagination, 404 ownership, mute categories at API layer | Same 10 tests pass |
| 5 | NC-PR1-010 (REFACTOR) | All files | — | ruff clean, no regressions | ruff check passes on all new files; existing unit tests 223 passed (4 pre-existing failures unrelated) |
TDD Cycle Evidence (PR-2)
| Cycle | Task | Test File | RED | GREEN | Evidence |
|---|---|---|---|---|---|
| 1 | NC-PR2-004 (producer flow) | tests/integration/test_notifications_lifecycle.py |
4 tests written against unwired producers | Wired lifecycle_hooks.py and health_monitor.py |
4 passed |
| 2 | NC-PR2-004 (severity mapping) | tests/integration/test_notifications_lifecycle.py |
Added error + warning severity tests | Already green from implementation | 6 passed |
| 3 | NC-PR2-003 (UserConfig schema) | src/api/user_config.py |
Schema extended with new optional fields | PATCH/GET endpoints validate correctly | Verified manually |
| 4 | NC-PR2-005 (REFACTOR) | All files | — | ruff clean, no regressions across 41 related tests | All pass |
Completed Tasks
PR-1: Backend Core
- NC-PR1-001: Alembic migration for
notificationstable - NC-PR1-002: SQLAlchemy
Notificationmodel (apps/api/src/models/notification.py) - NC-PR1-003: Export
Notificationinmodels/__init__.py - NC-PR1-004: NotificationService unit tests — basic CRUD (RED)
- NC-PR1-005: Implement
NotificationServicesingleton (GREEN) - NC-PR1-006: Service edge-case and isolation tests (TRIANGULATE)
- NC-PR1-007: API integration tests — basic endpoints (RED)
- NC-PR1-008: Implement FastAPI router + Pydantic schemas (GREEN)
- NC-PR1-009: API edge-case and ownership tests (TRIANGULATE)
- NC-PR1-010: Register router in
main.py+ importNotificationfor Alembic - NC-PR1-011: Code quality pass — ruff, test regressions, smoke tests (REFACTOR)
PR-2: Backend Integration
- NC-PR2-001: Wire
lifecycle_hooks.pytoNotificationService - NC-PR2-002: Wire
health_monitor.pytoNotificationService - NC-PR2-003: Extend
UserConfigschema for notification preferences - NC-PR2-004: Event producer integration tests (RED)
- NC-PR2-005: Verify producer tests pass and clean up (GREEN / REFACTOR)
Files Changed
PR-1 Files
apps/api/alembic/versions/2026_05_29_add_notifications_table.py(new) — Alembic migrationapps/api/src/models/notification.py(new) — SQLAlchemy modelapps/api/src/models/__init__.py— ExportNotificationapps/api/src/services/notification_service.py(new) —NotificationServicesingletonapps/api/src/api/notifications.py(new) — FastAPI router + Pydantic schemasapps/api/src/api/__init__.py— Exportnotifications_routerapps/api/src/main.py— Register router, importNotificationfor Alembicapps/api/tests/unit/test_notification_service.py(new) — 13 unit testsapps/api/tests/integration/test_notifications_api.py(new) — 10 integration testsapps/api/tests/integration/test_models.py— Updated expected tables list
PR-2 Files
apps/api/src/services/lifecycle_hooks.py— WiredNotificationServiceafter event bus publishapps/api/src/services/health_monitor.py— WiredNotificationServiceafter state change event publishapps/api/src/api/user_config.py— Addednotification_mute_categoriesandnotification_toast_levelto Pydantic schemasapps/api/tests/integration/test_notifications_lifecycle.py(new) — 6 integration tests for event-to-notification flow
Test Commands & Exit Codes
PR-1
# Unit tests for NotificationService (13 tests)
cd apps/api && python -m pytest tests/unit/test_notification_service.py -v
# Exit: 0 — 13 passed
# Integration tests for notifications API (10 tests)
cd apps/api && python -m pytest tests/integration/test_notifications_api.py -v
# Exit: 0 — 10 passed
# Existing unit tests (no regressions in our code)
cd apps/api && python -m pytest tests/unit/ -v
# Exit: 1 — 223 passed, 4 failed (pre-existing failures in test_config.py and test_git_repository_clone_preflight.py)
PR-2
# New integration tests for event producers (6 tests)
cd apps/api && python -m pytest tests/integration/test_notifications_lifecycle.py -v
# Exit: 0 — 6 passed
# NotificationService unit tests (no regressions)
cd apps/api && python -m pytest tests/unit/test_notification_service.py -v
# Exit: 0 — 13 passed
# Notifications API integration tests (no regressions)
cd apps/api && python -m pytest tests/integration/test_notifications_api.py -v
# Exit: 0 — 10 passed
# Health monitor unit tests (no regressions)
cd apps/api && python -m pytest tests/unit/test_health_monitor.py -v
# Exit: 0 — 6 passed
# Event integration tests (no regressions)
cd apps/api && python -m pytest tests/integration/test_events.py -v
# Exit: 0 — 6 passed
# Combined relevant test suite (41 tests)
cd apps/api && python -m pytest \
tests/unit/test_notification_service.py \
tests/integration/test_notifications_api.py \
tests/integration/test_notifications_lifecycle.py \
tests/unit/test_health_monitor.py \
tests/integration/test_events.py \
-v
# Exit: 0 — 41 passed
# Ruff linting on all PR-2 modified files
cd apps/api && python -m ruff check \
src/services/lifecycle_hooks.py \
src/services/health_monitor.py \
src/api/user_config.py \
tests/integration/test_notifications_lifecycle.py
# Exit: 0 — All checks passed
Deviations from Design
PR-1
- SQLAlchemy
metadatacolumn name conflict:Base.metadatais reserved by SQLAlchemy DeclarativeBase. Usednotification_metadataas the Python attribute name with DB column name"metadata". In the Pydantic response model, usedField(serialization_alias="metadata")so the JSON API still exposesmetadataas specified. created_attype in Pydantic: Useddatetimeinstead ofstrto leverage FastAPI's automatic ISO serialization.
PR-2
- None. All mappings and behaviors match the design spec (section 1.3) and task requirements exactly.
Surprises / Decisions
PR-1
- SQLite
func.now()resolution:test_list_notifications_orders_by_created_at_descfailed because multiple rapid INSERTs got identical timestamps. Fixed by explicitly settingcreated_atoffsets in the test after creation. - Pre-existing integration test failures: ~40 integration tests fail due to missing
asyncpgmodule and direct PostgreSQL connection attempts in their custom setup code. These are unrelated to our changes. - Pre-existing
test_models.pyoutdated: Thetest_expected_tables_are_registeredassertion had a hardcoded set missing many newer tables. Updated it to include all current tables (includingnotifications).
PR-2
- Health monitor
test_health_monitor_unhealthy_creates_warning_notificationrequiredpublic_url: The health monitor only checks tunnel health wheninstance.public_urlis truthy. Without setting it on the test fixture instance,_derive_statusreturned"running"instead of"unhealthy", which created an"info"notification. Fixed by settingtest_instance.public_urlin the test before calling_check_instance. - Patch target for failure test: The
test_notification_failure_does_not_block_event_pipelinepatchessrc.services.lifecycle_hooks.notification_service.create_notification. This only works becauselifecycle_hooks.pyimportsnotification_serviceat module level, making the attribute resolvable byunittest.mock.patch. - No schema migration needed for UserConfig: Preferences are stored in the existing JSON
configblob, consistent with the existing pattern (theme, editor, git identity). No Alembic migration required.
Remaining Tasks
- PR-3: Frontend Core (NC-PR3-001 through NC-PR3-012)
- PR-4: Toast Coordination (NC-PR4-001 through NC-PR4-006)
PR Boundary
This progress covers PR-1 and PR-2. PR-3 (frontend core — NotificationProvider, useNotifications, NotificationCenter, NotificationItem, styles, AppShell integration) and PR-4 (toast coordination — EventToastBridge preferences, settings UI) are out of scope.