Files
Fossign/README.md

237 lines
5.7 KiB
Markdown
Raw 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.
# Flask Digital Signage (simple)
Lightweight digital signage platform using **Flask + SQLite**.
## Features
- Central **admin** can manage companies, users, displays.
- Admin can **impersonate** any company user (no password).
- Company users can:
- Create playlists
- Add slides (image/video/webpage)
- Assign playlists to displays
- Displays are public **16:9 player webpages** suitable for kiosk browsers.
## Quickstart (Windows)
```bat
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
set FLASK_APP=app
flask init-db --admin-email beheer@alphen.cloud --admin-pass admin
flask run --debug
```
If Flask can't discover the app automatically, use:
```bat
set FLASK_APP=app:create_app
flask run --debug
```
Open http://127.0.0.1:5000
## Production (WSGI)
This repo includes a `wsgi.py` entrypoint for production WSGI servers.
### Important (Windows)
If you try to run Gunicorn directly on Windows you will see an error like:
```
ModuleNotFoundError: No module named 'fcntl'
```
Thats expected: **Gunicorn is Unix-only**. On Windows, run the app via:
- **Docker** (recommended) so Gunicorn runs inside a Linux container, or
- **WSL2/Linux** (Gunicorn works), or
- use a Windows-native WSGI server (e.g. Waitress) instead of Gunicorn.
Examples:
```bash
# gunicorn (Linux)
gunicorn -w 4 -b 0.0.0.0:8000 wsgi:app
# uWSGI
uwsgi --http :8000 --wsgi-file wsgi.py --callable app
```
Note: unlike `flask run`, WSGI servers typically don't auto-load `.env` / `.flaskenv`.
`wsgi.py` attempts to load `.env` (best-effort), but for real production you should set
environment variables via your process manager / secrets.
## Docker
### Docker Compose (recommended)
This repo includes a `docker-compose.yml` for a one-command startup.
On first run, the container will ensure the SQLite schema exists.
If you provide `ADMIN_PASS`, it will also create/update the initial admin user.
```powershell
docker compose up --build
```
Create an admin on startup (recommended):
```powershell
$env:ADMIN_EMAIL="you@example.com"
$env:ADMIN_PASS="YourStrongPassword"
docker compose up --build
```
Or put these in a `.env` file used by Compose.
Run in the background:
```powershell
docker compose up -d --build
```
Stop:
```powershell
docker compose down
```
Data persistence:
- SQLite DB is mounted to `./instance` on your host
- uploads are mounted to `./app/static/uploads` on your host
Build:
```bash
docker build -t signage:latest .
```
Run (with persistent SQLite DB + uploads):
```bash
docker run --rm -p 8000:8000 \
-e SECRET_KEY="change-me" \
-v %cd%/instance:/app/instance \
-v %cd%/app/static/uploads:/app/app/static/uploads \
signage:latest
```
PowerShell variant (sometimes volume path quoting is easier):
```powershell
docker run --rm -p 8000:8000 `
-e SECRET_KEY="change-me" `
-v "${PWD}/instance:/app/instance" `
-v "${PWD}/app/static/uploads:/app/app/static/uploads" `
signage:latest
```
Then open: http://127.0.0.1:8000
Notes:
- The container starts with Gunicorn using `wsgi:app`.
- You can override Gunicorn settings via env vars:
- `GUNICORN_WORKERS` (default: 2)
- `GUNICORN_BIND` (default: `0.0.0.0:8000`)
## Notes
- SQLite DB is stored at `instance/signage.sqlite`.
- Uploaded files go to `app/static/uploads/`.
## Display player
Open:
- `http://<host>/display/<token>` for live playback (counts towards the concurrent display limit)
- `http://<host>/display/<token>?preview=1` for preview (does not count towards the concurrent display limit)
### Live updates
The player keeps itself up-to-date automatically:
- It listens to `GET /api/display/<token>/events` (Server-Sent Events) and reloads the playlist immediately when it changes.
- It also does a fallback playlist refresh every 5 minutes for networks/proxies that block SSE.
## SMTP / Forgot password
This project includes a simple **forgot password** flow. SMTP configuration is read from environment variables.
You can also configure SMTP settings from the UI: **Admin → Settings**.
Environment variables still take precedence over the database settings.
### Public domain for emails
If your app runs behind a reverse proxy (or the internal hostname differs from the public hostname),
set **Admin → Settings → Public domain** to e.g. `signage.example.com` so links in password reset
emails point to the correct address.
Recommended: put these in a local `.env` file in the repo root. Flask (via `python-dotenv`) will auto-load it on startup. `.env` is already gitignored.
You can start from `.env.example`:
```bat
copy .env.example .env
```
### Example
```bat
REM Option A: set env vars in the same terminal where you run `flask run`
set SMTP_HOST=smtp.strato.de
set SMTP_PORT=587
set SMTP_USERNAME=beheer@alphen.cloud
set SMTP_PASSWORD=***
set SMTP_FROM=beheer@alphen.cloud
set SMTP_STARTTLS=1
set SMTP_DEBUG=1
REM Option B: put the same keys/values in a .env file instead
```
Security note: do **not** commit SMTP passwords to the repo. Prefer secrets management and rotate leaked credentials.
Note on the "From" address: some SMTP providers enforce that the authenticated mailbox
(`SMTP_USERNAME`) is used as the actual sender (envelope-from), even if a different
`SMTP_FROM` is provided. In that case the app sets a `Reply-To` header so replies still
go to `SMTP_FROM`, but the provider may still show the username address as the sender.
### Troubleshooting mail delivery
If the reset email is not received:
1. Set `SMTP_DEBUG=1` and request a reset again.
2. Watch the Flask console output for SMTP responses / errors.
3. Verify:
- `SMTP_USERNAME` and `SMTP_FROM` are allowed by your provider.
- You are using STARTTLS (port 587).
- The recipient mailbox isnt filtering it (spam/quarantine).