75 lines
5.1 KiB
Markdown
75 lines
5.1 KiB
Markdown
# CANCOM Simple Signage — Agent Guide
|
||
|
||
## Start
|
||
|
||
```bash
|
||
pip install -r requirements.txt
|
||
python app.py
|
||
docker compose up -d
|
||
```
|
||
|
||
`python app.py` (via `.venv/bin/python app.py`) serves on `http://localhost:5005`. `app.py` runs Flask with `debug=True`, `host="0.0.0.0"`, and `port=5005`.
|
||
|
||
## Source Of Truth
|
||
|
||
- Single Flask app in `app.py`; there is no database.
|
||
- Persistent state is `config.json` plus files under `media/<site>/<screen>/`.
|
||
- Port 5005; `README.md` hat den korrekten Port.
|
||
- Existing repo instructions in this file are the main local guidance; there is no `opencode.json` or workflow config in this repo.
|
||
|
||
## Multi-Standort-URL-Struktur (seit v4.2.0)
|
||
|
||
Standorte (sites) sind die oberste Organisationsebene und gruppieren Screens.
|
||
|
||
| Route | Beschreibung |
|
||
|-------|-------------|
|
||
| `GET /player/<site>/<screen>` | Player für Screen an einem Standort |
|
||
| `GET /admin` | Redirect zum ersten Standort |
|
||
| `GET /admin/<site>` | Admin-Dashboard für einen Standort |
|
||
| `GET /admin/<site>/priority` | Priority-Playlist als separate Seite |
|
||
| `GET /media/<site>/<screen>/<file>` | Medien-Datei ausliefern |
|
||
| `GET /media/priority/<file>` | Priority-Medien (global) |
|
||
| `GET /playlist/<site>/<screen>/hash` | Playlist-Checksumme für Auto-Reload |
|
||
| `GET /willkommen?site=<site>` | Willkommensseite für Standort generieren |
|
||
| `POST /api/customer` | API-Endpunkt (JSON mit "site"-Feld) |
|
||
| `GET /admin/<site>/add-screen?name=<name>` | Neuen Screen anlegen |
|
||
| `POST /admin/<site>/delete-screen/<screen>` | Screen + Medien löschen |
|
||
| `GET /add-site?name=<name>` | Neuen Standort anlegen |
|
||
| `POST /admin/<site>/delete-site` | Standort + alle Screens/Medien löschen |
|
||
|
||
## Behavior To Preserve
|
||
|
||
- `GET /player/<site>/<screen>` renders the playlist and auto-reloads from `/playlist/<site>/<screen>/hash`.
|
||
- `GET /admin` requires login; `config.json.admin` holds the credentials.
|
||
- URL playlist items are stored as dicts like `{"url": "https://...", "zoom": 0.8}` and the zoom value must survive save/reorder flows.
|
||
- `.html` items in `media/` are rendered inline as content, not in an iframe.
|
||
- `config.priority.enabled` makes the priority playlist show on every screen.
|
||
- `POST /api/customer` generates `welcome.html` and inserts it at the front of the lobby playlist for the specified site.
|
||
- New standorte can be added by creating `media/<neuer-standort>/<screen>/` directories and optionally adding config to `config.json["sites"][<neuer-standort>]`.
|
||
- Priority playlist (`config.priority`) is global and affects all sites/screens.
|
||
- Willkommensseite (`customer.html`) accepts up to 3 customer names; logos are fetched via OpenAI→Brandfetch and displayed in a flex row.
|
||
- `generate_welcome_html(customer_names, logo_urls)` takes lists for up to 3 customers; logos have equal width (280px) with `max-height: 180px`.
|
||
- `customer_names` are preserved in form fields after POST (via `value`-Attribute).
|
||
- Admin-UI nutzt keyadmin-Design: `brand-surface` (#2b2f36), `nav-surface` (rot #DA002D), Dark Mode per `localStorage("signage-theme")`.
|
||
- Gemeinsame HTML-Bausteine: `_header.html`, `_footer.html`, `_styles.html` (CSS-Variablen `--ccm-*`, Dark Mode, Card-Border-Radius 1rem).
|
||
- `add_customer_to_lobby_playlist` entfernt `welcome.html` sowohl als String als auch als Dict aus der Playlist vor dem Einfügen.
|
||
- `add_screen` legt ein Verzeichnis unter `media/<site>/<screen>/` an und einen Config-Eintrag.
|
||
- `delete_screen` entfernt den Screen aus der Config und löscht das Verzeichnis rekursiv.
|
||
- Custom-URL-Button: pro Screen konfigurierbar (`custom_url` + `custom_url_label` + `custom_url_enabled` + `custom_url_target`) im Admin-Formular; wird im Player als Button oben links angezeigt und öffnet die URL wahlweise in einem iframe-Overlay mit Zurück-Button (`overlay`) oder per Direkt-Weiterleitung (`redirect`); Player pausiert während das Overlay geöffnet ist.
|
||
- Neue Standorte können über den `+`-Button im Header oder über `GET /add-site?name=<name>` angelegt werden.
|
||
- `delete_site` entfernt den Standort aus Config und löscht das Medienverzeichnis rekursiv.
|
||
- `config.json["server_url"]` (z. B. `http://signage.ccmake.de`) wird in der Admin-Ansicht für die Player-URLs verwendet.
|
||
- Screen-Card-Body hat Tabler-Tabs: **Playlist** (1, aktiv), **Einstellungen** (2), **Medien** (3); Priority-Seite ebenfalls Tabs **Playlist** und **Medien**.
|
||
- Tab-Reihenfolge in Screen-Cards: Playlist → Einstellungen → Medien.
|
||
- Player-URL im Screen-Header ist ein klickbarer Link in grauer Farbe.
|
||
|
||
## Repo Quirks
|
||
|
||
- `media/` and media file extensions are gitignored.
|
||
- The app has no configured tests, lint, typecheck, formatter, or CI.
|
||
- Hardcoded secrets exist in tracked files; do not commit new secrets or reshuffle them casually.
|
||
- Wichtige Helper-Funktionen in `app.py`: `load_config()`, `save_config()`, `get_site_list()`, `get_screen_config()`, `is_url()`, `normalize_url()`, `playlist_item_name()`, `playlist_item_enabled()`, `load_priority_files()`, `prio_redirect()`.
|
||
- `welcome.html` wird in `media/<site>/lobby/` gespeichert.
|
||
- `search_customer_logo` in `generate_welcome_page.py` nutzt OpenAI GPT-4 + Brandfetch CDN.
|
||
- `admin_priority` rendert `priority.html` mit `site_list`, `current_site`, `priority_files`, `server_url`.
|