Files
music-agregator/docs/architecture/flows/monitor-album-stream-manual.puml
T

158 lines
4.8 KiB
Plaintext

@startuml MonitorAlbumStream - Manual Mode Happy Path
skinparam sequenceMessageAlign center
skinparam responseMessageBelowArrow true
title MonitorAlbumStream: Manual Mode (Interactive Prompts)
actor Client
participant "gRPC Server" as Server
participant "monitorWorkflow" as Workflow
participant "MusicAgregatorService" as Service
database "PostgreSQL" as DB
participant "IndexerService" as Indexer
participant "MagnetResolver" as Magnet
participant "TorrentClient\n(qBittorrent)" as QBit
== 1. Initialize Stream ==
Client -> Server: MonitorAlbumStream()
Server -> Client: stream established
Client -> Server: StartMonitorRequest
note right: album_id, quality\nmode = MANUAL
Server -> Workflow: newMonitorWorkflow()
== 2. Fetch Metadata ==
Workflow ->> Client: StatusUpdate(FETCHING_METADATA)
note right #lightblue: "Fetching album metadata..."
Workflow -> Service: getAlbumWithPersist()
Workflow ->> Client: StatusUpdate(FETCHING_METADATA)
note right #lightblue: Data: StreamAlbumInfo\n{artist, title, release_date,\nalready_owned, owned_quality}
== 3. Check Ownership (Interactive) ==
Workflow -> DB: downloads.HasAlbumInQuality()
DB --> Workflow: true (already owned!)
Workflow ->> Client: StatusUpdate(CHECKING_OWNED)
note right #lightyellow: "Already owned in FLAC quality"
Workflow ->> Client: PromptForDecision
note right #orange: type: CONFIRM\nmessage: "Album already owned. Download anyway?"\ndefault: false\ntimeout: max 300s
Client -> Server: UserDecision
note right: confirm: true\n(user chooses to continue)
Workflow -> Workflow: Continue with search
== 4. Search & Parse ==
Workflow ->> Client: StatusUpdate(SEARCHING_INDEXER)
Workflow -> Indexer: Search()
Indexer --> Workflow: 3 results
loop parse results
Workflow -> Magnet: Resolve()
end
Workflow ->> Client: StatusUpdate(PARSING_RESULTS)
note right #lightblue: Data: TorrentList\n[{id, title, seeders, format}, ...]
== 5. Select Torrents (Interactive) ==
Workflow ->> Client: PromptForDecision
note right #orange: type: SELECT_MANY\nmessage: "Select torrents to consider"\noptions: [{id, label, description}, ...]\ndefault: all selected\nmin: 1, max: N
Client -> Server: UserDecision
note right: selected_ids: ["torrent-0", "torrent-2"]\n(user deselects torrent-1)
Workflow -> Workflow: Filter to selected torrents
== 6. Filter by Quality ==
Workflow ->> Client: StatusUpdate(FILTERING_QUALITY)
Workflow -> Workflow: filterByQuality()
note right: 2 releases remain\nafter quality filter
== 7. Select Release (Interactive) ==
Workflow ->> Client: PromptForDecision
note right #orange: type: SELECT_ONE\nmessage: "Select release"\noptions: [{id, label, description}, ...]\ndefault: highest seeders
Client -> Server: UserDecision
note right: selected_id: "release-1"\n(user picks specific release)
Workflow ->> Client: StatusUpdate(SELECTING_RELEASE)
note right #lightblue: Data: ReleaseInfo\n{hash, format, seeders, tracker}
== 8. Confirm Add (Interactive) ==
Workflow ->> Client: StatusUpdate(ADDING_TORRENT)
note right #lightyellow: "Adding torrent: Title..."
Workflow ->> Client: PromptForDecision
note right #orange: type: CONFIRM\nmessage: "Add torrent 'Title' to client?"\nconfirm_label: "Add"\ncancel_label: "Skip"\ndefault: true
Client -> Server: UserDecision
note right: confirm: true
== 9. Add & Save ==
Workflow -> QBit: AddMagnet()
QBit --> Workflow: OK
Workflow ->> Client: StatusUpdate(SAVING)
Workflow -> DB: Create torrent & download
== 10. Complete ==
Workflow ->> Client: StatusUpdate(COMPLETE)
note right #lightblue: "Download started"
Workflow ->> Client: MonitorAlbumResponse
note right #lightgreen: Final result
== Cancel Cleanup (Disconnect or Cancel Message) ==
note over Client, QBit #salmon
**Manual Mode: Disconnect = Cancel**
When client disconnects or sends CancelRequest:
1. Workflow context is cancelled (stops further processing)
2. If torrent was added to qBit: **DeleteTorrent(hash)** removes it + files
3. If download record exists: marked as **cancelled** in DB
4. workflow_run marked as **cancelled** in DB
5. All events persisted to album_events for audit trail
Cleanup uses a fresh context (not the cancelled one).
end note
== Decision Points Summary ==
note over Client, QBit #lightyellow
**Manual Mode Decision Points:**
1. **CHECKING_OWNED** (CONFIRM)
- Triggered when: Album already owned in requested quality
- Default: false (skip)
- Timeout action: Use default
2. **PARSING_RESULTS** (SELECT_MANY)
- Triggered when: Multiple torrents found (>1)
- Default: All selected
- Timeout action: Use defaults
3. **SELECTING_RELEASE** (SELECT_ONE)
- Triggered when: Multiple releases after quality filter (>1)
- Default: Highest seeders
- Timeout action: Use default
4. **ADDING_TORRENT** (CONFIRM)
- Triggered: Always in manual mode
- Default: true (add)
- Timeout action: Use default
end note
@enduml