Update flow diagrams for event bus architecture, cancel cleanup, and SubscribeEvents

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/claude-agent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Alexander
2026-05-11 15:54:32 +02:00
parent 93821ab214
commit 69752bd6a2
5 changed files with 231 additions and 103 deletions
@@ -1,11 +1,11 @@
@startuml MonitorAlbumStream Protocol
skinparam sequenceMessageAlign center
title MonitorAlbumStream: Message Protocol
title MonitorAlbumStream & SubscribeEvents: Message Protocol
participant "Client" as C
participant "Server" as S
== Stream Initialization ==
== MonitorAlbumStream (Bidirectional) ==
C -> S: gRPC MonitorAlbumStream()
note right: Opens bidirectional stream
@@ -50,7 +50,44 @@ note left #lightgreen
- recoverable: bool
end note
== Monitor Steps (Status Updates) ==
== SubscribeEvents (Server-Side Stream) ==
C -> S: SubscribeEvents(SubscribeEventsRequest)
note right #lightyellow
**SubscribeEventsRequest:**
- since_seq: int64 (0 = live only, >0 = replay from seq)
**Response stream: AlbumEvent**
- seq: int64 (monotonic sequence number)
- workflow_run_id, album_id, quality
- event_type: status | error | result
- step: MonitorStep name
- message: human-readable text
- data_json: bytes (optional structured data)
- timestamp_ms: int64
**Global firehose**: receives events from ALL running workflows.
Client-side filtering by album_id if needed.
end note
== Event Flow Architecture ==
note over C, S #lightblue
**Event Path (DB first, bus second):**
1. Workflow step executes
2. Event written to **album_events** table (synchronous, durable)
3. Event published to **EventBus** (async, ephemeral notification)
4. Bus fans out to subscribers:
- MonitorAlbumStream clients (per-topic)
- SubscribeEvents clients (global)
5. Subscribers convert event to proto and stream.Send()
**DB is source of truth. Bus is notification layer.**
Events are never lost, even if no subscribers are connected.
end note
== Monitor Steps ==
note over C, S #lightyellow
**MonitorStep Enum:**
@@ -65,34 +102,34 @@ note over C, S #lightyellow
9. COMPLETE - Workflow finished
end note
== Prompt Types (Manual Mode) ==
== Mode Comparison ==
note over C, S #orange
**CONFIRM** (yes/no decision)
- confirm_label, cancel_label
- default_value: bool
note over C, S #lightyellow
**AUTOMATIC mode:**
- Workflow runs as background goroutine
- Client can disconnect, workflow continues (fire-and-forget)
- Duplicate request for same album+quality subscribes to existing
- Events delivered via EventBus bridge
**SELECT_ONE** (pick one option)
- options: [{id, label, description}]
- default_id: pre-selected option
**SELECT_MANY** (pick multiple options)
- options: [{id, label, description}]
- default_ids: pre-selected options
- min_selections, max_selections
**MANUAL mode:**
- Workflow runs inline in stream handler
- Interactive prompts at 4 decision points
- Disconnect = cancel = full cleanup (qBit delete + DB cancel)
- Events delivered directly via stream + persisted to DB
end note
== Data Payloads ==
== Persistence ==
note over C, S #lightblue
**StreamAlbumInfo** (at FETCHING_METADATA)
- artist, title, release_date, already_owned, owned_quality
note over C, S #lightgreen
**workflow_runs table:**
- Tracks workflow lifecycle: running → completed | failed | cancelled
- Unique constraint: one running workflow per album+quality
- Used for deduplication, recovery, and audit
**TorrentList** (at PARSING_RESULTS)
- torrents: [{id, title, tracker, seeders, format, lossless}]
**ReleaseInfo** (at SELECTING_RELEASE)
- info_hash, format, bit_depth, sample_rate, seeders, tracker
**album_events table:**
- Audit log of all workflow events
- seq BIGSERIAL for ordering and replay
- Supports subscribe-before-query replay pattern
end note
== Timeout Behavior ==
@@ -102,9 +139,6 @@ When prompt times out (max: 300s):
- Server uses **default decision** value
- Workflow continues automatically
- No error is raised
Timeout is capped server-side at 300s.
If timeout_seconds on prompt is 0 or exceeds max, 300s is used.
end note
@enduml