refactor: Make service dependencies explicit and injectable

Remove hidden cross-service coupling by making dependencies explicit through
dependency injection while maintaining backward compatibility via lazy imports.

Key changes:
- history_service and ban_service: Removed direct module-level imports of
  fail2ban_metadata_service, added optional service parameters to functions
- Added get_fail2ban_metadata_service() provider to dependencies.py
- Updated history router to inject Fail2BanMetadataService dependency
- history_service functions now use lazy imports in fallback paths for
  backward compatibility when service is not explicitly injected
- All test patches updated to use internal _get_fail2ban_db_path() helper
- jail_config_service and jail_service already follow best practices

This pattern prevents circular imports, makes services testable via explicit
mocking, and documents service dependencies clearly.

Fixes: Instructions.md #2 - Hidden cross-service coupling

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-27 18:26:08 +02:00
parent bc315b936b
commit 3bbf413c55
12 changed files with 342 additions and 100 deletions

View File

@@ -1,26 +1,3 @@
## 1) Broad exception catching in backend services
- Where found:
- [backend/app/services/ban_service.py](backend/app/services/ban_service.py)
- [backend/app/services/geo_cache.py](backend/app/services/geo_cache.py)
- [backend/app/services/blocklist_service.py](backend/app/services/blocklist_service.py)
- Why this is needed:
- Catching broad Exception hides root causes and weakens operational debugging.
- Goal:
- Replace broad catches with targeted exception handling and predictable failure paths.
- What to do:
- Inventory each broad catch.
- Replace with explicit exception classes.
- Keep one top-level safety catch only where unavoidable, with full context logging.
- Possible traps and issues:
- Over-tightening catches can expose previously hidden runtime failures.
- Docs changes needed:
- Add service error-handling policy and allowed catch patterns.
- Doc references:
- [Docs/Backend-Development.md](Docs/Backend-Development.md)
- https://docs.python.org/3/tutorial/errors.html
---
## 2) Hidden cross-service coupling (service imports service)
- Where found:
- [backend/app/services/jail_service.py](backend/app/services/jail_service.py)
@@ -43,6 +20,7 @@
- [Docs/Backend-Development.md](Docs/Backend-Development.md)
---
## 3) Blocklist import flow mixes too many responsibilities
- Where found:
- [backend/app/services/blocklist_service.py](backend/app/services/blocklist_service.py)
@@ -62,6 +40,7 @@
- [Docs/Features.md](Docs/Features.md)
---
## 4) Module-level mutable runtime flags in service layer
- Where found:
- [backend/app/services/jail_service.py](backend/app/services/jail_service.py)
@@ -80,6 +59,7 @@
- [Docs/Architekture.md](Docs/Architekture.md)
---
## 5) Inconsistent domain exception contracts across services
- Where found:
- [backend/app/routers/jails.py](backend/app/routers/jails.py)
@@ -101,6 +81,7 @@
- [Docs/Backend-Development.md](Docs/Backend-Development.md)
---
## 6) Raw DB connection exposed as dependency for all routes
- Where found:
- [backend/app/dependencies.py](backend/app/dependencies.py)
@@ -119,6 +100,7 @@
- [Docs/Backend-Development.md](Docs/Backend-Development.md)
---
## 7) Service layer coupled to response/presentation models
- Where found:
- [backend/app/services/ban_service.py](backend/app/services/ban_service.py)
@@ -137,6 +119,7 @@
- [Docs/Architekture.md](Docs/Architekture.md)
---
## 8) Inconsistent modeling style (TypedDict vs Pydantic)
- Where found:
- [backend/app/services/jail_service.py](backend/app/services/jail_service.py)
@@ -156,6 +139,7 @@
- [Docs/Backend-Development.md](Docs/Backend-Development.md)
---
## 9) Repository protocol coverage is incomplete
- Where found:
- [backend/app/repositories/protocols.py](backend/app/repositories/protocols.py)
@@ -175,6 +159,7 @@
- [Docs/Backend-Development.md](Docs/Backend-Development.md)
---
## 10) Startup sequence depends on implicit ordering
- Where found:
- [backend/app/startup.py](backend/app/startup.py)
@@ -193,6 +178,7 @@
- [Docs/Architekture.md](Docs/Architekture.md)
---
## 11) Logging semantics are inconsistent across backend modules
- Where found:
- [backend/app/services](backend/app/services)
@@ -212,6 +198,7 @@
- [Docs/Backend-Development.md](Docs/Backend-Development.md)
---
## 12) Prop drilling in jail overview page
- Where found:
- [frontend/src/pages/jails/JailOverviewSection.tsx](frontend/src/pages/jails/JailOverviewSection.tsx)
@@ -231,6 +218,7 @@
- [Docs/Web-Development.md](Docs/Web-Development.md)
---
## 13) Config page is over-centralized
- Where found:
- [frontend/src/pages/ConfigPage.tsx](frontend/src/pages/ConfigPage.tsx)
@@ -249,6 +237,7 @@
- [Docs/Web-Development.md](Docs/Web-Development.md)
---
## 14) Error boundary granularity is too coarse
- Where found:
- [frontend/src/App.tsx](frontend/src/App.tsx)
@@ -269,6 +258,7 @@
- https://react.dev/reference/react/Component#catching-rendering-errors-with-an-error-boundary
---
## 15) Fragmented async error UX handling in components
- Where found:
- [frontend/src/pages/jails/BanUnbanForm.tsx](frontend/src/pages/jails/BanUnbanForm.tsx)
@@ -288,6 +278,7 @@
- [Docs/Web-Development.md](Docs/Web-Development.md)
---
## 16) API usage pattern is inconsistent across components/hooks
- Where found:
- [frontend/src/pages/JailsPage.tsx](frontend/src/pages/JailsPage.tsx)
@@ -307,6 +298,7 @@
- [Docs/Web-Development.md](Docs/Web-Development.md)
---
## 17) Weak typed error contracts in generic hooks
- Where found:
- [frontend/src/hooks/useListData.ts](frontend/src/hooks/useListData.ts)
@@ -326,6 +318,7 @@
- [frontend/src/api/client.ts](frontend/src/api/client.ts)
---
## 18) Duplicate polling/list loading behavior across hooks
- Where found:
- [frontend/src/hooks/useListData.ts](frontend/src/hooks/useListData.ts)
@@ -344,6 +337,7 @@
- [Docs/Web-Development.md](Docs/Web-Development.md)
---
## 19) Provider dependency chain is implicit
- Where found:
- [frontend/src/App.tsx](frontend/src/App.tsx)
@@ -362,6 +356,7 @@
- [Docs/Web-Development.md](Docs/Web-Development.md)
---
## 20) Loading UX lacks progressive/skeleton states
- Where found:
- [frontend/src/pages](frontend/src/pages)
@@ -379,6 +374,7 @@
- [Docs/Web-Design.md](Docs/Web-Design.md)
---
## 21) Silent auth error swallow in fetch error utility
- Where found:
- [frontend/src/utils/fetchError.ts](frontend/src/utils/fetchError.ts)
@@ -396,6 +392,7 @@
- [frontend/src/providers/AuthProvider.tsx](frontend/src/providers/AuthProvider.tsx)
---
## 22) Magic strings are scattered in frontend storage keys
- Where found:
- [frontend/src/providers/AuthProvider.tsx](frontend/src/providers/AuthProvider.tsx)
@@ -415,6 +412,7 @@
- [frontend/src/utils/constants.ts](frontend/src/utils/constants.ts)
---
## 23) No global cancellation policy on route transitions
- Where found:
- [frontend/src/hooks](frontend/src/hooks)
@@ -432,6 +430,7 @@
- [Docs/Web-Development.md](Docs/Web-Development.md)
---
## 24) API response wrapper shape is inconsistent
- Where found:
- [backend/app/routers/dashboard.py](backend/app/routers/dashboard.py)
@@ -452,6 +451,7 @@
- [Docs/Backend-Development.md](Docs/Backend-Development.md)
---
## 25) No canonical snake_case/camelCase serialization policy
- Where found:
- [backend/app/models/server.py](backend/app/models/server.py)
@@ -471,6 +471,7 @@
- https://docs.pydantic.dev/latest/concepts/alias/
---
## 26) Pagination contract is not standardized across endpoints
- Where found:
- [backend/app/routers/dashboard.py](backend/app/routers/dashboard.py)
@@ -490,6 +491,7 @@
- [Docs/Backend-Development.md](Docs/Backend-Development.md)
---
## 27) Error response body shape is inconsistent
- Where found:
- [backend/app/main.py](backend/app/main.py)
@@ -509,6 +511,7 @@
- [Docs/Backend-Development.md](Docs/Backend-Development.md)
---
## 28) Login failure delay can enable app-layer DoS
- Where found:
- [backend/app/routers/auth.py](backend/app/routers/auth.py#L110)
@@ -526,6 +529,7 @@
- [backend/app/utils/rate_limiter.py](backend/app/utils/rate_limiter.py)
---
## 29) Blocklist URL validation has DNS-rebinding window
- Where found:
- [backend/app/utils/ip_utils.py](backend/app/utils/ip_utils.py#L145)
@@ -545,6 +549,7 @@
- https://cheatsheetseries.owasp.org/cheatsheets/Server_Side_Request_Forgery_Prevention_Cheat_Sheet.html
---
## 30) Setup persistence is non-atomic across DB contexts
- Where found:
- [backend/app/services/setup_service.py](backend/app/services/setup_service.py)
@@ -563,6 +568,7 @@
- [Docs/Architekture.md](Docs/Architekture.md)
---
## 31) Fire-and-forget reschedule may fail silently
- Where found:
- [backend/app/tasks/blocklist_import.py](backend/app/tasks/blocklist_import.py#L108)
@@ -580,6 +586,7 @@
- [Docs/Features.md](Docs/Features.md)
---
## 32) RateLimiter cleanup function is not scheduled/used
- Where found:
- [backend/app/utils/rate_limiter.py](backend/app/utils/rate_limiter.py#L84)
@@ -598,6 +605,7 @@
- [backend/app/utils/rate_limiter.py](backend/app/utils/rate_limiter.py)
---
## 33) Trusted proxy configuration is hardcoded in auth router
- Where found:
- [backend/app/routers/auth.py](backend/app/routers/auth.py#L46)
@@ -617,6 +625,7 @@
- [Docs/Instructions.md](Docs/Instructions.md)
---
## 34) Setup redirect allowlist uses broad prefix matching
- Where found:
- [backend/app/main.py](backend/app/main.py#L434)
@@ -634,6 +643,7 @@
- [backend/app/main.py](backend/app/main.py)
---
## 35) API client sends JSON and CSRF header for every request method
- Where found:
- [frontend/src/api/client.ts](frontend/src/api/client.ts)
@@ -652,6 +662,7 @@
- [backend/app/middleware/csrf.py](backend/app/middleware/csrf.py)
---
## 36) Polling continues when tab is not visible
- Where found:
- [frontend/src/hooks/usePolledData.ts](frontend/src/hooks/usePolledData.ts#L90)
@@ -670,6 +681,7 @@
- [Docs/Web-Development.md](Docs/Web-Development.md)
---
## 37) Multi-worker safety check depends on one environment variable
- Where found:
- [backend/app/startup.py](backend/app/startup.py#L61)
@@ -687,6 +699,7 @@
- [Docs/Architekture.md](Docs/Architekture.md)
---
## 38) History archive query paths may need explicit indexing plan
- Where found:
- [backend/app/db.py](backend/app/db.py)
@@ -707,6 +720,7 @@
- https://www.sqlite.org/queryplanner.html
---
## 39) No explicit DI container strategy for backend service graph
- Where found:
- [backend/app/dependencies.py](backend/app/dependencies.py)
@@ -725,6 +739,7 @@
- [Docs/Architekture.md](Docs/Architekture.md)
---
## 40) Frontend and backend observability are not aligned
- Where found:
- [backend/app/main.py](backend/app/main.py)
@@ -741,4 +756,4 @@
- Add observability and privacy-safe logging guidelines.
- Doc references:
- [Docs/Architekture.md](Docs/Architekture.md)
- [Docs/Web-Development.md](Docs/Web-Development.md)
- [Docs/Web-Development.md](Docs/Web-Development.md)