Files
BanGUI/Docs/Tasks.md
Lukas 848531c134 docs: update tasks from E2E test run; add proxy server
- Docs/Tasks.md: document 122 E2E test failures (fail2ban missing)
- e2e/proxy_server.py: add HTTP proxy for frontend dev server
- e2e/resources/common.resource: update test resource
2026-06-21 11:21:20 +02:00

2283 lines
69 KiB
Markdown

# E2E Test Failure Tasks
> Generated from Robot Framework test run on 2026-06-21.
> **Overall Result:** 123 tests, 0 passed, 122 failed, 1 skipped.
> **Root Cause:** Backend health check returns HTTP 503 because fail2ban is not installed/running (`ModuleNotFoundError: No module named 'fail2ban'`). All suites fail at `Suite Setup` → `Wait For Backend Health`.
---
## Task: Fix E2E Suite Setup — Backend Health Check
**Problem:** Every test suite fails during `Suite Setup` because `Wait For Backend Health` in `e2e/resources/common.resource` polls `GET /api/v1/health` and expects HTTP 200. The backend returns HTTP 503 with body `{"status":"unavailable","fail2ban":"offline","database":"ok","scheduler":"running","cache":"initialised"}`.
**Step That Fails:** `Suite Setup``Wait For Backend Health` keyword (line 24 in `common.resource`).
**Files to Check:**
- `e2e/resources/common.resource``Wait For Backend Health` keyword
- `backend/app/routers/health.py` — health endpoint logic
- `backend/app/utils/fail2ban_client.py` — fail2ban module import
- `Docker/compose.debug.yml` — how fail2ban is wired in the Docker stack
**Reference Docs:**
- `e2e/Instructions.md` — "Requires: stack up (make up)"
- `Docs/Deployment.md` — fail2ban dependency setup
- `Makefile``make e2e` target
**Expected Behavior:** Either:
1. The health check accepts 503 as "backend is up but degraded" and proceeds with tests, OR
2. fail2ban is installed and running so health returns 200.
---
## Task: 01 Setup And Auth — Setup Page Renders All Form Fields
**Test:** `Setup Page Renders All Form Fields`
**Suite:** `01_setup_and_auth.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`) — backend never becomes healthy within 120s timeout.
**Files to Check:**
- `e2e/tests/01_setup_and_auth.robot`
- `e2e/resources/common.resource`
- `frontend/src/pages/SetupPage.tsx` (or equivalent setup page component)
**Reference Docs:**
- `e2e/Instructions.md` — Setup wizard feature coverage
- `Docs/Features.md` — Setup wizard form fields, password strength, validation
**Expected Behavior:** Setup page loads with all required form fields visible (Master Password, Confirm Password, Database Path, fail2ban Socket Path, Timezone, Session Duration, Submit button).
---
## Task: 01 Setup And Auth — Password Strength Indicator Updates On Input
**Test:** `Password Strength Indicator Updates On Input`
**Suite:** `01_setup_and_auth.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/01_setup_and_auth.robot`
- `frontend/src/components/PasswordStrengthIndicator.tsx` (or equivalent)
**Reference Docs:**
- `Docs/Features.md` — Password strength indicator behavior
**Expected Behavior:** Four-segment strength bar updates dynamically as user types password. Weak password shows 1 segment, strong password shows 4 segments.
---
## Task: 01 Setup And Auth — Password Mismatch Shows Validation Error
**Test:** `Password Mismatch Shows Validation Error`
**Suite:** `01_setup_and_auth.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/01_setup_and_auth.robot`
- `frontend/src/pages/SetupPage.tsx`
**Reference Docs:**
- `Docs/Features.md` — Setup form validation
**Expected Behavior:** Submitting with non-matching passwords surfaces an error on the Confirm Password field.
---
## Task: 01 Setup And Auth — Empty Required Fields Show Validation Errors
**Test:** `Empty Required Fields Show Validation Errors`
**Suite:** `01_setup_and_auth.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/01_setup_and_auth.robot`
- `frontend/src/pages/SetupPage.tsx`
**Reference Docs:**
- `Docs/Features.md` — Required field validation
**Expected Behavior:** Submitting with blank required fields shows field-level error messages for each empty required input.
---
## Task: 01 Setup And Auth — Invalid Session Duration Shows Validation Error
**Test:** `Invalid Session Duration Shows Validation Error`
**Suite:** `01_setup_and_auth.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/01_setup_and_auth.robot`
- `frontend/src/pages/SetupPage.tsx`
- `backend/app/models/request.py` — session duration validation
**Reference Docs:**
- `Docs/Features.md` — Session duration validation rules
**Expected Behavior:** Submitting with an invalid session duration (e.g., negative, zero, or non-numeric) shows a validation error.
---
## Task: 01 Setup And Auth — Incomplete Password Shows Complexity Error
**Test:** `Incomplete Password Shows Complexity Error`
**Suite:** `01_setup_and_auth.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/01_setup_and_auth.robot`
- `frontend/src/pages/SetupPage.tsx`
- `frontend/src/utils/passwordValidation.ts` (or equivalent)
**Reference Docs:**
- `Docs/Features.md` — Password complexity requirements
**Expected Behavior:** Submitting a password that does not meet complexity rules (length, special chars, etc.) shows a complexity error message.
---
## Task: 01 Setup And Auth — Setup Completes Successfully And Redirects To Login
**Test:** `Setup Completes Successfully And Redirects To Login`
**Suite:** `01_setup_and_auth.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/01_setup_and_auth.robot`
- `frontend/src/pages/SetupPage.tsx`
- `backend/app/routers/setup.py` — setup completion endpoint
- `backend/app/services/setup_service.py`
**Reference Docs:**
- `Docs/Features.md` — Setup completion flow
- `e2e/Instructions.md` — Setup wizard full submit
**Expected Behavior:** Filling all required fields with valid data and submitting completes setup, creates the admin user, initializes the database, and redirects to `/login`.
---
## Task: 02 Ban Records — Simulated Failed Logins Appear As Ban Records
**Test:** `Simulated Failed Logins Appear As Ban Records`
**Suite:** `02_ban_records.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Specific Error:** `'' does not contain '192.168.100.99'` (from earlier partial run before backend was fully down).
**Files to Check:**
- `e2e/tests/02_ban_records.robot`
- `backend/app/routers/bans.py` — ban records endpoint
- `backend/app/services/ban_service.py`
- `Docker/simulate_failed_logins.sh` — simulation script
**Reference Docs:**
- `e2e/Instructions.md` — "end-to-end ban pipeline: fail2ban log → history"
- `Docs/Features.md` — Ban pipeline flow
**Expected Behavior:** Simulating failed SSH logins triggers fail2ban to ban the IP, and the banned IP appears in the dashboard/history within a reasonable time.
---
## Task: 02 Login — Login Page Renders Password Input
**Test:** `Login Page Renders Password Input`
**Suite:** `02_login.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/02_login.robot`
- `frontend/src/pages/LoginPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — Login page feature coverage
- `Docs/Features.md` — Login page UI
**Expected Behavior:** Login page shows a single password input field (no username field) and a submit button.
---
## Task: 02 Login — Login Page Has No Username Field
**Test:** `Login Page Has No Username Field`
**Suite:** `02_login.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/02_login.robot`
- `frontend/src/pages/LoginPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "Login page must NOT ask for a username"
**Expected Behavior:** The login page does NOT contain a username/email input field. Only password is required.
---
## Task: 02 Login — Login With Wrong Password Shows Error
**Test:** `Login With Wrong Password Shows Error`
**Suite:** `02_login.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/02_login.robot`
- `frontend/src/pages/LoginPage.tsx`
- `backend/app/routers/auth.py` — login endpoint
- `backend/app/services/auth_service.py`
**Reference Docs:**
- `e2e/Instructions.md` — "wrong password" test case
**Expected Behavior:** Submitting an incorrect password displays an error message (e.g., "Invalid credentials") without revealing whether the user exists.
---
## Task: 02 Login — Login Rate Limits After Multiple Failures
**Test:** `Login Rate Limits After Multiple Failures`
**Suite:** `02_login.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/02_login.robot`
- `backend/app/routers/auth.py` — rate limiting
- `backend/app/middleware/rate_limit.py` (or equivalent)
**Reference Docs:**
- `e2e/Instructions.md` — "Per-IP rate limit trial"
- `Docs/Security.md` — Rate limiting rules
**Expected Behavior:** After 5 failed login attempts from the same IP within 60 seconds, subsequent attempts receive HTTP 429 Too Many Requests.
---
## Task: 02 Login — Session Endpoint Returns 401 Without Cookie
**Test:** `Session Endpoint Returns 401 Without Cookie`
**Suite:** `02_login.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/02_login.robot`
- `backend/app/routers/auth.py` — session validation endpoint
- `backend/app/middleware/session.py` (or equivalent)
**Reference Docs:**
- `e2e/Instructions.md` — "session validation 401"
**Expected Behavior:** Calling `GET /api/v1/auth/session` without a valid session cookie returns HTTP 401 Unauthorized.
---
## Task: 02 Login — Direct Access To Protected Route Redirects To Login
**Test:** `Direct Access To Protected Route Redirects To Login`
**Suite:** `02_login.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/02_login.robot`
- `frontend/src/App.tsx` — route guards
- `frontend/src/components/ProtectedRoute.tsx` (or equivalent)
**Reference Docs:**
- `Docs/Features.md` — Route protection
**Expected Behavior:** Navigating directly to a protected route (e.g., `/dashboard`) without being logged in redirects to `/login`.
---
## Task: 02 Login — Session Validation 401 On Mount Redirects To Login
**Test:** `Session Validation 401 On Mount Redirects To Login`
**Suite:** `02_login.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/02_login.robot`
- `frontend/src/hooks/useSession.ts` (or equivalent)
- `frontend/src/components/ProtectedRoute.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "When the backend session check returns 401, the UI redirects"
**Expected Behavior:** When the frontend mounts and the session validation API returns 401, the user is redirected to the login page.
---
## Task: 02 Login — Logout Clears Session
**Test:** `Logout Clears Session`
**Suite:** `02_login.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/02_login.robot`
- `frontend/src/components/Sidebar.tsx` — logout button
- `backend/app/routers/auth.py` — logout endpoint
**Reference Docs:**
- `e2e/Instructions.md` — "Clicking the Sign Out button clears the session"
**Expected Behavior:** Clicking "Sign Out" clears the session cookie and invalidates the session on the backend.
---
## Task: 02 Login — After Logout Protected Pages Redirect To Login
**Test:** `After Logout Protected Pages Redirect To Login`
**Suite:** `02_login.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/02_login.robot`
- `frontend/src/App.tsx` — route guards
**Reference Docs:**
- `e2e/Instructions.md` — Post-logout behavior
**Expected Behavior:** After logging out, attempting to navigate to any protected page redirects to `/login`.
---
## Task: 02 Login — Login Preserves Originally Requested Page Via Next Parameter
**Test:** `Login Preserves Originally Requested Page Via Next Parameter`
**Suite:** `02_login.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/02_login.robot`
- `frontend/src/pages/LoginPage.tsx``next` query param handling
**Reference Docs:**
- `e2e/Instructions.md` — "After successful login, user is redirected to the originally requested page"
**Expected Behavior:** If an unauthenticated user tries to access `/jails`, they are redirected to `/login?next=/jails`. After successful login, they are redirected to `/jails`.
---
## Task: 03 Blocklist Import — Manual Blocklist Import Completes Without Error
**Test:** `Manual Blocklist Import Completes Without Error`
**Suite:** `03_blocklist_import.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Specific Error:** `Url: http://localhost:8000/api/v1/blocklists Expected status: 401 != 200`
**Files to Check:**
- `e2e/tests/03_blocklist_import.robot`
- `backend/app/routers/blocklists.py` — blocklist import endpoint
- `backend/app/services/blocklist_service.py`
**Reference Docs:**
- `e2e/Instructions.md` — "blocklist manual import via UI"
- `Docs/Features.md` — Blocklist importer
**Expected Behavior:** A logged-in admin can trigger a manual blocklist import via the UI/API, and it completes without errors. The endpoint should return 200 (not 401, which implies auth/session issue).
---
## Task: 03 Dashboard — Dashboard Page Renders Status Bar
**Test:** `Dashboard Page Renders Status Bar`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `frontend/src/pages/DashboardPage.tsx`
- `backend/app/routers/dashboard.py` — status endpoint
**Reference Docs:**
- `e2e/Instructions.md` — "status bar, time-range presets, data-source badges"
- `Docs/Features.md` — Dashboard overview
**Expected Behavior:** The dashboard page renders a status bar showing fail2ban server status (online/offline), version, and other key metrics.
---
## Task: 03 Dashboard — Dashboard Ban List Renders Columns
**Test:** `Dashboard Ban List Renders Columns`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `frontend/src/components/BanList.tsx` (or equivalent)
- `backend/app/routers/dashboard.py` — bans endpoint
**Reference Docs:**
- `Docs/Features.md` — Dashboard ban list table
**Expected Behavior:** The ban list table contains expected columns: IP Address, Country, Banned At, Expires At, Jail, Actions.
---
## Task: 03 Dashboard — Dashboard Time Range 24h Shows Live Source
**Test:** `Dashboard Time Range 24h Shows Live Source`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `frontend/src/pages/DashboardPage.tsx` — time range selector
- `backend/app/routers/dashboard.py` — bans endpoint with range filter
**Reference Docs:**
- `e2e/Instructions.md` — "Selecting Last 24 hours shows Live source badge"
**Expected Behavior:** Selecting "Last 24 hours" from the time range dropdown shows a "Live" data source badge, indicating data comes directly from fail2ban.
---
## Task: 03 Dashboard — Dashboard Time Range 7d Shows Archive Source
**Test:** `Dashboard Time Range 7d Shows Archive Source`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `frontend/src/pages/DashboardPage.tsx`
- `backend/app/routers/dashboard.py`
**Reference Docs:**
- `e2e/Instructions.md` — "Selecting Last 7 days shows Archive source badge"
**Expected Behavior:** Selecting "Last 7 days" shows an "Archive" data source badge, indicating data comes from the SQLite archive.
---
## Task: 03 Dashboard — Dashboard Time Range 30d Shows Archive Source
**Test:** `Dashboard Time Range 30d Shows Archive Source`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `frontend/src/pages/DashboardPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "Selecting Last 30 days shows Archive source badge"
**Expected Behavior:** Selecting "Last 30 days" shows an "Archive" data source badge.
---
## Task: 03 Dashboard — Dashboard Time Range 365d Shows Archive Source
**Test:** `Dashboard Time Range 365d Shows Archive Source`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `frontend/src/pages/DashboardPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "Selecting Last 365 days shows Archive source badge"
**Expected Behavior:** Selecting "Last 365 days" shows an "Archive" data source badge.
---
## Task: 03 Dashboard — Dashboard Bans Endpoint Returns Expected Shape
**Test:** `Dashboard Bans Endpoint Returns Expected Shape`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `backend/app/routers/dashboard.py``GET /api/v1/dashboard/bans`
- `backend/app/models/response.py` — ban response schema
**Reference Docs:**
- `Docs/API-Reference.md` — Dashboard bans endpoint contract
**Expected Behavior:** `GET /api/v1/dashboard/bans?range=24h&page=1&page_size=100` returns a paginated response with `items`, `total`, `page`, `page_size` fields, and each item has `ip`, `country`, `banned_at`, `expires_at`, `jail`.
---
## Task: 03 Dashboard — Dashboard Status Endpoint Returns Version
**Test:** `Dashboard Status Endpoint Returns Version`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `backend/app/routers/dashboard.py``GET /api/v1/dashboard/status`
**Reference Docs:**
- `Docs/API-Reference.md` — Dashboard status endpoint
**Expected Behavior:** `GET /api/v1/dashboard/status` returns JSON containing `version`, `online`, `jails_count`, and other status fields.
---
## Task: 03 Dashboard — Dashboard Bans By Country Endpoint
**Test:** `Dashboard Bans By Country Endpoint`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `backend/app/routers/dashboard.py``GET /api/v1/dashboard/bans/by-country`
**Reference Docs:**
- `Docs/API-Reference.md` — Geo aggregation endpoint
**Expected Behavior:** `GET /api/v1/dashboard/bans/by-country?range=24h` returns a list of `{country_code, country_name, count}` objects.
---
## Task: 03 Dashboard — Dashboard Bans Trend Endpoint
**Test:** `Dashboard Bans Trend Endpoint`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `backend/app/routers/dashboard.py``GET /api/v1/dashboard/bans/trend`
**Reference Docs:**
- `Docs/API-Reference.md` — Trend endpoint
**Expected Behavior:** `GET /api/v1/dashboard/bans/trend?range=24h` returns time-series data for chart rendering.
---
## Task: 03 Dashboard — Dashboard Bans By Jail Endpoint
**Test:** `Dashboard Bans By Jail Endpoint`
**Suite:** `03_dashboard.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/03_dashboard.robot`
- `backend/app/routers/dashboard.py` — jail aggregation endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Jail aggregation endpoint
**Expected Behavior:** Returns bans grouped by jail name with counts.
---
## Task: 04 Map — Map Page Renders World Map And Companion Table
**Test:** `Map Page Renders World Map And Companion Table`
**Suite:** `04_map.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/04_map.robot`
- `frontend/src/pages/MapPage.tsx`
- `frontend/src/components/WorldMap.tsx` (or equivalent)
**Reference Docs:**
- `e2e/Instructions.md` — "World Map View — country fills, click-to-filter"
- `Docs/Features.md` — Map view
**Expected Behavior:** The map page renders an interactive world map and a companion data table below it.
---
## Task: 04 Map — Map Page Renders Time Range Selector
**Test:** `Map Page Renders Time Range Selector`
**Suite:** `04_map.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/04_map.robot`
- `frontend/src/pages/MapPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — Map time range presets
**Expected Behavior:** The map page includes a time range selector (24h, 7d, 30d, 365d).
---
## Task: 04 Map — Map Page 24h Preset Shows Live Source Badge
**Test:** `Map Page 24h Preset Shows Live Source Badge`
**Suite:** `04_map.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/04_map.robot`
- `frontend/src/pages/MapPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "Selecting Last 24 hours shows Live source badge"
**Expected Behavior:** Selecting 24h on the map page shows a "Live" data source badge.
---
## Task: 04 Map — Map Page 7d Preset Shows Archive Source Badge
**Test:** `Map Page 7d Preset Shows Archive Source Badge`
**Suite:** `04_map.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/04_map.robot`
- `frontend/src/pages/MapPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "Selecting Last 7 days shows Archive source badge"
**Expected Behavior:** Selecting 7d on the map page shows an "Archive" data source badge.
---
## Task: 04 Map — Map Companion Table Is Sticky Header
**Test:** `Map Companion Table Is Sticky Header`
**Suite:** `04_map.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/04_map.robot`
- `frontend/src/components/MapCompanionTable.tsx` (or equivalent)
**Reference Docs:**
- `e2e/Instructions.md` — "sticky table header/footer"
**Expected Behavior:** The companion table below the map has a sticky header that remains visible while scrolling.
---
## Task: 04 Map — Map Page Has Zoom Controls
**Test:** `Map Page Has Zoom Controls`
**Suite:** `04_map.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/04_map.robot`
- `frontend/src/components/WorldMap.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "zoom controls"
**Expected Behavior:** The map includes zoom in/out controls (buttons or mouse wheel support).
---
## Task: 04 Map — Map Bans By Country API Endpoint
**Test:** `Map Bans By Country API Endpoint`
**Suite:** `04_map.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/04_map.robot`
- `backend/app/routers/dashboard.py` — geo endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Geo/country endpoint
**Expected Behavior:** `GET /api/v1/dashboard/bans/by-country` returns country-level ban counts for map coloring.
---
## Task: 04 Map — Map Threshold Config Endpoint Exists
**Test:** `Map Threshold Config Endpoint Exists`
**Suite:** `04_map.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/04_map.robot`
- `backend/app/routers/config_misc.py` (or equivalent)
**Reference Docs:**
- `Docs/API-Reference.md` — Map threshold configuration
**Expected Behavior:** A configuration endpoint exists for setting map color thresholds (e.g., low/medium/high ban count ranges).
---
## Task: 04 Map — Map Threshold Config Returns Thresholds
**Test:** `Map Threshold Config Returns Thresholds`
**Suite:** `04_map.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/04_map.robot`
- `backend/app/routers/config_misc.py`
**Reference Docs:**
- `Docs/API-Reference.md` — Map threshold configuration
**Expected Behavior:** The threshold config endpoint returns the currently configured threshold values.
---
## Task: 04 Map — Map Filter Clears And Resets Companion Table
**Test:** `Map Filter Clears And Resets Companion Table`
**Suite:** `04_map.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/04_map.robot`
- `frontend/src/pages/MapPage.tsx`
- `frontend/src/components/MapCompanionTable.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "click-to-filter, Clear filter"
**Expected Behavior:** Clicking a country on the map filters the companion table to that country. Clicking "Clear filter" resets the table to show all countries.
---
## Task: 05 Jails — Jails Page Lists Active Jails
**Test:** `Jails Page Lists Active Jails`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `frontend/src/pages/JailsPage.tsx`
- `backend/app/routers/jails.py` — jails list endpoint
**Reference Docs:**
- `e2e/Instructions.md` — "Jail Management — list"
- `Docs/Features.md` — Jail management
**Expected Behavior:** The jails page displays a table of all active jails with status, backend, banned count, failed count, find time, ban time, and max retry.
---
## Task: 05 Jails — Jails API Returns Active Jails
**Test:** `Jails API Returns Active Jails`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py``GET /api/v1/jails`
**Reference Docs:**
- `Docs/API-Reference.md` — Jails endpoint
**Expected Behavior:** `GET /api/v1/jails` returns a list of active jail configurations and their current status.
---
## Task: 05 Jails — Jail Detail Page Loads For First Active Jail
**Test:** `Jail Detail Page Loads For First Active Jail`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `frontend/src/pages/JailDetailPage.tsx`
- `backend/app/routers/jails.py` — jail detail endpoint
**Reference Docs:**
- `e2e/Instructions.md` — "Jail Management — list, ban/unban API, IP lookup"
**Expected Behavior:** Navigating to `/jails/{jail-name}` loads the detail page for that jail, showing banned IPs, ignore list, and jail controls.
---
## Task: 05 Jails — Ban An IP Via API
**Test:** `Ban An IP Via API`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py``POST /api/v1/bans`
- `backend/app/services/ban_service.py`
**Reference Docs:**
- `Docs/API-Reference.md` — Ban endpoint
- `e2e/Instructions.md` — "Ban / Unban IP"
**Expected Behavior:** `POST /api/v1/bans` with `{ip, jail}` bans the specified IP in the specified jail.
---
## Task: 05 Jails — Unban The IP We Just Banned
**Test:** `Unban The IP We Just Banned`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py``DELETE /api/v1/bans/{ip}`
**Reference Docs:**
- `Docs/API-Reference.md` — Unban endpoint
**Expected Behavior:** `DELETE /api/v1/bans/{ip}` (or equivalent unban endpoint) removes the ban for the specified IP.
---
## Task: 05 Jails — Unban All Endpoint Accepts Request
**Test:** `Unban All Endpoint Accepts Request`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py` — bulk unban endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Bulk unban endpoint
**Expected Behavior:** An endpoint exists to unban all IPs (either globally or per-jail) and returns success.
---
## Task: 05 Jails — Active Bans Endpoint Returns List
**Test:** `Active Bans Endpoint Returns List`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py` — active bans endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Active bans endpoint
**Expected Behavior:** `GET /api/v1/jails/{name}/bans` returns a paginated list of currently banned IPs for the specified jail.
---
## Task: 05 Jails — IP Lookup Endpoint Returns Geo
**Test:** `IP Lookup Endpoint Returns Geo`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/geo.py` — geo lookup endpoint
- `backend/app/services/geo_service.py`
**Reference Docs:**
- `Docs/API-Reference.md` — Geo lookup endpoint
- `Docs/Features.md` — IP geolocation
**Expected Behavior:** `GET /api/v1/geo/{ip}` returns geolocation data (country, city, ASN, org) for the given IP.
---
## Task: 05 Jails — Ignore List Add And Remove Via API
**Test:** `Ignore List Add And Remove Via API`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py` — ignore list endpoints
**Reference Docs:**
- `Docs/API-Reference.md` — Ignore list endpoints
**Expected Behavior:** `POST /api/v1/jails/{name}/ignore` adds an IP to the ignore list. `DELETE /api/v1/jails/{name}/ignore/{ip}` removes it.
---
## Task: 05 Jails — Ignore Self Toggle Via API
**Test:** `Ignore Self Toggle Via API`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py` — ignore self toggle
**Reference Docs:**
- `Docs/API-Reference.md` — Ignore self toggle
**Expected Behavior:** An endpoint exists to toggle "ignore self" (exclude the server's own IP from banning) for a jail.
---
## Task: 05 Jails — Jail Reload Endpoint Works
**Test:** `Jail Reload Endpoint Works`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py` — reload endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Jail control endpoints
**Expected Behavior:** `POST /api/v1/jails/{name}/reload` reloads the jail configuration and returns success.
---
## Task: 05 Jails — Jail Stop Endpoint Works
**Test:** `Jail Stop Endpoint Works`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py` — stop endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Jail control endpoints
**Expected Behavior:** `POST /api/v1/jails/{name}/stop` stops the jail and returns success.
---
## Task: 05 Jails — Jail Start Endpoint Works
**Test:** `Jail Start Endpoint Works`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py` — start endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Jail control endpoints
**Expected Behavior:** `POST /api/v1/jails/{name}/start` starts the jail and returns success.
---
## Task: 05 Jails — Jail Idle Endpoint Works
**Test:** `Jail Idle Endpoint Works`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py` — idle endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Jail control endpoints
**Expected Behavior:** `POST /api/v1/jails/{name}/idle` sets the jail to idle mode (monitoring without banning) and returns success.
---
## Task: 05 Jails — Reload All Jails Endpoint Works
**Test:** `Reload All Jails Endpoint Works`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/jails.py` — reload all endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Jail control endpoints
**Expected Behavior:** `POST /api/v1/jails/reload` reloads all jails and returns success.
---
## Task: 05 Jails — Geo Stats Endpoint Returns Counters
**Test:** `Geo Stats Endpoint Returns Counters`
**Suite:** `05_jails.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/05_jails.robot`
- `backend/app/routers/geo.py` — geo stats endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Geo stats endpoint
**Expected Behavior:** `GET /api/v1/geo/stats` returns aggregated geolocation statistics (bans by country, etc.).
---
## Task: 06 Config Jails Filters Actions — Config Page Renders All Required Tabs
**Test:** `Config Page Renders All Required Tabs`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `frontend/src/pages/ConfigPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "Configuration View — Jails/Filters/Actions tabs"
- `Docs/Features.md` — Configuration view
**Expected Behavior:** The configuration page renders tabs for Jails, Filters, Actions, Server, and Regex Tester.
---
## Task: 06 Config Jails Filters Actions — Config Jails Tab Defaults To Active
**Test:** `Config Jails Tab Defaults To Active`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `frontend/src/pages/ConfigPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "Jails/Filters/Actions tabs"
**Expected Behavior:** When navigating to `/config`, the "Jails" tab is active by default.
---
## Task: 06 Config Jails Filters Actions — Config Filters Tab Loads
**Test:** `Config Filters Tab Loads`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `frontend/src/pages/ConfigPage.tsx`
- `backend/app/routers/config_misc.py` — filters endpoint
**Reference Docs:**
- `e2e/Instructions.md` — "Filters tab"
**Expected Behavior:** Clicking the "Filters" tab loads and displays the list of fail2ban filter configurations.
---
## Task: 06 Config Jails Filters Actions — Config Actions Tab Loads
**Test:** `Config Actions Tab Loads`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `frontend/src/pages/ConfigPage.tsx`
- `backend/app/routers/config_misc.py` — actions endpoint
**Reference Docs:**
- `e2e/Instructions.md` — "Actions tab"
**Expected Behavior:** Clicking the "Actions" tab loads and displays the list of fail2ban action configurations.
---
## Task: 06 Config Jails Filters Actions — Config Server Tab Loads
**Test:** `Config Server Tab Loads`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `frontend/src/pages/ConfigPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "Server settings + log viewer"
**Expected Behavior:** The Server tab loads and displays server-wide settings.
---
## Task: 06 Config Jails Filters Actions — Config Regex Tester Tab Loads
**Test:** `Config Regex Tester Tab Loads`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `frontend/src/pages/ConfigPage.tsx`
- `frontend/src/components/RegexTester.tsx` (or equivalent)
**Reference Docs:**
- `e2e/Instructions.md` — "regex tester"
**Expected Behavior:** The Regex Tester tab loads with input fields for regex pattern and test log lines.
---
## Task: 06 Config Jails Filters Actions — Config Regex Tester API Endpoint Validates Pattern
**Test:** `Config Regex Tester API Endpoint Validates Pattern`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `backend/app/routers/config_misc.py` — regex tester endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Regex tester endpoint
**Expected Behavior:** `POST /api/v1/config/regex-test` (or equivalent) accepts a regex pattern and test lines, returns matches/non-matches.
---
## Task: 06 Config Jails Filters Actions — Config Jails Endpoint Lists Jail Configs
**Test:** `Config Jails Endpoint Lists Jail Configs`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `backend/app/routers/jail_config.py` — jail configs endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Jail config endpoint
**Expected Behavior:** `GET /api/v1/config/jails` returns a list of jail configuration files and their parsed settings.
---
## Task: 06 Config Jails Filters Actions — Config Filters Endpoint Lists Filter Configs
**Test:** `Config Filters Endpoint Lists Filter Configs`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `backend/app/routers/jail_config.py` — filter configs endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Filter config endpoint
**Expected Behavior:** `GET /api/v1/config/filters` returns a list of filter configuration files.
---
## Task: 06 Config Jails Filters Actions — Config Actions Endpoint Lists Action Configs
**Test:** `Config Actions Endpoint Lists Action Configs`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `backend/app/routers/jail_config.py` — action configs endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Action config endpoint
**Expected Behavior:** `GET /api/v1/config/actions` returns a list of action configuration files.
---
## Task: 06 Config Jails Filters Actions — Config Global Settings Endpoint
**Test:** `Config Global Settings Endpoint`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `backend/app/routers/jail_config.py` — global settings endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Global settings endpoint
**Expected Behavior:** `GET /api/v1/config/global` returns the global fail2ban configuration (e.g., `fail2ban.conf`).
---
## Task: 06 Config Jails Filters Actions — Config Service Status Endpoint
**Test:** `Config Service Status Endpoint`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `backend/app/routers/config_misc.py` — service status endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Service status endpoint
**Expected Behavior:** `GET /api/v1/config/service-status` returns fail2ban service status and log configuration.
---
## Task: 06 Config Jails Filters Actions — Config Security Headers Endpoint
**Test:** `Config Security Headers Endpoint`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `backend/app/routers/config_misc.py` — security headers endpoint
**Reference Docs:**
- `Docs/Security.md` — Security headers
**Expected Behavior:** An endpoint returns the currently configured security headers (CSP, X-Frame-Options, etc.).
---
## Task: 06 Config Jails Filters Actions — Config Inline Edit Round Trip For First Jail
**Test:** `Config Inline Edit Round Trip For First Jail`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `frontend/src/pages/ConfigPage.tsx`
- `backend/app/routers/jail_config.py` — update endpoint
**Reference Docs:**
- `e2e/Instructions.md` — "inline edit"
- `Docs/Features.md` — Config inline editing
**Expected Behavior:** Editing a jail config field inline, saving, and refreshing the page persists the change.
---
## Task: 06 Config Jails Filters Actions — Config Raw Section Lazy Load
**Test:** `Config Raw Section Lazy Load`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `frontend/src/pages/ConfigPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "raw config"
**Expected Behavior:** The raw config section is lazily loaded (not fetched until expanded) to improve initial page load performance.
---
## Task: 06 Config Jails Filters Actions — Config Raw Action File Endpoint
**Test:** `Config Raw Action File Endpoint`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `backend/app/routers/jail_config.py` — raw file endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Raw config endpoint
**Expected Behavior:** `GET /api/v1/config/actions/{name}/raw` returns the raw contents of an action config file.
---
## Task: 06 Config Jails Filters Actions — Config Jail Files Endpoint
**Test:** `Config Jail Files Endpoint`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `backend/app/routers/jail_config.py` — jail files endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Jail files endpoint
**Expected Behavior:** `GET /api/v1/config/jails/files` returns a list of available jail configuration files.
---
## Task: 06 Config Jails Filters Actions — Config Invalid Regex Returns 4xx
**Test:** `Config Invalid Regex Returns 4xx`
**Suite:** `06_config_jails_filters_actions.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/06_config_jails_filters_actions.robot`
- `backend/app/routers/config_misc.py` — regex tester endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Regex tester validation
**Expected Behavior:** Submitting an invalid regex pattern to the regex tester endpoint returns HTTP 400 (or other 4xx) with a descriptive error message.
---
## Task: 07 Config Log And Serversettings — Server Settings GET Returns Expected Keys
**Test:** `Server Settings GET Returns Expected Keys`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py` — server settings endpoint
**Reference Docs:**
- `e2e/Instructions.md` — "Server settings"
- `Docs/API-Reference.md` — Server settings endpoint
**Expected Behavior:** `GET /api/v1/config/server` returns JSON with expected keys: `log_level`, `db_purge_age`, `max_matches`, etc.
---
## Task: 07 Config Log And Serversettings — Server Settings Update Log Level
**Test:** `Server Settings Update Log Level`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py` — server settings update endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Server settings update
**Expected Behavior:** `PUT /api/v1/config/server` with `{log_level: "DEBUG"}` updates the log level and returns the updated config.
---
## Task: 07 Config Log And Serversettings — Server Settings Reject Invalid Log Level
**Test:** `Server Settings Reject Invalid Log Level`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py` — validation
**Reference Docs:**
- `Docs/API-Reference.md` — Server settings validation
**Expected Behavior:** Submitting an invalid log level (e.g., `"INVALID"`) returns HTTP 400 with a validation error.
---
## Task: 07 Config Log And Serversettings — Server Settings Update DB Purge Age
**Test:** `Server Settings Update DB Purge Age`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py`
**Reference Docs:**
- `Docs/API-Reference.md` — Server settings update
**Expected Behavior:** Updating `db_purge_age` persists the new value and applies it to the archive cleanup schedule.
---
## Task: 07 Config Log And Serversettings — Server Settings Update Max Matches
**Test:** `Server Settings Update Max Matches`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py`
**Reference Docs:**
- `Docs/API-Reference.md` — Server settings update
**Expected Behavior:** Updating `max_matches` persists the new value for log parsing.
---
## Task: 07 Config Log And Serversettings — Server Settings Reject Path Outside Allowlist
**Test:** `Server Settings Reject Path Outside Allowlist`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py` — path validation
**Reference Docs:**
- `Docs/Security.md` — Path traversal prevention
**Expected Behavior:** Submitting a log file path outside the allowed directory (e.g., `"/etc/passwd"`) returns HTTP 400.
---
## Task: 07 Config Log And Serversettings — Server Settings Accept Stdout Special Target
**Test:** `Server Settings Accept Stdout Special Target`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py`
**Reference Docs:**
- `Docs/API-Reference.md` — Server settings special targets
**Expected Behavior:** `"stdout"` is accepted as a special log target value.
---
## Task: 07 Config Log And Serversettings — Server Settings Accept Syslog Special Target
**Test:** `Server Settings Accept Syslog Special Target`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py`
**Reference Docs:**
- `Docs/API-Reference.md` — Server settings special targets
**Expected Behavior:** `"syslog"` is accepted as a special log target value.
---
## Task: 07 Config Log And Serversettings — Server Settings Accept Safe File Path
**Test:** `Server Settings Accept Safe File Path`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py`
**Reference Docs:**
- `Docs/API-Reference.md` — Server settings path validation
**Expected Behavior:** A safe, allowlisted file path (e.g., `"/var/log/auth.log"`) is accepted.
---
## Task: 07 Config Log And Serversettings — Flush Logs Endpoint Works
**Test:** `Flush Logs Endpoint Works`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py` — flush logs endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Log management endpoints
**Expected Behavior:** `POST /api/v1/config/logs/flush` flushes buffered logs and returns success.
---
## Task: 07 Config Log And Serversettings — Log Preview Endpoint Returns Content
**Test:** `Log Preview Endpoint Returns Content`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py` — log preview endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Log preview endpoint
**Expected Behavior:** `GET /api/v1/config/logs/preview` returns the most recent log lines as text or JSON.
---
## Task: 07 Config Log And Serversettings — Log Endpoint Returns Content Or 404
**Test:** `Log Endpoint Returns Content Or 404`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py` — log endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Log endpoint
**Expected Behavior:** `GET /api/v1/config/logs` returns log content if available, or HTTP 404 if no log file is configured/found.
---
## Task: 07 Config Log And Serversettings — Log Observation Add Rejects Path Outside Allowlist
**Test:** `Log Observation Add Rejects Path Outside Allowlist`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py` — log observation endpoint
**Reference Docs:**
- `Docs/Security.md` — Path traversal prevention
- `e2e/Instructions.md` — "log observation allowlist"
**Expected Behavior:** Adding a log observation path outside the allowlist returns HTTP 400 with a security error.
---
## Task: 07 Config Log And Serversettings — Log Observation Add Endpoint Exists
**Test:** `Log Observation Add Endpoint Exists`
**Suite:** `07_config_log_and_serversettings.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/07_config_log_and_serversettings.robot`
- `backend/app/routers/config_misc.py`
**Reference Docs:**
- `Docs/API-Reference.md` — Log observation endpoints
**Expected Behavior:** `POST /api/v1/config/logs/observation` exists and accepts `{path: "/var/log/auth.log"}`.
---
## Task: 08 History — History Page Renders
**Test:** `History Page Renders`
**Suite:** `08_history.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/08_history.robot`
- `frontend/src/pages/HistoryPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "Ban History — table, filters, per-IP timeline"
- `Docs/Features.md` — History view
**Expected Behavior:** The history page renders with a table, filters, and pagination controls.
---
## Task: 08 History — History Page Shows Archive Source Badge By Default
**Test:** `History Page Shows Archive Source Badge By Default`
**Suite:** `08_history.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/08_history.robot`
- `frontend/src/pages/HistoryPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "archive vs fail2ban source"
**Expected Behavior:** The history page shows an "Archive" data source badge by default (since history comes from the SQLite archive, not live fail2ban).
---
## Task: 08 History — History Page Default 7d Range
**Test:** `History Page Default 7d Range`
**Suite:** `08_history.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/08_history.robot`
- `frontend/src/pages/HistoryPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — History time range defaults
**Expected Behavior:** The history page defaults to showing the last 7 days of ban history.
---
## Task: 08 History — History Endpoint Returns Paginated Data
**Test:** `History Endpoint Returns Paginated Data`
**Suite:** `08_history.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/08_history.robot`
- `backend/app/routers/history.py` — history endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — History endpoint
**Expected Behavior:** `GET /api/v1/history?page=1&page_size=50` returns paginated ban history with `items`, `total`, `page`, `page_size`.
---
## Task: 08 History — History Archive Endpoint Returns Data
**Test:** `History Archive Endpoint Returns Data`
**Suite:** `08_history.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/08_history.robot`
- `backend/app/routers/history.py` — archive endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — History archive endpoint
**Expected Behavior:** `GET /api/v1/history/archive` returns archived ban records.
---
## Task: 08 History — History Per IP Endpoint Returns Data
**Test:** `History Per IP Endpoint Returns Data`
**Suite:** `08_history.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/08_history.robot`
- `backend/app/routers/history.py` — per-IP endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Per-IP history endpoint
**Expected Behavior:** `GET /api/v1/history/ip/{ip}` returns the ban timeline for a specific IP address.
---
## Task: 08 History — History Filter By Jail Returns Data
**Test:** `History Filter By Jail Returns Data`
**Suite:** `08_history.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/08_history.robot`
- `backend/app/routers/history.py`
**Reference Docs:**
- `Docs/API-Reference.md` — History filtering
**Expected Behavior:** `GET /api/v1/history?jail=ssh` returns only bans from the specified jail.
---
## Task: 08 History — History Filter By Source Fail2ban
**Test:** `History Filter By Source Fail2ban`
**Suite:** `08_history.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/08_history.robot`
- `backend/app/routers/history.py`
**Reference Docs:**
- `Docs/API-Reference.md` — History source filtering
**Expected Behavior:** Filtering by `source=fail2ban` returns only live fail2ban-sourced records.
---
## Task: 08 History — History Filter By Source Archive
**Test:** `History Filter By Source Archive`
**Suite:** `08_history.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/08_history.robot`
- `backend/app/routers/history.py`
**Reference Docs:**
- `Docs/API-Reference.md` — History source filtering
**Expected Behavior:** Filtering by `source=archive` returns only archived records.
---
## Task: 08 History — History URL Params Honored
**Test:** `History URL Params Honored`
**Suite:** `08_history.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/08_history.robot`
- `frontend/src/pages/HistoryPage.tsx` — URL param parsing
**Reference Docs:**
- `Docs/Features.md` — Deep-linking with URL params
**Expected Behavior:** Navigating to `/history?range=30d&jail=ssh` pre-selects the 30-day range and ssh jail filter.
---
## Task: 09 Blocklists — Blocklists Page Renders
**Test:** `Blocklists Page Renders`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `frontend/src/pages/BlocklistsPage.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "External Blocklist Importer — CRUD"
- `Docs/Features.md` — Blocklist management
**Expected Behavior:** The blocklists page renders with a table of configured sources, import controls, and schedule settings.
---
## Task: 09 Blocklists — Blocklists Sources List Endpoint
**Test:** `Blocklists Sources List Endpoint`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — sources list endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Blocklist sources endpoint
**Expected Behavior:** `GET /api/v1/blocklists` returns a list of configured blocklist sources.
---
## Task: 09 Blocklists — Blocklist Source Create Rejects Invalid Scheme
**Test:** `Blocklist Source Create Rejects Invalid Scheme`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — create endpoint validation
**Reference Docs:**
- `Docs/Security.md` — SSRF prevention
- `e2e/Instructions.md` — "SSRF validation"
**Expected Behavior:** Creating a blocklist source with an invalid URL scheme (e.g., `ftp://`, `file://`) returns HTTP 400.
---
## Task: 09 Blocklists — Blocklist Source Create Rejects Loopback URL
**Test:** `Blocklist Source Create Rejects Loopback URL`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — SSRF validation
**Reference Docs:**
- `Docs/Security.md` — SSRF prevention
**Expected Behavior:** Creating a blocklist source with a loopback URL (`http://127.0.0.1/...`, `http://localhost/...`) returns HTTP 400.
---
## Task: 09 Blocklists — Blocklist Source Create Rejects Private IP URL
**Test:** `Blocklist Source Create Rejects Private IP URL`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — SSRF validation
**Reference Docs:**
- `Docs/Security.md` — SSRF prevention
**Expected Behavior:** Creating a blocklist source with a private IP URL (`http://192.168.1.1/...`, `http://10.0.0.1/...`) returns HTTP 400.
---
## Task: 09 Blocklists — Blocklist Source Create Rejects Link Local URL
**Test:** `Blocklist Source Create Rejects Link Local URL`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — SSRF validation
**Reference Docs:**
- `Docs/Security.md` — SSRF prevention
**Expected Behavior:** Creating a blocklist source with a link-local URL (`http://169.254.1.1/...`) returns HTTP 400.
---
## Task: 09 Blocklists — Blocklist Schedule Endpoint Returns Config
**Test:** `Blocklist Schedule Endpoint Returns Config`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — schedule endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Blocklist schedule endpoint
**Expected Behavior:** `GET /api/v1/blocklists/schedule` returns the current import schedule configuration (cron expression, enabled status).
---
## Task: 09 Blocklists — Blocklist Schedule Update Works
**Test:** `Blocklist Schedule Update Works`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — schedule update endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Blocklist schedule update
**Expected Behavior:** `PUT /api/v1/blocklists/schedule` updates the import schedule and returns the updated config.
---
## Task: 09 Blocklists — Blocklist Manual Import Endpoint Reachable
**Test:** `Blocklist Manual Import Endpoint Reachable`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — manual import endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Blocklist manual import
**Expected Behavior:** `POST /api/v1/blocklists/import` triggers a manual import and returns a job ID or success status.
---
## Task: 09 Blocklists — Blocklist Import Log Endpoint Returns Paginated Data
**Test:** `Blocklist Import Log Endpoint Returns Paginated Data`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — import log endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Blocklist import log
**Expected Behavior:** `GET /api/v1/blocklists/log` returns paginated import log entries with timestamps, source, status, and error counts.
---
## Task: 09 Blocklists — Blocklist Delete Non Existent Returns 404
**Test:** `Blocklist Delete Non Existent Returns 404`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — delete endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Blocklist delete endpoint
**Expected Behavior:** `DELETE /api/v1/blocklists/{id}` for a non-existent source returns HTTP 404.
---
## Task: 09 Blocklists — Blocklist Create And Delete Cycle
**Test:** `Blocklist Create And Delete Cycle`
**Suite:** `09_blocklists.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/09_blocklists.robot`
- `backend/app/routers/blocklists.py` — create and delete endpoints
**Reference Docs:**
- `e2e/Instructions.md` — "CRUD"
**Expected Behavior:** Creating a valid blocklist source, verifying it appears in the list, and then deleting it removes it from the list.
---
## Task: 10 General Layout — Sidebar Is Visible On Dashboard
**Test:** `Sidebar Is Visible On Dashboard`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `frontend/src/components/Sidebar.tsx` (or `Layout.tsx`)
**Reference Docs:**
- `e2e/Instructions.md` — "sidebar nav"
- `Docs/Features.md` — Layout
**Expected Behavior:** After login, the sidebar navigation is visible on the dashboard page.
---
## Task: 10 General Layout — Sidebar Lists All Required Pages
**Test:** `Sidebar Lists All Required Pages`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `frontend/src/components/Sidebar.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "sidebar nav"
**Expected Behavior:** The sidebar contains links to: Dashboard, World Map, Jails, History, Blocklists, Configuration.
---
## Task: 10 General Layout — Sidebar Sign Out Logs User Out
**Test:** `Sidebar Sign Out Logs User Out`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `frontend/src/components/Sidebar.tsx`
- `backend/app/routers/auth.py` — logout endpoint
**Reference Docs:**
- `e2e/Instructions.md` — "Sign Out button"
**Expected Behavior:** Clicking "Sign Out" in the sidebar clears the session and redirects to `/login`.
---
## Task: 10 General Layout — Theme Toggle Is Present In Sidebar
**Test:** `Theme Toggle Is Present In Sidebar`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `frontend/src/components/Sidebar.tsx`
- `frontend/src/hooks/useTheme.ts` (or equivalent)
**Reference Docs:**
- `e2e/Instructions.md` — "theme toggle"
**Expected Behavior:** The sidebar contains a theme toggle button (light/dark mode).
---
## Task: 10 General Layout — Active Page Highlighted In Sidebar
**Test:** `Active Page Highlighted In Sidebar`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `frontend/src/components/Sidebar.tsx`
**Reference Docs:**
- `e2e/Instructions.md` — "active link highlighting"
**Expected Behavior:** The current page's sidebar link is visually highlighted (different background/text color).
---
## Task: 10 General Layout — Session Persists Across Page Reload
**Test:** `Session Persists Across Page Reload`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `frontend/src/hooks/useSession.ts`
- `backend/app/routers/auth.py` — session validation
**Reference Docs:**
- `e2e/Instructions.md` — "session persistence"
**Expected Behavior:** Reloading the page while logged in does NOT redirect to login; the session cookie is still valid.
---
## Task: 10 General Layout — Theme Toggle Changes Color Mode
**Test:** `Theme Toggle Changes Color Mode`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `frontend/src/components/Sidebar.tsx`
- `frontend/src/hooks/useTheme.ts`
**Reference Docs:**
- `e2e/Instructions.md` — "theme toggle"
**Expected Behavior:** Clicking the theme toggle switches the UI between light and dark mode, and the preference persists in `localStorage`.
---
## Task: 10 General Layout — Health Endpoint Returns Component Status
**Test:** `Health Endpoint Returns Component Status`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `backend/app/routers/health.py` — health endpoint
**Reference Docs:**
- `e2e/Instructions.md` — "health endpoints"
- `Docs/API-Reference.md` — Health endpoint
**Expected Behavior:** `GET /api/v1/health` returns JSON with component statuses: `database`, `fail2ban`, `scheduler`, `cache`, etc.
---
## Task: 10 General Layout — Liveness Endpoint Returns 200
**Test:** `Liveness Endpoint Returns 200`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `backend/app/routers/health.py` — liveness endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Liveness probe
- `Docs/Deployment.md` — Kubernetes probes
**Expected Behavior:** `GET /api/v1/health/live` always returns HTTP 200 (even if fail2ban is down), indicating the Python process is alive.
---
## Task: 10 General Layout — Metrics Endpoint Returns Prometheus Text
**Test:** `Metrics Endpoint Returns Prometheus Text`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `backend/app/routers/metrics.py` (or equivalent)
**Reference Docs:**
- `Docs/Observability.md` — Prometheus metrics
- `Docs/API-Reference.md` — Metrics endpoint
**Expected Behavior:** `GET /api/v1/metrics` returns Prometheus-formatted text with application metrics (request counts, ban counts, etc.).
---
## Task: 10 General Layout — Setup Timezone Endpoint Returns IANA String
**Test:** `Setup Timezone Endpoint Returns IANA String`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `backend/app/routers/setup.py` — timezone endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Setup timezone endpoint
**Expected Behavior:** `GET /api/v1/setup/timezone` returns a valid IANA timezone string (e.g., `"UTC"`, `"Europe/Berlin"`).
---
## Task: 10 General Layout — Setup Status Endpoint Returns Completed Flag
**Test:** `Setup Status Endpoint Returns Completed Flag`
**Suite:** `10_general_layout.robot`
**Step That Fails:** Parent suite setup (`Wait For Backend Health`).
**Files to Check:**
- `e2e/tests/10_general_layout.robot`
- `backend/app/routers/setup.py` — setup status endpoint
**Reference Docs:**
- `Docs/API-Reference.md` — Setup status endpoint
**Expected Behavior:** `GET /api/v1/setup` returns `{completed: true|false}` indicating whether initial setup has been completed.