Files
sofarr/docs/diagrams/component.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

119 lines
3.2 KiB
Plaintext

@startuml component
!theme plain
title sofarr — Component Diagram
skinparam componentStyle rectangle
skinparam packageStyle frame
package "Browser" as browser {
[index.html] as html
[app.js] as appjs
[style.css] as css
html ..> appjs : loads
html ..> css : loads
}
package "Express Server" as server {
[index.js\nEntry Point] as entry
[app.js\ncreateApp() factory] as appfactory
package "Middleware" {
[helmet\n(CSP nonce, HSTS)] as hm
[express-rate-limit\n(API + login)] as rl
[cookie-parser\n(signed cookies)] as cp
[express.json\n(64kb limit)] as ej
[express.static] as es
[requireAuth.js] as requireauth
[verifyCsrf.js\n(double-submit)] as verifycsrf
}
package "Routes" as routes {
[auth.js\n/api/auth\n(pre-CSRF)] as auth
[dashboard.js\n/api/dashboard\n(+SSE /stream)] as dashboard
[emby.js\n/api/emby] as emby_route
[sabnzbd.js\n/api/sabnzbd] as sab_route
[sonarr.js\n/api/sonarr] as sonarr_route
[radarr.js\n/api/radarr] as radarr_route
}
package "Utilities" as utils {
[poller.js] as poller
[cache.js\nMemoryCache] as cache
[config.js] as config
[qbittorrent.js\nQBittorrentClient] as qbt
[tokenStore.js\n(tokens.json)] as tokenstore
[sanitizeError.js] as sanitize
[logger.js] as logger
}
entry --> appfactory : createApp()
entry --> es : serve public/
entry --> poller : startPoller()
appfactory --> hm
appfactory --> rl
appfactory --> cp
appfactory --> ej
appfactory --> auth : mount before verifyCsrf
appfactory --> verifycsrf : applied to all /api below
appfactory --> dashboard
appfactory --> emby_route
appfactory --> sab_route
appfactory --> sonarr_route
appfactory --> radarr_route
emby_route --> requireauth
sab_route --> requireauth
sonarr_route --> requireauth
radarr_route --> requireauth
dashboard --> requireauth
auth --> tokenstore : storeToken / getToken / clearToken
dashboard --> cache : read poll:* keys
dashboard --> poller : pollAllServices()\n(on-demand mode)
dashboard --> config : getSonarrInstances()\ngetRadarrInstances()
dashboard --> qbt : mapTorrentToDownload()
poller --> cache : set poll:* keys
poller --> config : get all instances
poller --> qbt : getTorrents()
poller --> logger
qbt --> config : getQbittorrentInstances()
qbt --> logger
auth ..> sanitize
dashboard ..> sanitize
note "Browser uses EventSource\n(SSE) to /stream.\nServer pushes on each\npoll cycle — no client timer." as sseNote
sseNote .. dashboard
}
cloud "External Services" as external {
[Emby / Jellyfin] as emby
[SABnzbd] as sab
[Sonarr] as sonarr
[Radarr] as radarr
[qBittorrent] as qbit
}
auth --> emby : authenticate\nuser profile
dashboard --> emby : GET /Users\n(user-summary + tag badge classification)
emby_route --> emby
sab_route --> sab
sonarr_route --> sonarr
radarr_route --> radarr
poller --> sab : queue + history
poller --> sonarr : tags + queue + history
poller --> radarr : tags + queue + history
qbt --> qbit : login + torrents/info
appjs --> auth : POST /login\nGET /me\nGET /csrf\nPOST /logout
appjs --> dashboard : GET /stream (SSE)\nGET /user-downloads\nGET /status
es --> html : serve static
@enduml