# L4D2 Web UI Design

**Goal:** Replace the current minimal web UI with a functional, understated admin-console interface for technical end users who manage L4D2 servers, blueprints, overlays, jobs, and logs.

**Approval status:** User-approved design direction. Implementation must not start until the user explicitly approves moving from this spec to an implementation plan.

## Context

The existing web app is Flask with server-rendered Jinja templates, vendored HTMX, custom CSS, vanilla JavaScript, SQLite state, in-process jobs, and SSE log streams. The UI work must stay inside that architecture.

The current `l4d2web` code is a rough draft. Implementation may replace, remove, or reorganize existing web routes, templates, CSS, JavaScript, and tests when that better serves this spec. Preserve the approved architecture and product contracts, not draft implementation details.

The original web-app plan required a fixed link color of `#0F766E`. This spec supersedes that exact color requirement based on user feedback. Link and accent colors must still be consistent and tokenized, but they do not need to use `#0F766E`. The implementation plan should update older project docs that still describe the exact color as mandatory.

## Design Principles

- Build a plain functional admin console, not a visually themed game interface.
- Keep style minimal and comfortable for technical end users.
- Use color only when it communicates meaning or interaction.
- Use neutral backgrounds, surfaces, borders, and text for the basic layout.
- Use accent colors sparingly for links, primary actions, focus states, status, warnings, and errors.
- Avoid decorative gradients, decorative color blocks, colorful shadows, and unnecessary visual effects.
- Use one regular font stack for the app.
- Use monospace only where it improves readability, especially logs and command-like content.
- Keep the type scale small. Use larger text only for page titles and section headings.
- Prefer weight, spacing, and borders over many font sizes.
- Keep pages usable and understandable with standard HTML.
- Use HTMX only where partial updates clearly improve UX.
- Use SSE for live server-to-browser streams such as logs and job output.
- Do not introduce WebSockets for v1.

## Visual System

The UI should use CSS variables as the single source for visual consistency. Component CSS should reference tokens instead of hard-coding colors, spacing, borders, or radii.

The token set should include:

- Background colors, including page background, surface background, muted surface, and log surface.
- Text colors, including default, muted, inverted, and log text.
- Border and line colors.
- Interaction colors, including link, primary action, danger, warning, success, and focus.
- A spacing scale derived from a base value, using names like `--space-xs`, `--space-s`, `--space-m`, `--space-l`, `--space-xl`, and `--space-2xl`.
- Border radius values, used only where rounded corners help readability.
- Reusable line tokens such as `--line` for standard borders.

The default light theme should use a plain light gray page background, white surfaces, and subtle gray borders. The current radial teal background should be removed.

Dark mode should follow the user's system preference with `@media (prefers-color-scheme: dark)`. Dark mode should override variables only. Component CSS should not duplicate light and dark versions unless unavoidable.

Logs should stay dark monospace panels in both modes because that best matches terminal output and improves contrast for streaming logs.

## Navigation

The app shell should use a single horizontal header.

Left navigation:

```text
left4me | servers | blueprints | overlays
```

Right navigation:

```text
admin | user@email | logout
```

Navigation behavior:

- `left4me` links to `/dashboard`.
- `servers` links to `/servers`.
- `blueprints` links to `/blueprints`.
- `overlays` links to `/overlays`.
- `admin` appears only for admins and links to `/admin`.
- The current user identifier appears as text or as a future account link.
- Logout should use a small POST form styled like a nav link, not a GET link, so it remains compatible with CSRF rules.

## Routes And Page Structure

`/dashboard` should be a placeholder-only landing page for now. It should not show metrics, cards, or summaries yet. Example text: "Dashboard placeholder. Use the navigation to manage servers, blueprints, and overlays."

`/servers` should show a comfortable table of the current user's servers. The server name should link to `/servers/<id>`. The table should not have a separate "View" column. Useful columns include name, port, blueprint, desired state, actual state, active job, and real actions.

`/servers/<id>` should be action-oriented and log-focused. It should show lifecycle actions near the title, status metadata, linked blueprint information, current or recent job information, a job log panel, and a server log panel. It must not expose server-level overrides because servers remain live-linked to blueprints.

`/blueprints` should show the current user's private blueprints in a table. Blueprint names should link to `/blueprints/<id>`. Useful columns include name, overlay count, linked server count, and real actions.

