4.9 KiB
08 · End-to-End Workflows
This document traces the main user journeys through the system, tying together blueprints, models, utils, and the Graphify graph.
1. Content Upload → Playlist → Player
flowchart LR
U["Admin uploads media"] --> UF["/content/upload-media"]
UF -->|image| IMG["optimize_image_to_fullhd"]
UF -->|video| VID["validate via ffprobe"]
UF -->|pdf| PDF["pdf2image @300dpi → page PNGs"]
UF -->|pptx| PPT["LibreOffice → PDF → PNG slides"]
UF -->|large file| BG["process_file_in_background (thread)"]
UF --> DB[("Content row")]
DB --> PLA["/content/playlist/<id>/add-content"]
PLA --> PLC["playlist_content (position, duration, muted, edit_on_player_enabled)"]
PLC --> VER["Playlist.increment_version() + cache.clear()"]
VER --> API["/api/playlists/<id>"]
API --> P["Player fetches new playlist"]
Key files: app/blueprints/content.py, app/utils/uploads.py, app/utils/pptx_converter.py, app/models/content.py, app/models/playlist.py.
2. Playlist Synchronization (the "version" mechanism)
Every playlist mutation bumps Playlist.version. Players detect changes by polling:
sequenceDiagram
participant U as Admin UI
participant App
participant DB as SQLite
participant P as Player
U->>App: reorder / mute / duration / add / remove
App->>DB: mutate playlist_content
App->>DB: playlist.increment_version()
App->>App: cache.clear()
loop while player runs
P->>App: GET /api/playlist-version/<player_id>
App-->>P: {version: N}
alt version changed
P->>App: GET /api/playlists/<player_id>
App-->>P: new playlist payload
end
end
Playlist payload items include: file_name, type, duration, position, url (weblink or static file), description, edit_on_player_enabled, muted, audio.
3. On-Player Media Editing Pipeline ⭐ (heat 0.620)
When a signage operator edits an image directly on the player device:
flowchart TD
A["Player posts edited image"] --> B["POST /api/player-edit-media (Bearer + multipart)"]
B --> C{"Locate Content"}
C -->|by filename| D["match filename"]
C -->|edited_media regex| E["match edited_media/<id>/"]
C -->|fallback| F["last PlayerEdit"]
D/E/F --> G["Move original → edited_media/<content_id>/original_*"]
G --> H["Save new version + side-car metadata JSON"]
H --> I{"PlayerUser exists for user_code?"}
I -- no --> J["auto-create PlayerUser"]
I -- yes --> K["reuse"]
J/K --> L["Create PlayerEdit (version, original_name, new_name...)"]
L --> M["Repoint Content.filename → latest edit"]
M --> N["Preserve original_filename"]
N --> O["Playlist.increment_version() + cache.clear()"]
O --> P["Player sees updated media on refresh"]
Why this is a god node: PlayerEdit (99 edges) and PlayerUser (74 edges) make this the most-connected data flow in the system. See app/models/player_edit.py, app/models/player_user.py, app/blueprints/api.py.
4. HTTPS Configuration (Caddy)
flowchart TD
A["Admin → /admin/https-config"] --> B["POST /admin/https-config/update"]
B --> C["Validate + save HTTPSConfig (email, domain, ip, port)"]
C --> D["CaddyConfigGenerator.generate_caddyfile()"]
D --> E{"Mode"}
E -->|HTTP| F[":80 reverse proxy"]
E -->|domain| G["Let's Encrypt automatic HTTPS"]
E -->|IP| H["Internal CA self-signed"]
F/G/H --> I["write_caddyfile(/etc/caddy/Caddyfile)"]
I --> J["POST http://caddy:2019/load (hot reload)"]
J --> K["HTTPS live without restart"]
5. User Management & Auditing
flowchart TD
A["Admin panel"] --> B["/admin/user/create"]
A --> C["/admin/user/<id>/role"]
A --> D["/admin/user/<id>/password"]
A --> E["/admin/user/<id>/delete"]
B/C/D/E --> L["log_action(level, message)"]
L --> S[("server_log")]
S --> F["dashboard / admin recent logs"]
S --> G["/api/logs (limit, level, since)"]
Roles: admin (full), user (manage content/players), viewer (read-only dashboard).
6. Portal SSO (optional corporate gateway)
sequenceDiagram
participant B as Browser
participant G as Umbrella nginx gateway
participant A as DigiServer
B->>G: request (authenticated by portal)
G->>A: proxy + headers X-Auth-Username, X-Auth-Role
A->>A: init_portal_sso before_request
A->>A: _get_or_create_user(username, role)
A-->>B: dashboard (auto logged-in)
7. Media Housekeeping (Leftovers)
Content not assigned to any playlist is flagged as "leftover":
flowchart LR
L["/admin/leftover-media"] --> T["grouped by type: image/video/pdf/pptx + sizes"]
T --> D["/admin/delete-leftover-images|videos"]
D --> X["delete file + edited_media archive + PlayerEdit rows"]
Next: 09 · Legacy & Migrations