Files
ske087 46602f1933 Sanitize codebase, reorganize docs, and add missing deploy files
Remove dead code identified in docs/SANITIZATION-REVIEW.md:
- app/blueprints/content_old.py and app/blueprints/playlist.py
- app/models/group.py, app/utils/nginx_config_reader.py
- orphaned templates (content_list, edit_content, upload_content,
  player_page) and the related group/Template references

Result: 6 blueprints, 82 routes, no dead modules or orphan templates.

Add files that deploy.sh and docker-entrypoint.sh already require but
which were never tracked:
- https_manager.py       (referenced by deploy.sh, migrate_network.sh,
                          docker-entrypoint.sh)
- Caddyfile.example      (seeded by deploy.sh; its absence aborts deploy)

Relocate generated Graphify artifacts from graphify-out/ to
docs/graphify-out/ (110 files, no content change) and archive the
superseded docs under docs/.

Ignore hygiene:
- ignore ad-hoc .env backups (.env.bak*) — they contain live secrets
- keep the pre-sanitization snapshots (docs/legacy code/,
  docs/old_code_documentation/) on disk but out of the repo

Fix .env.example: drop a duplicated config block, genericize the
hardcoded host IP, and document HOSTNAME_INTERNAL.
2026-09-11 12:18:34 +03:00

198 lines
8.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 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"]
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 + audit** | `blueprints/auth.py`, `models/server_log.py`, `utils/logger.py`, `old_code_documentation/blueprint_groups.py` | Auth flows + audit logging |
| **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) | ***(removed)*** | — | Groups model + legacy nginx reader were deleted during sanitization |
| **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)