Docs: mark Task 8/9 completed and update architecture docs

This commit is contained in:
2026-03-22 10:06:00 +01:00
parent 05dc9fa1e3
commit 335f89c554
2 changed files with 52 additions and 20 deletions

View File

@@ -82,10 +82,12 @@ The backend follows a **layered architecture** with strict separation of concern
backend/ backend/
├── app/ ├── app/
│ ├── __init__.py │ ├── __init__.py
│ ├── main.py # FastAPI app factory, lifespan, exception handlers │ ├── `main.py` # FastAPI app factory, lifespan, exception handlers
│ ├── config.py # Pydantic settings (env vars, .env loading) │ ├── `config.py` # Pydantic settings (env vars, .env loading)
│ ├── dependencies.py # FastAPI Depends() providers (DB, services, auth) │ ├── `db.py` # Database connection and initialization
│ ├── models/ # Pydantic schemas │ ├── `exceptions.py` # Shared domain exception classes
│ ├── `dependencies.py` # FastAPI Depends() providers (DB, services, auth)
│ ├── `models/` # Pydantic schemas
│ │ ├── auth.py # Login request/response, session models │ │ ├── auth.py # Login request/response, session models
│ │ ├── ban.py # Ban request/response/domain models │ │ ├── ban.py # Ban request/response/domain models
│ │ ├── jail.py # Jail request/response/domain models │ │ ├── jail.py # Jail request/response/domain models
@@ -111,6 +113,12 @@ backend/
│ │ ├── jail_service.py # Jail listing, start/stop/reload, status aggregation │ │ ├── jail_service.py # Jail listing, start/stop/reload, status aggregation
│ │ ├── ban_service.py # Ban/unban execution, currently-banned queries │ │ ├── ban_service.py # Ban/unban execution, currently-banned queries
│ │ ├── config_service.py # Read/write fail2ban config, regex validation │ │ ├── config_service.py # Read/write fail2ban config, regex validation
│ │ ├── config_file_service.py # Shared config parsing and file-level operations
│ │ ├── raw_config_io_service.py # Raw config file I/O wrapper
│ │ ├── jail_config_service.py # jail config activation/deactivation logic
│ │ ├── filter_config_service.py # filter config lifecycle management
│ │ ├── action_config_service.py # action config lifecycle management
│ │ ├── log_service.py # Log preview and regex test operations
│ │ ├── history_service.py # Historical ban queries, per-IP timeline │ │ ├── history_service.py # Historical ban queries, per-IP timeline
│ │ ├── blocklist_service.py # Download, validate, apply blocklists │ │ ├── blocklist_service.py # Download, validate, apply blocklists
│ │ ├── geo_service.py # IP-to-country resolution, ASN/RIR lookup │ │ ├── geo_service.py # IP-to-country resolution, ASN/RIR lookup
@@ -119,17 +127,18 @@ backend/
│ ├── repositories/ # Data access layer (raw queries only) │ ├── repositories/ # Data access layer (raw queries only)
│ │ ├── settings_repo.py # App configuration CRUD in SQLite │ │ ├── settings_repo.py # App configuration CRUD in SQLite
│ │ ├── session_repo.py # Session storage and lookup │ │ ├── session_repo.py # Session storage and lookup
│ │ ├── blocklist_repo.py # Blocklist sources and import log persistence │ │ ├── blocklist_repo.py # Blocklist sources and import log persistence│ │ ├── fail2ban_db_repo.py # fail2ban SQLite ban history read operations
│ │ └── import_log_repo.py # Import run history records │ │ ├── geo_cache_repo.py # IP geolocation cache persistence│ │ └── import_log_repo.py # Import run history records
│ ├── tasks/ # APScheduler background jobs │ ├── tasks/ # APScheduler background jobs
│ │ ├── blocklist_import.py# Scheduled blocklist download and application │ │ ├── blocklist_import.py# Scheduled blocklist download and application
│ │ ├── geo_cache_flush.py # Periodic geo cache persistence (dirty-set flush to SQLite) │ │ ├── geo_cache_flush.py # Periodic geo cache persistence (dirty-set flush to SQLite)│ │ ├── geo_re_resolve.py # Periodic re-resolution of stale geo cache records│ │ └── health_check.py # Periodic fail2ban connectivity probe
│ │ └── health_check.py # Periodic fail2ban connectivity probe
│ └── utils/ # Helpers, constants, shared types │ └── utils/ # Helpers, constants, shared types
│ ├── fail2ban_client.py # Async wrapper around the fail2ban socket protocol │ ├── fail2ban_client.py # Async wrapper around the fail2ban socket protocol
│ ├── ip_utils.py # IP/CIDR validation and normalisation │ ├── ip_utils.py # IP/CIDR validation and normalisation
│ ├── time_utils.py # Timezone-aware datetime helpers │ ├── time_utils.py # Timezone-aware datetime helpers│ ├── jail_config.py # Jail config parser/serializer helper
── constants.py # Shared constants (default paths, limits, etc.) ── conffile_parser.py # Fail2ban config file parser/serializer
│ ├── config_parser.py # Structured config object parser
│ ├── config_writer.py # Atomic config file write operations│ └── constants.py # Shared constants (default paths, limits, etc.)
├── tests/ ├── tests/
│ ├── conftest.py # Shared fixtures (test app, client, mock DB) │ ├── conftest.py # Shared fixtures (test app, client, mock DB)
│ ├── test_routers/ # One test file per router │ ├── test_routers/ # One test file per router
@@ -158,8 +167,9 @@ The HTTP interface layer. Each router maps URL paths to handler functions. Route
| `blocklist.py` | `/api/blocklists` | CRUD blocklist sources, trigger import, view import logs | | `blocklist.py` | `/api/blocklists` | CRUD blocklist sources, trigger import, view import logs |
| `geo.py` | `/api/geo` | IP geolocation lookup, ASN and RIR data | | `geo.py` | `/api/geo` | IP geolocation lookup, ASN and RIR data |
| `server.py` | `/api/server` | Log level, log target, DB path, purge age, flush logs | | `server.py` | `/api/server` | Log level, log target, DB path, purge age, flush logs |
| `health.py` | `/api/health` | fail2ban connectivity health check and status |
#### Services (`app/services/`) #### Services (`app/services`)
The business logic layer. Services orchestrate operations, enforce rules, and coordinate between repositories, the fail2ban client, and external APIs. Each service covers a single domain. The business logic layer. Services orchestrate operations, enforce rules, and coordinate between repositories, the fail2ban client, and external APIs. Each service covers a single domain.
@@ -175,7 +185,8 @@ The business logic layer. Services orchestrate operations, enforce rules, and co
| `filter_config_service.py` | Discovers available filters by scanning filter.d/; reads, creates, updates, and deletes filter definitions; assigns filters to jails | | `filter_config_service.py` | Discovers available filters by scanning filter.d/; reads, creates, updates, and deletes filter definitions; assigns filters to jails |
| `action_config_service.py` | Discovers available actions by scanning action.d/; reads, creates, updates, and deletes action definitions; assigns actions to jails | | `action_config_service.py` | Discovers available actions by scanning action.d/; reads, creates, updates, and deletes action definitions; assigns actions to jails |
| `config_file_service.py` | Shared utilities for configuration parsing and manipulation: parses config files, validates names/IPs, manages atomic file writes, probes fail2ban socket | | `config_file_service.py` | Shared utilities for configuration parsing and manipulation: parses config files, validates names/IPs, manages atomic file writes, probes fail2ban socket |
| `conffile_parser.py` | Parses fail2ban `.conf` files into structured Python types (jail config, filter config, action config); also serialises back to text | | `raw_config_io_service.py` | Low-level file I/O for raw fail2ban config files |
| `log_service.py` | Log preview and regex test operations (extracted from config_service) |
| `history_service.py` | Queries the fail2ban database for historical ban records, builds per-IP timelines, computes ban counts and repeat-offender flags | | `history_service.py` | Queries the fail2ban database for historical ban records, builds per-IP timelines, computes ban counts and repeat-offender flags |
| `blocklist_service.py` | Downloads blocklists via aiohttp, validates IPs/CIDRs, applies bans through fail2ban or iptables, logs import results | | `blocklist_service.py` | Downloads blocklists via aiohttp, validates IPs/CIDRs, applies bans through fail2ban or iptables, logs import results |
| `geo_service.py` | Resolves IP addresses to country, ASN, and RIR using external APIs or a local database, caches results | | `geo_service.py` | Resolves IP addresses to country, ASN, and RIR using external APIs or a local database, caches results |
@@ -191,15 +202,26 @@ The data access layer. Repositories execute raw SQL queries against the applicat
| `settings_repo.py` | CRUD operations for application settings (master password hash, DB path, fail2ban socket path, preferences) | | `settings_repo.py` | CRUD operations for application settings (master password hash, DB path, fail2ban socket path, preferences) |
| `session_repo.py` | Store, retrieve, and delete session records for authentication | | `session_repo.py` | Store, retrieve, and delete session records for authentication |
| `blocklist_repo.py` | Persist blocklist source definitions (name, URL, enabled/disabled) | | `blocklist_repo.py` | Persist blocklist source definitions (name, URL, enabled/disabled) |
| `fail2ban_db_repo.py` | Read historical ban records from the fail2ban SQLite database |
| `geo_cache_repo.py` | Persist and query IP geo resolution cache |
| `import_log_repo.py` | Record import run results (timestamp, source, IPs imported, errors) for the import log view | | `import_log_repo.py` | Record import run results (timestamp, source, IPs imported, errors) for the import log view |
#### Models (`app/models/`) #### Models (`app/models/`)
Pydantic schemas that define data shapes and validation. Models are split into three categories per domain: Pydantic schemas that define data shapes and validation. Models are split into three categories per domain.
- **Request models** — validate incoming API data (e.g., `BanRequest`, `LoginRequest`) | Model file | Purpose |
- **Response models** — shape outgoing API data (e.g., `JailResponse`, `BanListResponse`) |---|---|
- **Domain models** — internal representations used between services and repositories (e.g., `Ban`, `Jail`) | `auth.py` | Login/request and session models |
| `ban.py` | Ban creation and lookup models |
| `blocklist.py` | Blocklist source and import log models |
| `config.py` | Fail2ban config view/edit models |
| `file_config.py` | Raw config file read/write models |
| `geo.py` | Geo and ASN lookup models |
| `history.py` | Historical ban query and timeline models |
| `jail.py` | Jail listing and status models |
| `server.py` | Server status and settings models |
| `setup.py` | First-run setup wizard models |
#### Tasks (`app/tasks/`) #### Tasks (`app/tasks/`)
@@ -209,6 +231,7 @@ APScheduler background jobs that run on a schedule without user interaction.
|---|---| |---|---|
| `blocklist_import.py` | Downloads all enabled blocklist sources, validates entries, applies bans, records results in the import log | | `blocklist_import.py` | Downloads all enabled blocklist sources, validates entries, applies bans, records results in the import log |
| `geo_cache_flush.py` | Periodically flushes newly resolved IPs from the in-memory dirty set to the `geo_cache` SQLite table (default: every 60 seconds). GET requests populate only the in-memory cache; this task persists them without blocking any request. | | `geo_cache_flush.py` | Periodically flushes newly resolved IPs from the in-memory dirty set to the `geo_cache` SQLite table (default: every 60 seconds). GET requests populate only the in-memory cache; this task persists them without blocking any request. |
| `geo_re_resolve.py` | Periodically re-resolves stale entries in `geo_cache` to keep geolocation data fresh |
| `health_check.py` | Periodically pings the fail2ban socket and updates the cached server status so the frontend always has fresh data | | `health_check.py` | Periodically pings the fail2ban socket and updates the cached server status so the frontend always has fresh data |
#### Utils (`app/utils/`) #### Utils (`app/utils/`)
@@ -219,7 +242,16 @@ Pure helper modules with no framework dependencies.
|---|---| |---|---|
| `fail2ban_client.py` | Async client that communicates with fail2ban via its Unix domain socket — sends commands and parses responses using the fail2ban protocol. Modelled after [`./fail2ban-master/fail2ban/client/csocket.py`](../fail2ban-master/fail2ban/client/csocket.py) and [`./fail2ban-master/fail2ban/client/fail2banclient.py`](../fail2ban-master/fail2ban/client/fail2banclient.py). | | `fail2ban_client.py` | Async client that communicates with fail2ban via its Unix domain socket — sends commands and parses responses using the fail2ban protocol. Modelled after [`./fail2ban-master/fail2ban/client/csocket.py`](../fail2ban-master/fail2ban/client/csocket.py) and [`./fail2ban-master/fail2ban/client/fail2banclient.py`](../fail2ban-master/fail2ban/client/fail2banclient.py). |
| `ip_utils.py` | Validates IPv4/IPv6 addresses and CIDR ranges using the `ipaddress` stdlib module, normalises formats | | `ip_utils.py` | Validates IPv4/IPv6 addresses and CIDR ranges using the `ipaddress` stdlib module, normalises formats |
| `jail_utils.py` | Jail helper functions for configuration and status inference |
| `jail_config.py` | Jail config parser and serializer for fail2ban config manipulation |
| `time_utils.py` | Timezone-aware datetime construction, formatting helpers, time-range calculations | | `time_utils.py` | Timezone-aware datetime construction, formatting helpers, time-range calculations |
| `log_utils.py` | Structured log formatting and enrichment helpers |
| `conffile_parser.py` | Parses Fail2ban `.conf` files into structured objects and serialises back to text |
| `config_parser.py` | Builds structured config objects from file content tokens |
| `config_writer.py` | Atomic config file writes, backups, and safe replace semantics |
| `config_file_utils.py` | Common file-level config utility helpers |
| `fail2ban_db_utils.py` | Fail2ban DB path discovery and ban-history parsing helpers |
| `setup_utils.py` | Setup wizard helper utilities |
| `constants.py` | Shared constants: default socket path, default database path, time-range presets, limits | | `constants.py` | Shared constants: default socket path, default database path, time-range presets, limits |
#### Configuration (`app/config.py`) #### Configuration (`app/config.py`)

