feat: Stage 1 — backend and frontend scaffolding

Backend (tasks 1.1, 1.5–1.8):
- pyproject.toml with FastAPI, Pydantic v2, aiosqlite, APScheduler 3.x,
  structlog, bcrypt; ruff + mypy strict configured
- Pydantic Settings (BANGUI_ prefix env vars, fail-fast validation)
- SQLite schema: settings, sessions, blocklist_sources, import_log;
  WAL mode + foreign keys; idempotent init_db()
- FastAPI app factory with lifespan (DB, aiohttp session, scheduler),
  CORS, unhandled-exception handler, GET /api/health
- Fail2BanClient: async Unix-socket wrapper using run_in_executor,
  custom error types, async context manager
- Utility modules: ip_utils, time_utils, constants
- 47 tests; ruff 0 errors; mypy --strict 0 errors

Frontend (tasks 1.2–1.4):
- Vite + React 18 + TypeScript strict; Fluent UI v9; ESLint + Prettier
- Custom brand theme (#0F6CBD, WCAG AA contrast) with light/dark variants
- Typed fetch API client (ApiError, get/post/put/del) + endpoints constants
- tsc --noEmit 0 errors
This commit is contained in:
2026-02-28 21:15:01 +01:00
parent 460d877339
commit 7392c930d6
59 changed files with 7601 additions and 17 deletions

24
frontend/src/main.tsx Normal file
View File

@@ -0,0 +1,24 @@
/**
* Application entry point.
*
* Mounts the root `<App />` component into the `#root` DOM element
* supplied by `index.html`.
*/
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
const rootElement = document.getElementById("root");
if (rootElement === null) {
throw new Error(
"Root element #root not found. Ensure index.html contains <div id='root'></div>."
);
}
createRoot(rootElement).render(
<StrictMode>
<App />
</StrictMode>
);