merge: develop into main (fix Mermaid diagram rendering)
This commit is contained in:
@@ -941,8 +941,8 @@ graph TB
|
||||
sonarr_r --> sonarr
|
||||
radarr_r --> radarr
|
||||
|
||||
appjs -->|POST /login\nGET /me\nGET /csrf\nPOST /logout| auth
|
||||
appjs -->|GET /stream SSE\nGET /user-downloads\nGET /status| dashboard
|
||||
appjs -->|POST /login, GET /me, GET /csrf, POST /logout| auth
|
||||
appjs -->|GET /stream SSE, GET /user-downloads, GET /status| dashboard
|
||||
es -->|serve static| html
|
||||
```
|
||||
|
||||
@@ -976,16 +976,16 @@ sequenceDiagram
|
||||
Note over Browser,Emby: Login
|
||||
User->>Browser: Enter credentials (+ rememberMe)
|
||||
Browser->>Auth: POST /api/auth/login
|
||||
Note right of Auth: Rate limit: max 10 failed\nattempts per IP / 15 min
|
||||
Auth->>Emby: POST /Users/authenticatebyname\nDeviceId = sha256(username)[0:16]
|
||||
Note right of Auth: Rate limit: max 10 failed attempts per IP / 15 min
|
||||
Auth->>Emby: POST /Users/authenticatebyname (DeviceId = sha256(username)[0:16])
|
||||
alt Valid credentials
|
||||
Emby-->>Auth: { User.Id, AccessToken }
|
||||
Auth->>Emby: GET /Users/{id}
|
||||
Emby-->>Auth: { Name, Policy.IsAdministrator }
|
||||
Auth->>Tokens: storeToken(userId, AccessToken)
|
||||
Note right of Tokens: Server-side only\n31-day TTL, atomic write
|
||||
Auth->>Auth: Set emby_user cookie\nhttpOnly, sameSite=strict\nsecure (if TRUST_PROXY)\nrememberMe → Max-Age 30d
|
||||
Auth->>Auth: Set csrf_token cookie\nhttpOnly=false, sameSite=strict
|
||||
Note right of Tokens: Server-side only, 31-day TTL, atomic write
|
||||
Auth->>Auth: Set emby_user cookie (httpOnly, sameSite=strict, secure if TRUST_PROXY)
|
||||
Auth->>Auth: Set csrf_token cookie (httpOnly=false, sameSite=strict)
|
||||
Auth-->>Browser: { success: true, user, csrfToken }
|
||||
Browser->>Browser: showDashboard() + startSSE()
|
||||
else Invalid credentials
|
||||
@@ -1023,7 +1023,7 @@ sequenceDiagram
|
||||
User->>Browser: Login success / valid session
|
||||
Browser->>Dashboard: GET /api/dashboard/stream (EventSource)
|
||||
Dashboard->>Dashboard: requireAuth: extract user/isAdmin
|
||||
Dashboard->>Dashboard: Set Content-Type: text/event-stream\nRegister in activeClients
|
||||
Dashboard->>Dashboard: Set Content-Type: text/event-stream, register in activeClients
|
||||
|
||||
opt Polling disabled AND cache empty
|
||||
Dashboard->>Poller: pollAllServices()
|
||||
@@ -1033,7 +1033,7 @@ sequenceDiagram
|
||||
end
|
||||
|
||||
Dashboard->>Cache: get all poll:* keys
|
||||
Dashboard->>Dashboard: Build maps, match downloads\nextractUserTag / buildTagBadges
|
||||
Dashboard->>Dashboard: Build maps, match downloads, extractUserTag / buildTagBadges
|
||||
Dashboard-->>Browser: data: { user, isAdmin, downloads }
|
||||
Browser->>Browser: hideLoading() + renderDownloads()
|
||||
|
||||
@@ -1050,7 +1050,7 @@ sequenceDiagram
|
||||
|
||||
User->>Browser: Close tab / logout
|
||||
Browser->>Dashboard: TCP close (req close event)
|
||||
Dashboard->>Dashboard: offPollComplete(cb)\nclearInterval(heartbeat)\ndelete activeClients[key]
|
||||
Dashboard->>Dashboard: offPollComplete(cb), clearInterval(heartbeat), delete activeClients[key]
|
||||
```
|
||||
|
||||
### 13.4 Background Polling Cycle
|
||||
@@ -1094,8 +1094,8 @@ sequenceDiagram
|
||||
Poller->>QBT: getTorrents()
|
||||
QBT-->>Poller: [{ name, progress, ... }]
|
||||
|
||||
Poller->>Poller: Record per-task timings\nlastPollTimings = { totalMs, timestamp, tasks }
|
||||
Poller->>Cache: set poll:* keys (TTL = POLL_INTERVAL × 3)
|
||||
Poller->>Poller: Record per-task timings: lastPollTimings = { totalMs, timestamp, tasks }
|
||||
Poller->>Cache: set poll:* keys (TTL = POLL_INTERVAL x 3)
|
||||
Poller->>Poller: Notify SSE subscribers (forEach cb())
|
||||
Poller->>Poller: polling = false
|
||||
```
|
||||
@@ -1330,11 +1330,11 @@ stateDiagram-v2
|
||||
Submitting --> [*] : Auth success
|
||||
}
|
||||
|
||||
LoginForm --> Dashboard : Auth success\n(fade transition)
|
||||
LoginForm --> Dashboard : Auth success (fade transition)
|
||||
|
||||
state Dashboard {
|
||||
[*] --> Rendering
|
||||
Rendering --> Rendering : SSE message → renderDownloads()
|
||||
Rendering --> Rendering : SSE message triggers renderDownloads()
|
||||
Rendering --> Rendering : Theme change
|
||||
|
||||
state SSEConnection {
|
||||
@@ -1368,13 +1368,13 @@ stateDiagram-v2
|
||||
|
||||
state Disabled {
|
||||
[*] --> OnDemand
|
||||
OnDemand : No background timer.\nData fetched when dashboard\nrequest finds empty cache.
|
||||
OnDemand : No background timer. Data fetched when dashboard request finds empty cache.
|
||||
}
|
||||
|
||||
Disabled --> Polling : dashboard triggers pollAllServices()
|
||||
Polling --> Disabled : Poll complete (on-demand)
|
||||
|
||||
Idle --> Polling : setInterval fires\nor immediate first poll
|
||||
Idle --> Polling : setInterval fires or immediate first poll
|
||||
|
||||
state Polling {
|
||||
[*] --> Locked
|
||||
@@ -1382,7 +1382,7 @@ stateDiagram-v2
|
||||
Locked --> Fetching
|
||||
Fetching --> Storing : All promises resolved
|
||||
Fetching --> HandleError : Per-service error (caught)
|
||||
Storing --> Notifying : Cache updated\nTTL = POLL_INTERVAL × 3
|
||||
Storing --> Notifying : Cache updated, TTL = POLL_INTERVAL x 3
|
||||
Notifying : Notify SSE subscribers
|
||||
Notifying --> Done
|
||||
Done : polling = false
|
||||
@@ -1401,7 +1401,7 @@ stateDiagram-v2
|
||||
[*] --> Skip
|
||||
Skip : polling === true, skip cycle
|
||||
}
|
||||
Idle --> ConcurrentSkip : Interval fires while\nprevious still running
|
||||
Idle --> ConcurrentSkip : Interval fires while previous still running
|
||||
ConcurrentSkip --> Idle : Log skip
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user