Files
digiserver-v2/docs/04-application-core.md
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

180 lines
5.9 KiB
Markdown

# 04 · Application Core
Covers the application factory, configuration, extensions, middleware, CLI commands, context processors, and template layer. This is **Community 4** in the Graphify knowledge graph.
---
## 1. Application Factory — `app/app.py`
The entire app is constructed by `create_app(config_name=None)`:
```mermaid
flowchart TD
A["create_app()"] --> B["Set instance_path"]
B --> C["Load config: Dev / Prod / Test"]
C --> D["ProxyFix middleware"]
D --> E["ScriptNameFix middleware"]
E --> F["init extensions: db bcrypt login migrate cache cors"]
F --> G["configure_login_manager()"]
G --> H["register_blueprints()"]
H --> I["register_error_handlers()"]
I --> J["register_commands()"]
J --> K["register_context_processors()"]
K --> L["register_template_filters()"]
L --> M["init_portal_sso(app)"]
M --> N["db.create_all() (idempotent)"]
N --> O["return app"]
```
### Blueprint registration
```python
def register_blueprints(app):
from app.blueprints.main import main_bp
from app.blueprints.auth import auth_bp
from app.blueprints.admin import admin_bp
from app.blueprints.players import players_bp
from app.blueprints.content import content_bp
from app.blueprints.playlist import playlist_bp
from app.blueprints.api import api_bp
...
```
> Note: `content_old.py` (legacy content routes) was **deleted** during the code
> sanitization pass — see [SANITIZATION-REVIEW.md](SANITIZATION-REVIEW.md). The
> legacy `playlist.py` blueprint remains (redirect-only).
---
## 2. Configuration — `app/config.py`
Four classes: `Config` (base) → `DevelopmentConfig`, `ProductionConfig`, `TestingConfig`.
| Setting | Value | Notes |
|---|---|---|
| `MAX_CONTENT_LENGTH` | 2 GB | upload cap |
| `UPLOAD_FOLDER` | `app/static/uploads` | media |
| `UPLOAD_FOLDERLOGO` | `app/static/resurse` | logos |
| `ALLOWED_EXTENSIONS` | png jpg jpeg gif bmp mp4 avi mkv mov webm pdf ppt pptx | |
| `PERMANENT_SESSION_LIFETIME` | 30 min | |
| `SESSION_COOKIE_SECURE` | False (True in prod) | |
| `ITEMS_PER_PAGE` | 20 | |
| `SERVER_VERSION` | 2.0.0 | shown in UI footer |
| `PLAYER_CODE_DIR` | `/app/data/player` | staged player source |
| `PLAYER_REPO_URL` | env `PLAYER_REPO_URL` | Kiwy-Signage repo |
| DB (dev) | `instance/dev.db` | |
| DB (prod) | `instance/dashboard.db` | |
| DB (test) | in-memory | |
---
## 3. Extensions — `app/extensions.py`
Centralizes shared singletons:
```python
db = SQLAlchemy()
bcrypt = Bcrypt()
login_manager = LoginManager() # login_view='auth.login'
migrate = Migrate()
cache = Cache()
cors = CORS()
```
CORS is configured in `create_app` for `/api/*`: all origins, GET/POST/OPTIONS/PUT/DELETE, supports credentials.
---
## 4. Middleware
### ProxyFix (Werkzeug)
`app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_port=1)` — trusts one reverse-proxy hop (Caddy / umbrella nginx).
### ScriptNameFix — `app/utils/script_name_fix.py`
`ScriptNameFix` WSGI middleware sets `SCRIPT_NAME` from `HTTP_X_SCRIPT_NAME` so `url_for()` generates correct paths when the app is mounted under a sub-path (e.g. `/digiserver`).
---
## 5. Login Manager
```python
login_manager.login_view = 'auth.login'
login_manager.login_message = 'Please log in to access this page.'
@login_manager.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
```
---
## 6. Error Handlers
| Code | Template | Behaviour |
|---|---|---|
| 404 | `errors/404.html` | Not found |
| 403 | `errors/403.html` | Forbidden |
| 500 | `errors/500.html` | Rolls back DB session |
| 413 | `errors/413.html` | Payload too large |
| 408 | `errors/408.html` | Request timeout |
The `/api` blueprint registers its own **JSON** 404/405/500 handlers.
---
## 7. CLI Commands
| Command | Purpose |
|---|---|
| `flask init-db` | `db.create_all()` |
| `flask create-admin --username X` | Create admin user (prompts for password) |
| `flask seed-db` | Seed sample data (blocked in production) |
---
## 8. Context Processors
- **`inject_config`** — exposes `server_version`, `build_date`, `logo_exists` to all templates.
- **`inject_user_theme`** — exposes the authenticated user's `theme` (`light`/`dark`) for the UI toggle.
---
## 9. Template Filters
- **`localtime`** — converts naive/UTC datetimes to local time with a configurable `strftime` format (default `%Y-%m-%d %H:%M`).
---
## 10. Template & Static Layout
```
app/templates/
├── base.html ← main layout (theme, logos, nav)
├── dashboard.html
├── auth/ login.html, register.html, change_password.html
├── admin/ admin.html, user_management.html, leftover_media.html,
│ dependencies.html, customize_logos.html, editing_users.html,
│ https_config.html, build_player.html
├── content/ content_list_new.html, media_library.html,
│ upload_media.html, manage_playlist_content.html
├── players/ players_list.html, add_player.html, edit_player.html,
│ manage_player.html, player_page.html, player_fullscreen.html,
│ edited_media.html, edited_media_report.html, _deploy_badge.html
└── errors/ 403.html, 404.html, 500.html (+413/408)
app/static/
├── icons/ edit, home, info, monitor, moon, playlist, sun, trash, upload, warning (SVG)
├── uploads/ uploaded media + edited_media/<content_id>/ (versioned edits)
└── (resurse/ logo storage — referenced by config)
```
---
## 11. Portal SSO — `app/utils/portal_sso.py`
`init_portal_sso(app)` registers a `before_request` hook that reads `X-Auth-Username` / `X-Auth-Role` headers (set by the umbrella nginx gateway). If present, it auto-creates and logs in the local `User` (`_get_or_create_user`). This lets the app sit behind an existing corporate SSO portal.
---
> Next: [05 · Blueprints & API](05-blueprints-api.md)