- docs/ARCHITECTURE.md: full system overview, technology stack, directory structure, component architecture, data flow, auth, polling/caching, download matching pipeline, API reference, frontend architecture, configuration, deployment guide - docs/diagrams/component.puml: system component diagram - docs/diagrams/seq-auth.puml: authentication sequence diagram - docs/diagrams/seq-dashboard.puml: dashboard request sequence diagram - docs/diagrams/seq-polling.puml: background polling cycle sequence - docs/diagrams/class-server.puml: server-side class/module diagram - docs/diagrams/class-data.puml: data model / entity diagram - docs/diagrams/state-ui.puml: frontend UI state diagram - docs/diagrams/state-poller.puml: poller state diagram - docs/diagrams/activity-matching.puml: download matching activity diagram
86 lines
2.9 KiB
Plaintext
86 lines
2.9 KiB
Plaintext
@startuml seq-dashboard
|
|
!theme plain
|
|
title sofarr — Dashboard Request 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
|
|
|
|
== Periodic Refresh (or Initial Load) ==
|
|
user -> browser : (auto-refresh fires)
|
|
activate browser
|
|
browser -> dashboard : GET /api/dashboard/user-downloads\n?refreshRate=5000&showAll=false
|
|
activate dashboard
|
|
|
|
dashboard -> dashboard : Parse emby_user cookie\nExtract username, isAdmin
|
|
dashboard -> dashboard : Track client refresh rate\nin activeClients Map
|
|
|
|
alt Polling disabled AND cache empty
|
|
dashboard -> poller : pollAllServices()
|
|
activate poller
|
|
poller -> ext : Parallel API calls\n(SAB, Sonarr, Radarr, qBit)
|
|
ext --> poller : Raw data
|
|
poller -> cache : set poll:* keys\n(TTL = 30s)
|
|
deactivate poller
|
|
end
|
|
|
|
dashboard -> cache : get('poll:sab-queue')
|
|
cache --> dashboard : { slots, status, speed }
|
|
dashboard -> cache : get('poll:sab-history')
|
|
cache --> dashboard : { slots }
|
|
dashboard -> cache : get('poll:sonarr-tags')
|
|
cache --> dashboard : [{ instance, data }]
|
|
dashboard -> cache : get('poll:sonarr-queue')
|
|
cache --> dashboard : { records } (with embedded series)
|
|
dashboard -> cache : get('poll:sonarr-history')
|
|
cache --> dashboard : { records }
|
|
dashboard -> cache : get('poll:radarr-queue')
|
|
cache --> dashboard : { records } (with embedded movie)
|
|
dashboard -> cache : get('poll:radarr-history')
|
|
cache --> dashboard : { records }
|
|
dashboard -> cache : get('poll:radarr-tags')
|
|
cache --> dashboard : [{id, label}]
|
|
dashboard -> cache : get('poll:qbittorrent')
|
|
cache --> dashboard : [torrent, ...]
|
|
|
|
dashboard -> dashboard : Build seriesMap from\nSonarr queue records
|
|
dashboard -> dashboard : Build moviesMap from\nRadarr queue records
|
|
dashboard -> dashboard : Build tag maps\n(id → label)
|
|
|
|
group SABnzbd Queue Matching
|
|
loop each queue slot
|
|
dashboard -> dashboard : Match title vs Sonarr queue
|
|
dashboard -> dashboard : Match title vs Radarr queue
|
|
dashboard -> dashboard : Resolve series/movie\n→ extract user tag\n→ filter by username
|
|
end
|
|
end
|
|
|
|
group SABnzbd History Matching
|
|
loop each history slot
|
|
dashboard -> dashboard : Match title vs Sonarr history
|
|
dashboard -> dashboard : Match title vs Radarr history
|
|
dashboard -> dashboard : Resolve via seriesMap/moviesMap\n→ extract user tag\n→ filter
|
|
end
|
|
end
|
|
|
|
group qBittorrent Matching
|
|
loop each torrent
|
|
dashboard -> dashboard : 1. Match vs Sonarr queue
|
|
dashboard -> dashboard : 2. Match vs Radarr queue
|
|
dashboard -> dashboard : 3. Match vs Sonarr history
|
|
dashboard -> dashboard : 4. Match vs Radarr history
|
|
dashboard -> dashboard : mapTorrentToDownload()\n→ enrich with series/movie info
|
|
end
|
|
end
|
|
|
|
dashboard --> browser : { user, isAdmin,\ndownloads: [...] }
|
|
deactivate dashboard
|
|
|
|
browser -> browser : renderDownloads()\n(diff-based update)
|
|
deactivate browser
|
|
|
|
@enduml
|