All checks were successful
Build and Push Docker Image / build (push) Successful in 24s
ARCHITECTURE.md: - Directory structure: add middleware/requireAuth.js and favicon assets - §4.1: remove CORS from middleware list - §4.2: all proxy routes now auth-required via requireAuth; add middleware description - §6: cookie payload corrected (no token); document secure+sameSite - §7: add emby:users cache key (60s TTL) - §8: Download Object table: userTag → allTags/matchedUserTag/tagBadges - §9 POST /login: document cookie security attributes - §10: add Tag Badge Rendering section; remove hardcoded line count Diagrams: - class-server.puml: add requireAuth middleware module; update dashboard.js methods (extractAllTags, extractUserTag w/ username, buildTagBadges, getEmbyUsers); add TagBadge value class; add auth relationships for all proxy routes - class-data.puml: Download Object userTag → allTags/matchedUserTag/ tagBadges; add TagBadge class; remove token from Session Cookie - seq-auth.puml: cookie payload no longer contains token; add secure/sameSite note - component.puml: remove CORS component; add requireAuth; consolidate Emby connection to show tag badge + user-summary usage - activity-matching.puml: update to extractAllTags/extractUserTag (with username); showAll uses hasAnyTag; tagBadges built from embyUserMap; add Emby user fetch step; update legend - seq-dashboard.puml: add emby:users cache lookup / Emby fetch for showAll; update matching groups to show tag classification; add tag badge rendering note on renderDownloads()
101 lines
3.4 KiB
Plaintext
101 lines
3.4 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)
|
|
|
|
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
|
|
dashboard -> dashboard : Build embyUserMap\n(lowerName → displayName)
|
|
end
|
|
|
|
group SABnzbd Queue Matching
|
|
loop each queue slot
|
|
dashboard -> dashboard : Match title vs Sonarr queue
|
|
dashboard -> dashboard : Match title vs Radarr queue
|
|
dashboard -> dashboard : extractAllTags() + extractUserTag(username)\nInclude if: showAll+anyTag OR matchedUserTag\nAttach allTags, matchedUserTag\nIf showAll: tagBadges = buildTagBadges(embyUserMap)
|
|
end
|
|
end
|
|
|
|
group SABnzbd History Matching
|
|
loop each history slot
|
|
dashboard -> dashboard : Match title vs Sonarr/Radarr history
|
|
dashboard -> dashboard : Same tag extraction + inclusion logic
|
|
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: allTags, matchedUserTag, tagBadges
|
|
end
|
|
end
|
|
|
|
dashboard --> browser : { user, isAdmin,\ndownloads: [...] }
|
|
deactivate dashboard
|
|
|
|
browser -> browser : renderDownloads() (diff-based)
|
|
note right
|
|
createDownloadCard() renders tag badges:
|
|
- Normal: accent badge for matchedUserTag
|
|
- showAll: amber badges (unmatched tags)
|
|
accent badges (matched → show Emby displayName)
|
|
end note
|
|
deactivate browser
|
|
|
|
@enduml
|