# l4d2-web-app

Flask web app for managing L4D2 servers through user-private blueprints.

## Key v1 behaviors

- Local username/password login; no public signup
- Admin-managed overlay catalog
- Private blueprints per user
- Server creation from blueprints (live-linked; no per-server blueprint overrides)
- Async job model with persisted command logs in `job_logs`
- Desired vs actual state model
- Live logs for jobs and servers via SSE endpoints
- Host operations go through `l4d2ctl` via a local host command runner, not direct `l4d2host` imports

## Frontend constraints

- Server-rendered templates (Jinja)
- Vendored HTMX (`static/vendor/htmx.min.js`)
- Custom CSS only
- Tokenized, consistent link and accent colors

## Development

From the workspace root (`../`):

```bash
uv sync          # creates .venv, installs l4d2host + l4d2web editable, plus dev deps
uv run pytest l4d2web/tests -q
```

## Configuration

The web app reads these settings from the environment:

- `DATABASE_URL`: SQLAlchemy database URL, for example `sqlite:////var/lib/left4me/left4me.db`.
- `SECRET_KEY`: Flask secret key used for sessions and CSRF-sensitive state.
- `JOB_WORKER_THREADS`: number of background job worker threads.

In the systemd deployment, environment is loaded from `/etc/left4me/host.env` and `/etc/left4me/web.env`.

## Admin Bootstrap

Create the first admin account with the Flask CLI. Provide the password through `LEFT4ME_ADMIN_PASSWORD`:

```bash
LEFT4ME_ADMIN_PASSWORD='change-me' flask create-user <username> --admin
```
