Architecture

Technology stack

The GUI is built on top of three libraries:

  • Flask — WSGI web framework, handles routing, sessions, and template rendering.

  • Jinja2 — templating engine (included with Flask); templates live in gui/templates/.

  • HTMX — JavaScript library loaded from CDN; drives partial page updates and SSE subscriptions without writing custom fetch/XHR code.

All application logic lives in gui/app.py. No core files are modified.

Server-Sent Events (SSE)

Two independent SSE streams deliver real-time data to the browser.

Runner stream

When fwtester.py completes each test, it commits the result to the SQLite database (fwtester-sqlite3.db, table tests_results). The endpoint /runner/db-stream polls the database for new rows and emits each one as an HTML fragment (a <tr> element). HTMX appends each fragment to the results table body using hx-swap="beforeend".

A second endpoint, /runner/stream, tails outputs/logs/fwtester.log and forwards each line as an SSE message. This is used by the log viewer modal inside the Runner page.

Hot-test stream

/hot-test/stream reads the standard output of the run_hot_test.py subprocess line by line and forwards each line as an SSE message. When the subprocess exits, the generator emits an event: close message so the browser-side EventSource can call src.close() and stop reconnecting.

Key files

File

Purpose

gui/app.py

Flask application: all routes, SSE generators, helper functions.

gui/run_hot_test.py

HotTestRunner subclass of FwTester; single-test runner used by hot-test.

gui/i18n.py

Translation dictionary and t(key, locale) helper.

gui/auth.py

User authentication: SQLite storage, PBKDF2-SHA256 hashing, session management.

gui/install-gui-service.sh

Portable systemd service installer.

gui/uninstall-gui-service.sh

Removes the systemd service.

gui/templates/

Jinja2 templates: one per page plus HTMX partials (_*.html).

gui/static/style.css

Application stylesheet (no external CSS framework).

requirements-gui.txt

GUI-specific Python dependencies (Flask).

HotTestRunner

HotTestRunner (gui/run_hot_test.py) is a subclass of FwTester with three overrides:

  • __init__ — skips loading tests.csv; sets self._tests to a single constructed CSV rule string built from the CLI arguments.

  • _resume() — always returns -1 so the single test is never skipped by the resume logic.

  • generate_report() — no-op; hot-test results are not written to the report CSV.

It uses fwtester_hot-sqlite3.db as its database to avoid interfering with the main runner’s resume state. fwnics.csv and routes.csv must still be present.

Internationalisation (i18n)

All user-visible strings are looked up through the t(key, locale) function defined in gui/i18n.py. The function resolves:

  1. The string for the requested locale.

  2. Falls back to the English (en) string if the key is missing for that locale.

  3. Falls back to the key name itself if the key is not found in any locale.

The active locale is stored in the Flask session and changed via GET /set-lang?lang=<code>. Supported codes: en, es, ca.

Note

Because the server runs with debug=False, Python modules are loaded once at startup and are not reloaded between requests. Changes to gui/i18n.py require a service restart to take effect.

Authentication

gui/auth.py manages user accounts in the users table of fwtester-sqlite3.db. Passwords are stored as PBKDF2-SHA256 hashes using Python’s hashlib.pbkdf2_hmac. Sessions are handled by Flask’s built-in signed cookie mechanism.

The users table coexists with the tests_results table in the same database file. The “Clear results” operation issues a DELETE FROM tests_results statement and does not touch the users table.