`/blueprints/<id>` should show a normal detail/edit form. It should include blueprint name, ordered overlays, arguments, and config. Arguments and config should be multiline textareas. The page should explain that overlay order matters and that the first overlay has highest precedence.

`/overlays` should be the only overlay catalog page. All authenticated users can view overlays. Admins see create, edit, and delete controls on the same page. Non-admins do not see edit controls.

`/admin` should be a simple admin landing page with links to admin-only areas such as users and jobs. Overlay administration should not be duplicated here.

`/admin/users` should show a user table with username, admin flag, and account metadata. Usernames should link to a detail page only if a detail page exists.

`/admin/jobs` should show a job table with operation, state, server, user, timestamps, and log access. Job IDs or operations may link to job detail/log pages only if those pages exist.

## Table Rules

Tables should use normal comfortable spacing and clear empty states.

If an entity has a detail page, the entity name should be the link to that page. Do not add a separate row action just for viewing details.

The final table column should be reserved for real actions such as start, stop, edit, delete, promote, demote, or reassign.

## Forms And Progressive Enhancement

Use standard HTML forms by default. Full-page POST and redirect behavior is acceptable for create, update, delete, and lifecycle actions.

Use HTMX only where it improves UX without adding architectural complexity. Good candidates include status fragments, row refreshes after lifecycle actions, small validation feedback, and log/status panels that benefit from partial replacement.

Keep JavaScript unobtrusive when it is needed. Do not put inline JavaScript in templates. Static JavaScript files should enhance regular HTML with `data-*` attributes and normal form fields.

## Blueprint Editing

Blueprint editing can stay form-based for v1.

The blueprint page should include:

- A name field.
- A selected overlays section that displays overlays in saved order.
- Form controls to add, remove, and reorder overlays.
- Multiline `arguments` textarea, interpreted as one argument or argument group per non-empty line.
- Multiline `config` textarea, interpreted as one server config line per non-empty line.
- A primary save action for normal blueprint edits.

Overlay ordering may use full-page form submissions for v1. A simple table with one row per overlay, a checkbox to include it, and a numeric order field is acceptable. Dedicated add, remove, move-up, and move-down submit buttons are also acceptable if they preserve the current name, arguments, config, and ordered overlay IDs so users do not lose in-progress edits.

Saved overlay IDs must remain ordered. If hidden fields are used, repeated `overlay_ids` inputs should appear in the intended order so Flask can read them with `request.form.getlist("overlay_ids")`. If numeric order fields are used, the server should sort selected overlay IDs by those fields before persisting `BlueprintOverlay.position`.

## Server Detail Page

The server detail page should prioritize operations and diagnostics.

Recommended section order:

- Title and lifecycle action buttons.
- Status metadata including name, port, blueprint, desired state, actual state, display state, and last error.
- Linked blueprint summary including overlay order, arguments, and config.
- Current or recent job summary.
- Job log panel.
- Server log panel.

Lifecycle actions should use standard POST forms. Destructive delete should require confirmation. If a job is active, conflicting actions should be disabled or clearly blocked.

Job logs and server logs should stream with SSE. Status may use HTMX polling, SSE, or normal refresh depending on the smallest reliable implementation for the page.

## Access Rules

Authenticated users can access dashboard, servers, blueprints, and overlays.

Blueprints remain private per user.

Servers remain private per user.

Overlays are visible to all authenticated users.

Only admins can create, edit, or delete overlays.

Only admins can access `/admin`, `/admin/users`, and `/admin/jobs`.

Non-admin direct access to admin pages should return forbidden.

## Out Of Scope

- External frontend frameworks or new frontend dependencies.
- WebSockets.
- Manual dark-mode toggle.
- Game-themed visual design.
- Dashboard metrics or summary widgets.
- Client-side overlay drag-and-drop ordering for v1.
- Server-level blueprint overrides.
- Duplicated overlay administration under `/admin/overlays`.

## Implementation Boundaries

This design is intentionally UI-focused. It does not change the host library contract, job execution model, blueprint privacy model, or desired-vs-actual server state model.

Existing draft web code is not a compatibility boundary. When existing draft code conflicts with this spec, prefer changing the code and tests to this spec over preserving old placeholder behavior.

Before implementation starts, create a separate implementation plan and get explicit user approval.
