Files
BanGUI/Docs/Tasks.md
2026-04-05 22:45:41 +02:00

74 lines
4.5 KiB
Markdown

# BanGUI — Task List
This document breaks the entire BanGUI project into development stages, ordered so that each stage builds on the previous one. Every task is described in prose with enough detail for a developer to begin work. References point to the relevant documentation.
Reference: `Docs/Refactoring.md` for full analysis of each issue.
---
## Open Issues
---
### TASK-001 — WorldMap: filter companion table by selected country (server-side)
**Status:** Done
**Priority:** Medium
**Domain:** Full-stack (backend + frontend)
**References:** `Docs/Features.md §4`, `Docs/Web-Development.md`
#### Background
The `GET /api/dashboard/bans/by-country` endpoint always returns the **200 most recent** ban rows in `bans` (constant `_MAX_COMPANION_BANS = 200` in `backend/app/services/ban_service.py`). `MapPage.tsx` stores a `selectedCountry` state and filters the returned rows client-side via `visibleBans`. This means the companion table can only show the fraction of a country's bans that fall within the global top-200 window. If the selected time range has, say, 1 500 bans and 300 are from China, but China's bans are not all in the top 200 overall, the table will silently display fewer than 300 rows.
When a country is selected the companion table **must** return the complete set of bans for that country so the user sees an accurate picture.
#### Desired behaviour
- No country selected → companion table shows the 200 most recent bans across all countries (existing behaviour, no change).
- Country selected → the server returns **all** ban entries for that country in the selected time window; no client-side row-count cap applies.
- Deselecting a country (clicking the same country again, or the "Clear filter" button) reverts to the default 200-row unfiltered view.
- The existing `visibleBans` client-side filter in `MapPage.tsx` can remain as a defensive guard but must not be the only filter.
#### Implementation steps
1. **Backend — router** (`backend/app/routers/dashboard.py`)
- Add `country_code: str | None = Query(default=None, description="ISO alpha-2 country code to filter companion rows.")` to `get_bans_by_country`.
- Pass it to `ban_service.bans_by_country(..., country_code=country_code)`.
2. **Backend — service** (`backend/app/services/ban_service.py`)
- Add `country_code: str | None = None` keyword argument to `bans_by_country`.
- After `geo_map` is built (existing geo-resolution step), collect IPs whose resolved country matches `country_code`.
- For the **fail2ban source**: call `fail2ban_db_repo.get_currently_banned` with `ip_filter=matched_ips` and no `limit` (remove the `_MAX_COMPANION_BANS` cap for filtered queries).
- For the **archive source**: filter `all_rows` to those whose IP is in `matched_ips` and return all of them (skip the `page_size=_MAX_COMPANION_BANS` call).
- When `country_code` is `None`, behaviour is identical to today.
3. **Backend — repository** (`backend/app/repositories/fail2ban_db_repo.py`)
- Add `ip_filter: list[str] | None = None` to `get_currently_banned`.
- When provided and non-empty, append `AND ip IN ({placeholders})` to the SQL `WHERE` clause, parameterised safely (never interpolated as a string).
4. **Backend — repository (archive)** (`backend/app/repositories/history_archive_repo.py`)
- Similarly add optional `ip_filter` to the archive companion-rows query used from `bans_by_country`.
5. **Frontend — API client** (`frontend/src/api/map.ts`)
- Add optional `countryCode?: string` parameter to `fetchBansByCountry`.
- When set, append `country_code=<value>` to the query string.
6. **Frontend — hook** (`frontend/src/hooks/useMapData.ts`)
- Add `countryCode?: string` to the function signature.
- Include it in the `useCallback` dependency array and pass it to `fetchBansByCountry`.
7. **Frontend — page** (`frontend/src/pages/MapPage.tsx`)
- Pass `selectedCountry ?? undefined` as `countryCode` to `useMapData`.
- The hook's effect will re-fetch automatically when `selectedCountry` changes; the existing `useEffect` that resets `page` to 1 already covers this.
#### Testing guidance
- Select a country that has > 200 bans in the chosen time window; confirm the companion table shows more than the previous cap would allow.
- With no country selected, confirm only 200 rows are returned (no regression).
- Deselect the country; confirm the unfiltered 200-row view is restored.
- Test with the archive source as well as the fail2ban live source.
- Verify the `ip_filter` SQL clause is parameterised and cannot be injected.
---