View File

@@ -150,7 +150,7 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue.
--- ---
### Task 7 — Remove remaining service-to-service coupling ### Task 7 — Remove remaining service-to-service coupling (✅ completed)
**Priority**: Medium **Priority**: Medium
**Refactoring ref**: Refactoring.md §1 **Refactoring ref**: Refactoring.md §1
@@ -172,7 +172,7 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue.
--- ---
### Task 8 — Update Architecture documentation ### Task 8 — Update Architecture documentation (✅ completed)
**Priority**: Medium **Priority**: Medium
**Refactoring ref**: Refactoring.md §4 **Refactoring ref**: Refactoring.md §4
@@ -194,7 +194,7 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue.
--- ---
### Task 9 — Add React Error Boundary to the frontend ### Task 9 — Add React Error Boundary to the frontend (✅ completed)
**Priority**: Medium **Priority**: Medium
**Refactoring ref**: Refactoring.md §6 **Refactoring ref**: Refactoring.md §6
@@ -238,7 +238,7 @@ Reference: `Docs/Refactoring.md` for full analysis of each issue.
--- ---
### Task 11 — Create generic `useConfigItem<T>` hook (frontend) ### Task 11 — Create generic `useConfigItem<T>` hook (frontend) (✅ completed)
**Priority**: Low **Priority**: Low
**Refactoring ref**: Refactoring.md §8 **Refactoring ref**: Refactoring.md §8