Files
headquarter/openspec/changes/notification-center/apply-progress.md
T
alex cbaebcf649 feat: notification center backend core (PR-1)
- Add notifications table with Alembic migration
- Notification model with user-scoped indexing and partial index on unread
- NotificationService singleton with create/list/count/mark-read/dismiss
- FastAPI router: GET /notifications, GET /unread, PATCH /{id}/read,
  POST /mark-all-read, DELETE /{id}
- Mute categories filtering from UserConfig
- 13 unit tests for NotificationService
- 10 integration tests for API endpoints
- Updated test_models.py with new table registration

Quality gates: pytest 23 new passed, ruff clean
2026-05-29 12:09:14 +02:00

5.3 KiB

Apply Progress: PR-1 Backend Core for Notification Center

TDD Cycle Evidence

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)

Completed Tasks

  • NC-PR1-001: Alembic migration for notifications table
  • NC-PR1-002: SQLAlchemy Notification model (apps/api/src/models/notification.py)
  • NC-PR1-003: Export Notification in models/__init__.py
  • NC-PR1-004: NotificationService unit tests — basic CRUD (RED)
  • NC-PR1-005: Implement NotificationService singleton (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 + import Notification for Alembic
  • NC-PR1-011: Code quality pass — ruff, test regressions, smoke tests (REFACTOR)

Files Changed

  1. apps/api/alembic/versions/2026_05_29_add_notifications_table.py (new) — Alembic migration
  2. apps/api/src/models/notification.py (new) — SQLAlchemy model
  3. apps/api/src/models/__init__.py — Export Notification
  4. apps/api/src/services/notification_service.py (new)NotificationService singleton
  5. apps/api/src/api/notifications.py (new) — FastAPI router + Pydantic schemas
  6. apps/api/src/api/__init__.py — Export notifications_router
  7. apps/api/src/main.py — Register router, import Notification for Alembic
  8. apps/api/tests/unit/test_notification_service.py (new) — 13 unit tests
  9. apps/api/tests/integration/test_notifications_api.py (new) — 10 integration tests
  10. apps/api/tests/integration/test_models.py — Updated expected tables list

Test Commands & Exit Codes

# 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

# Combined new tests
cd apps/api && python -m pytest tests/unit/test_notification_service.py tests/integration/test_notifications_api.py -v
# Exit: 0 — 23 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)

# Ruff linting on all new/modified files
cd apps/api && python -m ruff check \
  src/models/notification.py \
  src/models/__init__.py \
  src/services/notification_service.py \
  src/api/notifications.py \
  src/api/__init__.py \
  src/main.py \
  alembic/versions/2026_05_29_add_notifications_table.py \
  tests/unit/test_notification_service.py \
  tests/integration/test_notifications_api.py \
  tests/integration/test_models.py
# Exit: 0 — All checks passed

# Smoke tests
health: 200
notifications unauth: 401

Deviations from Design

  • SQLAlchemy metadata column name conflict: Base.metadata is reserved by SQLAlchemy DeclarativeBase. Used notification_metadata as the Python attribute name with DB column name "metadata". In the Pydantic response model, used Field(serialization_alias="metadata") so the JSON API still exposes metadata as specified.
  • created_at type in Pydantic: Used datetime instead of str to leverage FastAPI's automatic ISO serialization.

Surprises / Decisions

  1. SQLite func.now() resolution: test_list_notifications_orders_by_created_at_desc failed because multiple rapid INSERTs got identical timestamps. Fixed by explicitly setting created_at offsets in the test after creation.
  2. Pre-existing integration test failures: ~40 integration tests fail due to missing asyncpg module and direct PostgreSQL connection attempts in their custom setup code. These are unrelated to our changes.
  3. Pre-existing test_models.py outdated: The test_expected_tables_are_registered assertion had a hardcoded set missing many newer tables. Updated it to include all current tables (including notifications).

Remaining Tasks

None — PR-1 is complete.

PR Boundary

This PR covers PR-1 only (NC-PR1-001 through NC-PR1-011). PR-2 (backend integration) and PR-3/PR-4 (frontend) are out of scope.