Files
sofarr/docs/diagrams/seq-dashboard.puml
Gronod 9751dbf98d
Some checks failed
Build and Push Docker Image / build (push) Successful in 31s
CI / Security audit (push) Successful in 51s
CI / Tests & coverage (push) Successful in 1m6s
Render PlantUML Diagrams / Render .puml → .png (push) Failing after 47s
docs(diagrams): review + fix all .puml files; touch all to trigger render
seq-auth:
- startAutoRefresh() -> startSSE(), stopAutoRefresh() -> stopSSE()
- Cookie secure flag: 'secure (prod)' -> 'secure (if TRUST_PROXY)'

component:
- Fix typo creatApp -> createApp
- Add GET /csrf, POST /logout to browser->auth arrow
- Add GET /stream (SSE) to browser->dashboard arrow

class-server:
- Add subscribers Set, onPollComplete(), offPollComplete() to Poller class

class-data:
- Add SSE Event /stream shape alongside API Response /user-downloads
- Add sser *-- dl relationship

state-ui:
- Fix invalid multi-line transition labels with raw Unicode arrows
  (broke PlantUML parser); replace with valid \n escapes on single line

seq-dashboard, seq-polling, state-poller, activity-matching:
- Whitespace touch to trigger render-diagrams CI workflow
2026-05-17 10:20:52 +01:00

69 lines
2.4 KiB
Plaintext

@startuml seq-dashboard
!theme plain
title sofarr — Dashboard SSE Stream Sequence
actor User as user
participant "Browser\n(app.js)" as browser
participant "Express\n/api/dashboard" as dashboard
participant "MemoryCache" as cache
participant "Poller" as poller
participant "External\nServices" as ext
== SSE Connection (on login / page load) ==
user -> browser : Login success\nor valid session
activate browser
browser -> dashboard : GET /api/dashboard/stream\n(EventSource, Cookie: emby_user)
activate dashboard
dashboard -> dashboard : requireAuth: parse cookie\nextract username, isAdmin
dashboard -> dashboard : Set headers:\nContent-Type: text/event-stream\nX-Accel-Buffering: no
dashboard -> dashboard : Register in activeClients Map\n{ user, type:'sse', connectedAt }
alt Polling disabled AND cache empty
dashboard -> poller : pollAllServices()
activate poller
poller -> ext : Parallel API calls
ext --> poller : Raw data
poller -> cache : set poll:* keys (TTL=30s)
deactivate poller
end
== Initial Payload (sent immediately on connect) ==
dashboard -> cache : get all poll:* keys
dashboard -> dashboard : Build seriesMap, moviesMap,\nsonarrTagMap, radarrTagMap
alt showAll=true
dashboard -> cache : get('emby:users')
alt cache miss
dashboard -> ext : GET /Users (Emby)
ext --> dashboard : [{ Name, ... }]
dashboard -> cache : set('emby:users', map, 60s)
end
end
dashboard -> dashboard : Match SABnzbd/qBit downloads\nvs Sonarr/Radarr records\nextractUserTag / buildTagBadges
dashboard --> browser : data: { user, isAdmin, downloads }
browser -> browser : hideLoading()\nrenderDownloads()
== Pushed Updates (on every poll cycle) ==
loop Each poll cycle completes
poller -> poller : pollAllServices() complete
poller -> dashboard : onPollComplete callback fires
dashboard -> cache : get all poll:* keys
dashboard -> dashboard : Rebuild download payload
dashboard --> browser : data: { user, isAdmin, downloads }
browser -> browser : renderDownloads() (diff-based)
end
== Heartbeat (every 25s) ==
dashboard --> browser : : heartbeat
note right : Keeps connection alive\nthrough idle-timeout proxies
== Client Disconnects ==
user -> browser : Close tab / logout
browser -> dashboard : TCP close (req 'close' event)
dashboard -> dashboard : offPollComplete(callback)\nclearInterval(heartbeat)\ndelete activeClients[key]
deactivate dashboard
deactivate browser
@enduml