Skip to content

Refactor RepoDiffer PR monitoring to hexagonal ports/adapters #77

@ponbac

Description

@ponbac

Summary

RepoDiffer currently mixes multiple concerns in one type:

  • domain diff logic
  • Azure DevOps provider calls
  • Tokio worker orchestration (mpsc, interval, retry)
  • cache/state ownership
  • notification side effects

This creates tight coupling between domain logic and provider/runtime details, and makes it harder to evolve pull request monitoring toward the same hexagonal structure used by time tracking.

Goal

Refactor PR monitoring so business logic is provider-agnostic and runtime/provider specifics are isolated in adapters.

Proposed architecture

Inbound ports (use-cases)

  • PullRequestMonitorService
    • start(repo_key, interval)
    • stop(repo_key)
    • force_update(repo_key)
    • get_status(repo_key) / list_statuses()
  • PullRequestReadService
    • get_cached_repo_pull_requests(repo_key)
    • get_followed_pull_requests(user_id)
    • get_most_recent_commits(repo_key)

Outbound ports

  • PullRequestProvider
    • fetch open PRs + required details (threads, commits, work items, identities)
  • PullRequestCache
    • read/write snapshots, identities cache, monitor status, timestamps
  • PullRequestNotifier
    • publish PR change events / notify affected users

Domain services

  • PullRequestPollingServiceImpl
    • orchestrates provider fetch -> diff -> cache update -> notify
  • PullRequestDiffEngine
    • pure PR snapshot diffing (testable, provider-independent)

Adapter boundaries

  • adapters/outbound/azure_devops/* implements PullRequestProvider
  • cache adapter in adapters/outbound/{postgres|memory} implements PullRequestCache
  • notification adapter wraps existing notification flow behind PullRequestNotifier
  • background worker (tokio::spawn, channels, retry policy) moved to an inbound/background adapter; domain service does not own mpsc/interval loop.

Migration plan (incremental)

  1. Add PR ports + domain service interfaces (no behavior change yet).
  2. Extract diff logic from RepoDiffer::tick into PullRequestDiffEngine.
  3. Introduce PullRequestProvider Azure adapter.
  4. Introduce PullRequestCache adapter (memory first to preserve current behavior).
  5. Add background worker adapter and route /differs endpoints through PullRequestMonitorService.
  6. Migrate pull request read endpoints (and work-item PR enrichment usage) to PullRequestReadService.
  7. Remove legacy RepoDiffer runtime maps/channels from AppState.

Acceptance criteria

  • Domain PR monitoring logic no longer imports az_devops::* or Tokio channel/runtime primitives.
  • RepoDiffer is removed or reduced to adapter-level code.
  • Routes depend on inbound service traits rather than direct AppState internals.
  • Existing behavior preserved:
    • start/stop/force differ actions
    • cached PR reads
    • change notifications
  • PR monitoring is structured for additional SCM providers without modifying domain services.

Out of scope

  • Full multi-provider implementation in this issue (only architecture + Azure adapter migration).

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions