Files
BanGUI/Docs/Instructions.md

12 KiB

AI Agent — General Instructions

You are an autonomous coding agent working on BanGUI, a web application for monitoring, managing, and configuring fail2ban through a clean web interface. This document defines how you operate, what rules you follow, and which workflow you repeat for every task.

Read this document completely before starting any work.


1. Project Context

BanGUI consists of two main parts:

Layer Stack Docs
Backend Python 3.12+, FastAPI, Pydantic v2, aiosqlite, structlog Backend-Development.md
Frontend TypeScript, React, Fluent UI v9, Vite Web-Development.md

Supporting documentation you must know and respect:

Document Purpose
Features.md Complete feature list and expected behaviour
Architekture.md System architecture, component relationships, data flow
Web-Design.md Visual design rules, theming, layout, spacing, motion
Backend-Development.md Backend coding rules, project structure, conventions
Web-Development.md Frontend coding rules, project structure, conventions

Always consult the relevant document before writing code. If your planned change contradicts any rule defined in those documents, the document wins — adjust your approach.


2. General Rules

2.1 Follow the Docs

  • Every coding convention, naming rule, project structure decision, and library choice is defined in the development docs. Do not deviate.
  • Backend code follows Backend-Development.md — strict typing, async only, structlog, Pydantic models, layered architecture (routers → services → repositories).
  • Frontend code follows Web-Development.md — strict TypeScript, Fluent UI v9 only, makeStyles for styling, typed API calls, hooks for state.
  • Visual decisions follow Web-Design.md — Fluent design tokens, semantic colour slots, 4 px spacing grid, correct elevation and motion.

2.2 Write Production-Quality Code

  • Write code as if it ships today. No TODOs, no placeholders, no half-implementations.
  • Every function has explicit type annotations (Python) or type signatures (TypeScript).
  • Every public function has a docstring (Python — Google style) or JSDoc comment (TypeScript).
  • No any in TypeScript. No Any in Python (unless justified with a comment).
  • No magic numbers or strings — use named constants.
  • No dead code, no commented-out blocks, no unused imports.

2.3 Keep It Small and Focused

  • One function does one thing.
  • One component per file.
  • One service per domain.
  • If a file grows beyond ~150 lines (components) or ~200 lines (services), split it.

2.4 Never Break Existing Code

  • Before changing any file, understand what it does and who depends on it.
  • Run the existing test suite before and after your changes. If tests fail after your change, fix them before moving on.
  • Do not remove or rename public APIs without updating all callers.

2.5 Think Before You Code

  • Read the task description carefully. If it is ambiguous, check Features.md and Architekture.md for clarification.
  • Plan your changes before writing code. Identify which files are affected, which layers are involved, and what tests are needed.
  • Prefer the simplest correct solution. Do not over-engineer.

3. Task Workflow

Repeat the following cycle for every task. Do not skip steps.

Step 1 — Pick a Task

  • Open tasks.md and pick the next unfinished task (highest priority first).
  • Mark the task as in progress.
  • Read the task description thoroughly. Understand the expected outcome before proceeding.

Step 2 — Plan Your Steps

  • Break the task into concrete implementation steps.
  • Identify which files need to be created, modified, or deleted.
  • Identify which layers are affected (router, service, repository, model, component, hook, page, type, etc.).
  • Identify edge cases and error scenarios.
  • Write down your plan before touching any code.

Step 3 — Write Code

Step 4 — Add Logging

  • Add structured log statements at key points in new or modified code.
  • Backend: use structlog with contextual key-value pairs — never print().
  • Log at appropriate levels: info for operational events, warning for recoverable issues, error for failures.
  • Never log sensitive data (passwords, tokens, session IDs).

Step 5 — Write Tests

  • Write tests for every new or changed piece of functionality.
  • Backend: use pytest + pytest-asyncio + httpx.AsyncClient. See Backend-Development.md § 9.
  • Frontend: test components and hooks according to the frontend test setup.
  • Test the happy path and error/edge cases.
  • Mock external dependencies — tests must never touch real infrastructure.
  • Follow the naming pattern: test_<unit>_<scenario>_<expected>.

Step 6 — Review Your Code

Run a thorough self-review before considering the task done. Check all of the following:

6.1 — Warnings and Errors

  • Backend: run ruff check and mypy --strict (or pyright --strict). Fix every warning and error.
  • Frontend: run tsc --noEmit and eslint. Fix every warning and error.
  • Zero warnings, zero errors — no exceptions.

6.2 — Test Coverage

  • Run the test suite with coverage enabled.
  • Aim for >80 % line coverage overall.
  • Critical paths (auth, banning, scheduling, API endpoints) must be 100 % covered.
  • If coverage is below the threshold, write additional tests before proceeding.

6.3 — Coding Principles

Verify your code against the coding principles defined in Backend-Development.md § 13 and Web-Development.md:

  • Clean Code — Meaningful names, small functions, no magic values, guard clauses over deep nesting.
  • Separation of Concerns — Each module has a single, well-defined responsibility. Layers are not mixed.
  • Single Responsibility Principle — Every class and function has one reason to change.
  • DRY — No duplicated logic. Shared behaviour is extracted.
  • KISS — The simplest correct solution is used. No over-engineering.
  • Type Safety — All types are explicit. No any / Any. No # type: ignore without justification.

6.4 — Architecture Compliance

Verify against Architekture.md and the project structure rules:

  • Files are in the correct directories (routers in routers/, services in services/, components in components/, etc.).
  • Dependencies flow in the right direction (routers → services → repositories; pages → components → hooks).
  • No circular imports.
  • No business logic in routers or components.
  • No HTTP/framework concerns in services or repositories.
  • Pydantic models separate request, response, and domain shapes.
  • Frontend types live in types/, not scattered across components.

Step 7 — Update Documentation

  • If your change introduces new features, new endpoints, new components, or changes existing behaviour, update the relevant docs:
  • Keep documentation accurate and in sync with the code. Outdated docs are worse than no docs.

Step 8 — Mark Task Complete

  • Open tasks.md and mark the task as done.
  • Add a brief summary of what was implemented or changed.

Step 9 — Commit

  • Stage all changed files.
  • Write a commit message in imperative tense, max 72 characters for the subject line.
    • Good: Add jail reload endpoint
    • Bad: added stuff / WIP / fix
  • If the change is large, include a body explaining why, not just what.
  • Branch naming: feature/<short-description>, fix/<short-description>, chore/<short-description>.
  • Ensure the commit passes: linter, type checker, all tests.

Step 10 — Next Task

  • Return to Step 1 and pick the next task.

4. Workflow Summary

┌─────────────────────────────────────────┐
│  1. Pick task from tasks.md             │
│  2. Plan your steps                     │
│  3. Write code                          │
│  4. Add logging                         │
│  5. Write tests                         │
│  6. Review your code                    │
│     ├── 6.1  Check warnings & errors    │
│     ├── 6.2  Check test coverage        │
│     ├── 6.3  Check coding principles    │
│     └── 6.4  Check architecture         │
│  7. Update documentation if needed      │
│  8. Mark task complete in tasks.md      │
│  9. Git commit                          │
│ 10. Pick next task ──────── loop ───┐   │
│         ▲                           │   │
│         └───────────────────────────┘   │
└─────────────────────────────────────────┘

5. When You Are Stuck

  • Re-read the task description and the relevant docs.
  • Search the existing codebase for similar patterns — follow established conventions.
  • Check the fail2ban source code in fail2ban-master/ if you need to understand how fail2ban works internally.
  • If a decision is genuinely ambiguous and no document covers it, choose the simplest option that is consistent with existing code and document your reasoning in a code comment.

6. What You Must Never Do

  • Never commit code that does not compile or has type errors.
  • Never commit code without tests.
  • Never use libraries that are explicitly forbidden in the development docs.
  • Never bypass the linter or type checker with blanket ignores.
  • Never hard-code secrets, passwords, or tokens.
  • Never push directly to main — always use feature branches.
  • Never skip the review step — sloppy code compounds over time.
  • Never leave a task half-done — finish it or revert it.

7. Dev Quick-Reference

Start / stop the stack

make up      # start all containers (from repo root)
make down    # stop all containers
make logs    # tail logs

Backend: http://127.0.0.1:8000 · Frontend (Vite proxy): http://127.0.0.1:5173

API login (dev)

The frontend SHA256-hashes the password before sending it to the API.
The session cookie is named bangui_session.

# Dev master password: Hallo123!
HASHED=$(echo -n "Hallo123!" | sha256sum | awk '{print $1}')
TOKEN=$(curl -s -X POST http://127.0.0.1:8000/api/auth/login \
  -H 'Content-Type: application/json' \
  -d "{\"password\":\"$HASHED\"}" \
  | python3 -c 'import sys,json; print(json.load(sys.stdin)["token"])')

# Use token in subsequent requests:
curl -H "Cookie: bangui_session=$TOKEN" http://127.0.0.1:8000/api/dashboard/status