@startuml MonitorAlbumStream - Already Owned Scenarios skinparam sequenceMessageAlign center skinparam responseMessageBelowArrow true title MonitorAlbumStream: Already Owned Handling actor Client participant "monitorWorkflow" as Workflow participant "EventBus" as Bus database "PostgreSQL" as DB participant "IndexerService" as Indexer note over Client, Indexer #lightblue All events are persisted to album_events table (DB first) then published to EventBus for live subscribers. In automatic mode, workflow runs as background goroutine. end note == Scenario A: Automatic Mode - Early Return == Client -> Workflow: StartMonitorRequest(mode=AUTOMATIC) Workflow ->> Client: StatusUpdate(FETCHING_METADATA) note right #lightblue: "Fetching album metadata..." Workflow ->> Client: StatusUpdate(FETCHING_METADATA) note right #lightblue: "Got: Artist - Title"\nData: StreamAlbumInfo Workflow ->> Client: StatusUpdate(CHECKING_OWNED) Workflow -> DB: downloads.HasAlbumInQuality() DB --> Workflow: true Workflow ->> Client: StatusUpdate(COMPLETE) note right #lightgreen: "Already owned" Workflow ->> Client: MonitorAlbumResponse note right: album: monitored\ndownload: existing info\nrelease: nil (no search) note over Client, Workflow #lightblue **Automatic Mode**: Skips search entirely. Returns immediately with existing download info. end note == Scenario B: Manual Mode - User Confirms Continue == Client -> Workflow: StartMonitorRequest(mode=MANUAL) Workflow ->> Client: StatusUpdate(FETCHING_METADATA) Workflow ->> Client: StatusUpdate(FETCHING_METADATA) Workflow ->> Client: StatusUpdate(CHECKING_OWNED) Workflow -> DB: downloads.HasAlbumInQuality() DB --> Workflow: true Workflow ->> Client: PromptForDecision note right #orange: type: CONFIRM\nmessage: "Album already owned. Download anyway?"\ndefault: false Client -> Workflow: UserDecision(confirm=true) note right #lightgreen: User chooses\nto continue Workflow ->> Client: StatusUpdate(SEARCHING_INDEXER) note right: Proceeds with normal flow... Workflow -> Indexer: Search() note right: ... continues to completion == Scenario C: Manual Mode - User Skips == Client -> Workflow: StartMonitorRequest(mode=MANUAL) Workflow ->> Client: StatusUpdate(FETCHING_METADATA) Workflow ->> Client: StatusUpdate(FETCHING_METADATA) Workflow ->> Client: StatusUpdate(CHECKING_OWNED) Workflow -> DB: downloads.HasAlbumInQuality() DB --> Workflow: true Workflow ->> Client: PromptForDecision note right #orange: type: CONFIRM\nmessage: "Album already owned. Download anyway?" Client -> Workflow: UserDecision(confirm=false) note right #lightyellow: User chooses\nto skip Workflow ->> Client: StatusUpdate(COMPLETE) note right: "Skipped - already owned" Workflow ->> Client: MonitorAlbumResponse note right: album: monitored\ndownload: existing info\nrelease: nil == Scenario D: Manual Mode - Timeout == Client -> Workflow: StartMonitorRequest(mode=MANUAL) Workflow ->> Client: StatusUpdate(FETCHING_METADATA) Workflow ->> Client: StatusUpdate(FETCHING_METADATA) Workflow ->> Client: StatusUpdate(CHECKING_OWNED) Workflow ->> Client: PromptForDecision note over Client, Workflow #lightyellow Client does not respond within timeout (max: 300s) end note Workflow -> Workflow: Use default decision note right: default: false\n(skip download) Workflow ->> Client: StatusUpdate(COMPLETE) note right: "Skipped - already owned" Workflow ->> Client: MonitorAlbumResponse @enduml