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
240 lines
5.2 KiB
Plaintext
240 lines
5.2 KiB
Plaintext
@startuml class-data
|
|
!theme plain
|
|
title sofarr — Data Model Diagram
|
|
|
|
skinparam classAttributeIconSize 0
|
|
|
|
package "External API Responses" {
|
|
class "SABnzbd Queue Slot" as sabq {
|
|
+ filename : string
|
|
+ nzbname : string
|
|
+ percentage : string
|
|
+ mb : string
|
|
+ mbmissing : string
|
|
+ size : string
|
|
+ timeleft : string
|
|
+ status : string
|
|
+ storage : string
|
|
}
|
|
|
|
class "SABnzbd History Slot" as sabh {
|
|
+ name : string
|
|
+ nzb_name : string
|
|
+ nzbname : string
|
|
+ status : string
|
|
+ size : string
|
|
+ completed_time : string
|
|
+ storage : string
|
|
}
|
|
|
|
class "Sonarr Queue Record" as sqr {
|
|
+ id : number
|
|
+ seriesId : number
|
|
+ series : SonarrSeries
|
|
+ title : string
|
|
+ sourceTitle : string
|
|
+ trackedDownloadStatus : string
|
|
+ trackedDownloadState : string
|
|
+ statusMessages : StatusMessage[]
|
|
+ errorMessage : string
|
|
}
|
|
|
|
class "Sonarr History Record" as shr {
|
|
+ id : number
|
|
+ seriesId : number
|
|
+ title : string
|
|
+ sourceTitle : string
|
|
+ eventType : string
|
|
}
|
|
|
|
class "SonarrSeries" as ss {
|
|
+ id : number
|
|
+ title : string
|
|
+ titleSlug : string
|
|
+ path : string
|
|
+ tags : number[]
|
|
+ images : Image[]
|
|
+ _instanceUrl : string
|
|
}
|
|
|
|
class "Radarr Queue Record" as rqr {
|
|
+ id : number
|
|
+ movieId : number
|
|
+ movie : RadarrMovie
|
|
+ title : string
|
|
+ sourceTitle : string
|
|
+ trackedDownloadStatus : string
|
|
+ trackedDownloadState : string
|
|
+ statusMessages : StatusMessage[]
|
|
+ errorMessage : string
|
|
}
|
|
|
|
class "Radarr History Record" as rhr {
|
|
+ id : number
|
|
+ movieId : number
|
|
+ title : string
|
|
+ sourceTitle : string
|
|
+ eventType : string
|
|
}
|
|
|
|
class "RadarrMovie" as rm {
|
|
+ id : number
|
|
+ title : string
|
|
+ titleSlug : string
|
|
+ path : string
|
|
+ tags : number[]
|
|
+ images : Image[]
|
|
+ _instanceUrl : string
|
|
}
|
|
|
|
class "Tag" as tag {
|
|
+ id : number
|
|
+ label : string
|
|
}
|
|
|
|
class "Image" as img {
|
|
+ coverType : string
|
|
+ remoteUrl : string
|
|
+ url : string
|
|
}
|
|
|
|
class "StatusMessage" as sm {
|
|
+ title : string
|
|
+ messages : string[]
|
|
}
|
|
|
|
class "qBittorrent Torrent" as qbt {
|
|
+ name : string
|
|
+ hash : string
|
|
+ size : number
|
|
+ completed : number
|
|
+ progress : number (0-1)
|
|
+ state : string
|
|
+ dlspeed : number
|
|
+ eta : number
|
|
+ num_seeds : number
|
|
+ num_leechs : number
|
|
+ availability : number
|
|
+ category : string
|
|
+ tags : string
|
|
+ save_path : string
|
|
+ content_path : string
|
|
+ instanceId : string
|
|
+ instanceName : string
|
|
}
|
|
|
|
class "Emby User" as eu {
|
|
+ Id : string
|
|
+ Name : string
|
|
+ Policy : { IsAdministrator: boolean }
|
|
}
|
|
|
|
sqr *-- ss : embedded\n(includeSeries)
|
|
rqr *-- rm : embedded\n(includeMovie)
|
|
sqr *-- sm
|
|
rqr *-- sm
|
|
ss *-- img
|
|
rm *-- img
|
|
}
|
|
|
|
package "sofarr Internal Models" {
|
|
class "Download Object" as dl {
|
|
+ type : 'series' | 'movie' | 'torrent'
|
|
+ title : string
|
|
+ coverArt : string | null
|
|
+ status : string
|
|
+ progress : string
|
|
+ mb : string
|
|
+ mbmissing : string
|
|
+ size : string
|
|
+ speed : string
|
|
+ eta : string
|
|
+ seriesName : string | null
|
|
+ movieName : string | null
|
|
+ episodeInfo : object | null
|
|
+ movieInfo : object | null
|
|
+ allTags : string[]
|
|
+ matchedUserTag : string | null
|
|
+ tagBadges : TagBadge[] | undefined
|
|
+ importIssues : string[] | null
|
|
+ downloadPath : string | null
|
|
+ targetPath : string | null
|
|
+ arrLink : string | null
|
|
+ qbittorrent : boolean
|
|
+ seeds : number
|
|
+ peers : number
|
|
+ availability : string
|
|
+ rawSize : number
|
|
+ rawSpeed : number
|
|
+ rawEta : number
|
|
+ hash : string
|
|
+ category : string
|
|
+ completedAt : string
|
|
}
|
|
|
|
class "TagBadge" as tagbadge <<value>> {
|
|
+ label : string
|
|
+ matchedUser : string | null
|
|
}
|
|
|
|
class "API Response\n/user-downloads" as apir {
|
|
+ user : string
|
|
+ isAdmin : boolean
|
|
+ downloads : Download[]
|
|
}
|
|
|
|
class "SSE Event\n/stream (data: frame)" as sser {
|
|
+ user : string
|
|
+ isAdmin : boolean
|
|
+ downloads : Download[]
|
|
' Same shape as /user-downloads response.
|
|
' Pushed after every poll cycle completes.
|
|
}
|
|
|
|
class "Status Response\n/status" as statr {
|
|
+ server : ServerInfo
|
|
+ polling : PollingInfo
|
|
+ cache : CacheStats
|
|
+ clients : ClientInfo[]
|
|
}
|
|
|
|
class "ServerInfo" as si {
|
|
+ uptimeSeconds : number
|
|
+ nodeVersion : string
|
|
+ memoryUsageMB : number
|
|
+ heapUsedMB : number
|
|
+ heapTotalMB : number
|
|
}
|
|
|
|
class "PollingInfo" as pi {
|
|
+ enabled : boolean
|
|
+ intervalMs : number
|
|
+ lastPoll : PollTimings
|
|
}
|
|
|
|
class "Session Cookie\nemby_user" as cookie {
|
|
+ id : string
|
|
+ name : string
|
|
+ isAdmin : boolean
|
|
' Note: Emby AccessToken intentionally excluded
|
|
}
|
|
|
|
apir *-- dl
|
|
sser *-- dl
|
|
statr *-- si
|
|
statr *-- pi
|
|
}
|
|
|
|
' Data flow connections
|
|
sabq ..> dl : matched &\ntransformed
|
|
sabh ..> dl : matched &\ntransformed
|
|
qbt ..> dl : mapTorrentToDownload()
|
|
ss ..> dl : coverArt, seriesName,\npath, tags
|
|
rm ..> dl : coverArt, movieName,\npath, tags
|
|
tag ..> dl : allTags / matchedUserTag
|
|
eu ..> cookie : login creates
|
|
eu ..> tagbadge : buildTagBadges()
|
|
dl *-- tagbadge : tagBadges[]
|
|
|
|
@enduml
|