updates to digiserver app server

This commit is contained in:
2026-09-10 21:03:16 +03:00
parent 046f5e5efd
commit 1c5186463a
129 changed files with 33014 additions and 17 deletions
+198
View File
@@ -0,0 +1,198 @@
# 01 · System Architecture
> Generated from the Graphify knowledge graph (41 communities) and source analysis of `digiserver-v2`.
---
## 1. System Overview
DigiServer v2 is a Flask application serving **three audiences**:
1. **Humans (admins)** — manage content, playlists, players, users, HTTPS via the web UI.
2. **Players (physical signage)** — poll the REST API for playlists, send status feedback, upload edited media.
3. **Operators** — deploy/update player software remotely over SSH.
```mermaid
flowchart LR
subgraph Browser["Web UI (Admins)"]
A[Login]
B[Dashboard / Admin / Content / Players]
end
subgraph App["digiserver-app (Flask :5000)"]
C[Gunicorn x4]
D[7 Blueprints]
E[SQLAlchemy + SQLite]
F[Cache / Background tasks]
end
subgraph Players["Signage Players"]
G[Player 1]
H[Player N]
end
subgraph Proxy["Reverse Proxy"]
I[Caddy :80/:443]
J[Umbrella nginx gateway - optional SSO]
end
I -->|reverse_proxy digiserver-app:5000| C
J -.X-Auth-Username .-> C
D --> E
G <-->|"/api/*"| D
H <-->|"/api/*"| D
Browser --> I
C -.SSH deploy/rsync.-> G
C -.SSH deploy/rsync.-> H
```
---
## 2. Layered Architecture
Graphify assigns each node a **level** (0 = entry/global → 3 = utility):
| Layer | Level | Components |
|---|---|---|
| **L0 — Entry / Global** | 0 | `create_app()`, `app.py`, config classes, error handlers, CLI commands |
| **L1 — Strategic / Core** | 1 | Blueprint route handlers (players, content, api, admin), model classes |
| **L2 — Implementation** | 2 | Playlist/group management helpers, processing helpers, model methods |
| **L3 — Utility** | 3 | `logger.py`, `ssh_deploy.py`, `caddy_manager.py`, `uploads.py`, `pptx_converter.py`, migrations |
```mermaid
flowchart TD
subgraph L0["L0 · Entry"]
create_app["create_app()"]
ProxyFix
ScriptNameFix
portal_sso["init_portal_sso()"]
end
subgraph L1["L1 · Blueprints + Models"]
bp["main · auth · admin · players · content · playlist · api"]
models["User Player Content Playlist PlayerEdit PlayerFeedback PlayerUser HTTPSConfig ServerLog"]
end
subgraph L2["L2 · Implementation"]
bg["run_background_task()"]
dep["deploy_player_to_host()"]
caddy["CaddyConfigGenerator"]
pb["build_player_files() / write_base_config()"]
end
subgraph L3["L3 · Utility"]
log["log_action()"]
up["uploads.py"]
pptx["pptx_converter.py"]
nginx["NginxConfigReader"]
end
create_app --> bp
create_app --> models
bp --> log
bp --> bg
bp --> dep
bp --> caddy
bp --> pb
bp --> up
bp --> pptx
```
---
## 3. Component Map (files → communities)
Graphify clustered the code into **41 communities**. The 12 meaningful ones are shown below (communities 1340 are mostly migrations, isolated helper functions, and archived code).
| Community | Domain (derived) | Files | Role |
|---|---|---|---|
| **C0** (90) | **Authentication + legacy groups** | `blueprints/auth.py`, `blueprints/content_old.py`, `models/server_log.py`, `utils/logger.py`, `utils/group_player_management.py`, `old_code_documentation/blueprint_groups.py` | Auth flows + audit logging + (legacy) group features |
| **C1** (80) | **Admin + HTTPS + player users** | `blueprints/admin.py`, `models/https_config.py`, `models/player_user.py`, `utils/caddy_manager.py`, `migrations/add_player_user_table.py` | Admin panel, Caddy HTTPS generation, editing-user registry |
| **C2** (68) | **Playlist & content workflows** | `blueprints/content.py`, `blueprints/playlist.py`, `models/playlist.py` | Modern playlist-centric content management + legacy redirects |
| **C3** (62) | **Player API + edits** | `blueprints/api.py`, `models/player_edit.py` | Player-facing REST, edited-media pipeline |
| **C4** (55) | **Application core** | `app.py`, `config.py`, `models/user.py`, `utils/portal_sso.py`, `utils/script_name_fix.py` | App factory, config, auth identity, middleware |
| **C5** (54) | **Content & player models** | `models/content.py`, `models/player.py`, `models/player_feedback.py`, `blueprints/main.py` | Media model, player model, feedback, dashboard |
| **C6** (51) | **Player management UI** | `blueprints/players.py`, `migrations/add_https_config_table.py` | Player CRUD, manage page, deployment polling |
| **C7** (42) | **Groups (legacy)** | `models/group.py`, `utils/nginx_config_reader.py` | Archived groups feature + legacy nginx reader |
| **C8** (24) | **Dev tooling** | `old_code_documentation/test_edit_media_api.py`, `Colors`, integrity checker | Test/analysis utilities |
| **C9** (21) | **Upload processing** | `utils/uploads.py` | Upload progress, video/image processing |
| **C10** (20) | **Deployment** | `utils/background_tasks.py`, `utils/ssh_deploy.py` | Background SSH deployment engine |
| **C11** (19) | **Player build/staging** | `utils/player_build.py` | Stage player source code on server |
| **C12** (8) | **PPTX conversion** | `utils/pptx_converter.py` | LibreOffice PPTX → PDF → PNG |
```mermaid
flowchart TD
C0["C0 · Auth & logging"]
C1["C1 · Admin & HTTPS"]
C2["C2 · Playlists & content"]
C3["C3 · Player API & edits"]
C4["C4 · App core"]
C5["C5 · Content/player models"]
C6["C6 · Player management UI"]
C9["C9 · Upload processing"]
C10["C10 · Deployment"]
C11["C11 · Player build"]
C12["C12 · PPTX conversion"]
C1 -->|27 edges| C3
C2 -->|25 edges| C3
C2 -->|25 edges| C0
C3 -->|25 edges| C1
C1 -->|21 edges| C0
C6 -->|16 edges| C1
C6 -->|16 edges| C3
C3 -->|14 edges| C0
C6 -->|14 edges| C0
C5 -->|9 edges| C3
C9 -->|5 edges| C0
C1 -->|3 edges| C11
C10 --> C6
C11 --> C10
C12 --> C9
```
*(edge weights from `graphify-out/metadata.json` communityLinks)*
---
## 4. Middleware & Request Pipeline
Every request flows through three layers before reaching a blueprint:
```mermaid
flowchart LR
R["Raw request"] --> PF["werkzeug ProxyFix"]
PF --> SF["ScriptNameFix"]
SF --> SSO["portal_sso (before_request)"]
SSO --> BP["Blueprint route"]
BP --> DB[("SQLAlchemy / SQLite")]
```
1. **ProxyFix** — trusts `X-Forwarded-For/Proto/Host/Port` from Caddy/nginx (1 hop).
2. **ScriptNameFix** — reads `X-Script-Name` (e.g. `/digiserver`) so `url_for()` produces correct prefixed URLs behind an umbrella nginx gateway.
3. **Portal SSO** (`portal_sso.py`) — if the umbrella nginx sends `X-Auth-Username` / `X-Auth-Role`, automatically create + log in the local user.
---
## 5. Key Architectural Decisions
| Decision | Implementation |
|---|---|
| **Application factory** | `create_app(config_name)` — clean testability, per-env config |
| **Blueprint isolation** | 7 blueprints with clear URL prefixes; API separate from UI |
| **Playlist versioning** | `Playlist.version` incremented on every mutation → players poll `/api/playlist-version/<id>` for refresh |
| **In-memory caching** | Flask-Caching `@cache.memoize(300)` on playlist builders; `cache.clear()` on mutations |
| **DB-backed audit log** | `log_action()` writes `ServerLog` rows; surfaced on dashboard & admin |
| **Two auth systems** | Humans: Flask-Login (`User`). Players: `auth_code` Bearer + `quickconnect_code` (bcrypt) |
| **Remote provisioning** | SSH + rsync/git staged code → write `app_config.json` → run install/start scripts |
| **HTTPS automation** | `CaddyConfigGenerator` writes `Caddyfile`; reloads Caddy via admin API on `:2019` |
---
## 6. Runtime Dependencies (requirements.txt)
**Runtime:** Flask 3.1, Werkzeug 3.1, SQLAlchemy 2.0.37, Flask-SQLAlchemy 3.1.1, Flask-Migrate, Flask-Bcrypt, Flask-Login, Flask-Caching, Flask-Cors, Flask-Talisman, pdf2image, Pillow, ffmpeg-python, python-magic, bcrypt, cryptography, gunicorn 23, psutil, python-dotenv.
**System binaries (Docker):** `poppler-utils`, `ffmpeg`, `libmagic1`, `LibreOffice` (core/impress/writer), `fonts-noto-color-emoji`, `sshpass`, `openssh-client`, `rsync`, `git`.
**Dev:** black, flake8, pytest, pytest-cov. *(`gevent` is commented out — incompatible with Python 3.13.)*
---
> Next: [02 · Knowledge Graph](02-knowledge-graph.md)