239 lines
12 KiB
Markdown
239 lines
12 KiB
Markdown
# BanGUI — Refactoring Instructions for AI Agents
|
|
|
|
This document is the single source of truth for any AI agent performing a refactoring task on the BanGUI codebase.
|
|
Read it in full before writing a single line of code.
|
|
The authoritative description of every module, its responsibilities, and the allowed dependency direction is in [Architekture.md](Architekture.md). Always cross-reference it.
|
|
|
|
---
|
|
|
|
## 0. Golden Rules
|
|
|
|
1. **Architecture first.** Every change must comply with the layered architecture defined in [Architekture.md §2](Architekture.md). Dependencies flow inward: `routers → services → repositories`. Never add an import that reverses this direction.
|
|
2. **One concern per file.** Each module has an explicitly stated purpose in [Architekture.md](Architekture.md). Do not add responsibilities to a module that do not belong there.
|
|
3. **No behaviour change.** Refactoring must preserve all existing behaviour. If a function's public signature, return value, or side-effects must change, that is a feature — create a separate task for it.
|
|
4. **Tests stay green.** Run the full test suite (`pytest backend/`) before and after every change. Do not submit work that introduces new failures.
|
|
5. **Smallest diff wins.** Prefer targeted edits. Do not rewrite a file when a few lines suffice.
|
|
|
|
---
|
|
|
|
## 1. Before You Start
|
|
|
|
### 1.1 Understand the project
|
|
|
|
Read the following documents in order:
|
|
|
|
1. [Architekture.md](Architekture.md) — full system overview, component map, module purposes, dependency rules.
|
|
2. [Docs/Backend-Development.md](Backend-Development.md) — coding conventions, testing strategy, environment setup.
|
|
3. [Docs/Tasks.md](Tasks.md) — open issues and planned work; avoid touching areas that have pending conflicting changes.
|
|
|
|
### 1.2 Map the code to the architecture
|
|
|
|
Before editing, locate every file that is in scope:
|
|
|
|
```
|
|
backend/app/
|
|
routers/ HTTP layer — zero business logic
|
|
services/ Business logic — orchestrates repositories + clients
|
|
repositories/ Data access — raw SQL only
|
|
models/ Pydantic schemas
|
|
tasks/ APScheduler jobs
|
|
utils/ Pure helpers, no framework deps
|
|
main.py App factory, lifespan, middleware
|
|
config.py Pydantic settings
|
|
dependencies.py FastAPI Depends() wiring
|
|
|
|
frontend/src/
|
|
api/ Typed fetch wrappers + endpoint constants
|
|
components/ Presentational UI, no API calls
|
|
hooks/ All state, side-effects, API calls
|
|
pages/ Route components — orchestration only
|
|
providers/ React context
|
|
types/ TypeScript interfaces
|
|
utils/ Pure helpers
|
|
```
|
|
|
|
Confirm which layer every file you intend to touch belongs to. If unsure, consult [Architekture.md §2.2](Architekture.md) (backend) or [Architekture.md §3.2](Architekture.md) (frontend).
|
|
|
|
### 1.3 Run the baseline
|
|
|
|
```bash
|
|
# Backend
|
|
pytest backend/ -x --tb=short
|
|
|
|
# Frontend
|
|
cd frontend && npm run test
|
|
```
|
|
|
|
Record the number of passing tests. After refactoring, that number must be equal or higher.
|
|
|
|
---
|
|
|
|
## 2. Backend Refactoring
|
|
|
|
### 2.1 Routers (`app/routers/`)
|
|
|
|
**Allowed content:** request parsing, response serialisation, dependency injection via `Depends()`, delegation to a service, HTTP error mapping.
|
|
**Forbidden content:** SQL queries, business logic, direct use of `fail2ban_client`, any logic that would also make sense in a unit test without an HTTP request.
|
|
|
|
Checklist:
|
|
- [ ] Every handler calls exactly one service method per logical operation.
|
|
- [ ] No `if`/`elif` chains that implement business rules — move these to the service.
|
|
- [ ] No raw SQL or repository imports.
|
|
- [ ] All response models are Pydantic schemas from `app/models/`.
|
|
- [ ] HTTP status codes are consistent with API conventions (200 OK, 201 Created, 204 No Content, 400/422 for client errors, 404 for missing resources, 500 only for unexpected failures).
|
|
|
|
### 2.2 Services (`app/services/`)
|
|
|
|
**Allowed content:** business rules, coordination between repositories and external clients, validation that goes beyond Pydantic, fail2ban command orchestration.
|
|
**Forbidden content:** raw SQL, direct aiosqlite calls, FastAPI `HTTPException` (raise domain exceptions instead and let the router or exception handler convert them).
|
|
|
|
Checklist:
|
|
- [ ] Service classes / functions accept plain Python types or domain models — not `Request` or `Response` objects.
|
|
- [ ] No direct `aiosqlite` usage — go through a repository.
|
|
- [ ] No `HTTPException` — raise a custom domain exception or a plain `ValueError`/`RuntimeError` with a clear message.
|
|
- [ ] No circular imports between services — if two services need each other's logic, extract the shared logic to a utility or a third service.
|
|
|
|
### 2.3 Repositories (`app/repositories/`)
|
|
|
|
**Allowed content:** SQL queries, result mapping to domain models, transaction management.
|
|
**Forbidden content:** business logic, fail2ban calls, HTTP concerns, logging beyond debug-level traces.
|
|
|
|
Checklist:
|
|
- [ ] Every public method accepts a `db: aiosqlite.Connection` parameter — sessions are not managed internally.
|
|
- [ ] Methods return typed domain models or plain Python primitives, never raw `aiosqlite.Row` objects exposed to callers.
|
|
- [ ] No business rules (e.g., no "if this setting is missing, create a default" logic — that belongs in the service).
|
|
|
|
### 2.4 Models (`app/models/`)
|
|
|
|
- Keep **Request**, **Response**, and **Domain** model types clearly separated (see [Architekture.md §2.2](Architekture.md)).
|
|
- Do not use response models as function arguments inside service or repository code.
|
|
- Validators (`@field_validator`, `@model_validator`) belong in models only when they concern data shape, not business rules.
|
|
|
|
### 2.5 Tasks (`app/tasks/`)
|
|
|
|
- Tasks must be thin: fetch inputs → call one service method → log result.
|
|
- Error handling must be inside the task (APScheduler swallows unhandled exceptions — log them explicitly).
|
|
- No direct repository or `fail2ban_client` use; go through a service.
|
|
|
|
### 2.6 Utils (`app/utils/`)
|
|
|
|
- Must have zero framework dependencies (no FastAPI, no aiosqlite imports).
|
|
- Must be pure or near-pure functions.
|
|
- `fail2ban_client.py` is the single exception — it wraps the socket protocol but still has no service-layer logic.
|
|
|
|
### 2.7 Dependencies (`app/dependencies.py`)
|
|
|
|
- This file is the **only** place where service constructors are called and injected.
|
|
- Do not construct services inside router handlers; always receive them via `Depends()`.
|
|
|
|
---
|
|
|
|
## 3. Frontend Refactoring
|
|
|
|
### 3.1 Pages (`src/pages/`)
|
|
|
|
**Allowed content:** composing components and hooks, layout decisions, routing.
|
|
**Forbidden content:** direct `fetch`/`axios` calls, inline business logic, state management beyond what is needed to coordinate child components.
|
|
|
|
Checklist:
|
|
- [ ] All data fetching goes through a hook from `src/hooks/`.
|
|
- [ ] No API function from `src/api/` is called directly inside a page component.
|
|
|
|
### 3.2 Components (`src/components/`)
|
|
|
|
**Allowed content:** rendering, styling, event handlers that call prop callbacks.
|
|
**Forbidden content:** API calls, hook-level state (prefer lifting state to the page or a dedicated hook), direct use of `src/api/`.
|
|
|
|
Checklist:
|
|
- [ ] Components receive all data via props.
|
|
- [ ] Components emit changes via callback props (`onXxx`).
|
|
- [ ] No `useEffect` that calls an API function — that belongs in a hook.
|
|
|
|
### 3.3 Hooks (`src/hooks/`)
|
|
|
|
**Allowed content:** `useState`, `useEffect`, `useCallback`, `useRef`; calls to `src/api/`; local state derivation.
|
|
**Forbidden content:** JSX rendering, Fluent UI components.
|
|
|
|
Checklist:
|
|
- [ ] Each hook has a single, focused concern matching its name (e.g., `useBans` only manages ban data).
|
|
- [ ] Hooks return a stable interface: `{ data, loading, error, refetch }` or equivalent.
|
|
- [ ] Shared logic between hooks is extracted to `src/utils/` (pure) or a parent hook (stateful).
|
|
|
|
### 3.4 API layer (`src/api/`)
|
|
|
|
- `client.ts` is the only place that calls `fetch`. All other api files call `client.ts`.
|
|
- `endpoints.ts` is the single source of truth for URL strings.
|
|
- API functions must be typed: explicit request and response TypeScript interfaces from `src/types/`.
|
|
|
|
### 3.5 Types (`src/types/`)
|
|
|
|
- Interfaces must match the backend Pydantic response schemas exactly (field names, optionality).
|
|
- Do not use `any`. Use `unknown` and narrow with type guards when the shape is genuinely unknown.
|
|
|
|
---
|
|
|
|
## 4. General Code Quality Rules
|
|
|
|
### Naming
|
|
- Python: `snake_case` for variables/functions, `PascalCase` for classes.
|
|
- TypeScript: `camelCase` for variables/functions, `PascalCase` for components and types.
|
|
- File names must match the primary export they contain.
|
|
|
|
### Error handling
|
|
- Backend: raise typed exceptions; map them to HTTP status codes in `main.py` exception handlers or in the router — nowhere else.
|
|
- Frontend: all API call error states are represented in hook return values; never swallow errors silently.
|
|
|
|
### Logging (backend)
|
|
- Use `structlog` with bound context loggers — never bare `print()`.
|
|
- Log at `debug` in repositories, `info` in services for meaningful events, `warning`/`error` in tasks and exception handlers.
|
|
- Never log sensitive data (passwords, session tokens, raw IP lists larger than a handful of entries).
|
|
|
|
### Async correctness (backend)
|
|
- Every function that touches I/O (database, fail2ban socket, HTTP) must be `async def`.
|
|
- Never call `asyncio.run()` inside a running event loop.
|
|
- Do not use `time.sleep()` — use `await asyncio.sleep()`.
|
|
|
|
---
|
|
|
|
## 5. Refactoring Workflow
|
|
|
|
Follow this sequence for every refactoring task:
|
|
|
|
1. **Read** the relevant section of [Architekture.md](Architekture.md) for the files you will touch.
|
|
2. **Run** the full test suite to confirm the baseline.
|
|
3. **Identify** the violation or smell: which rule from this document does it break?
|
|
4. **Plan** the minimal change: what is the smallest edit that fixes the violation?
|
|
5. **Edit** the code. One logical change per commit.
|
|
6. **Verify** imports: nothing new violates the dependency direction.
|
|
7. **Run** the full test suite. All previously passing tests must still pass.
|
|
8. **Update** any affected docstrings or inline comments to reflect the new structure.
|
|
9. **Do not** update `Architekture.md` unless the refactor changes the documented structure — that requires a separate review.
|
|
|
|
---
|
|
|
|
## 6. Common Violations to Look For
|
|
|
|
| Violation | Where it typically appears | Fix |
|
|
|---|---|---|
|
|
| Business logic in a router handler | `app/routers/*.py` | Extract logic to the corresponding service |
|
|
| Direct `aiosqlite` calls in a service | `app/services/*.py` | Move the query into the matching repository |
|
|
| `HTTPException` raised inside a service | `app/services/*.py` | Raise a domain exception; catch and convert it in the router or exception handler |
|
|
| API call inside a React component | `src/components/*.tsx` | Move to a hook; pass data via props |
|
|
| Hardcoded URL string in a hook or component | `src/hooks/*.ts`, `src/components/*.tsx` | Use the constant from `src/api/endpoints.ts` |
|
|
| `any` type in TypeScript | anywhere in `src/` | Replace with a concrete interface from `src/types/` |
|
|
| `print()` statements in production code | `backend/app/**/*.py` | Replace with `structlog` logger |
|
|
| Synchronous I/O in an async function | `backend/app/**/*.py` | Use the async equivalent |
|
|
| A repository method that contains an `if` with a business rule | `app/repositories/*.py` | Move the rule to the service layer |
|
|
|
|
---
|
|
|
|
## 7. Out of Scope
|
|
|
|
Do not make the following changes unless explicitly instructed in a separate task:
|
|
|
|
- Adding new API endpoints or pages.
|
|
- Changing database schema or migration files.
|
|
- Upgrading dependencies.
|
|
- Altering Docker or CI configuration.
|
|
- Modifying `Architekture.md` or `Tasks.md`.
|