feat: Implement automated OpenAPI type generation

Add automated type synchronization from backend OpenAPI schema to frontend TypeScript types to prevent type drift and ensure runtime safety.

Changes:
- Add openapi-typescript as dev dependency
- Create npm scripts for type generation (generate:types) and validation (validate:types)
- Integrate type generation into build pipeline (runs before TypeScript compilation)
- Generate frontend/src/types/generated.ts from backend OpenAPI schema
- Add frontend/scripts/validate-types.sh for CI/CD validation
- Update Web-Development.md with type generation workflow documentation
- Update Backend-Development.md with OpenAPI schema sync requirements

Workflow:
1. Backend automatically exposes OpenAPI schema at /api/openapi.json (FastAPI built-in)
2. Frontend build runs 'npm run generate:types' to generate types from schema
3. Generated types are committed to version control
4. CI can run 'npm run validate:types' to fail builds if types drift

Fixes critical type safety issue where frontend types were manually maintained
and could become out of sync with backend Pydantic models.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-04-30 21:00:05 +02:00
parent c4ede71fa6
commit 59c92f9a83
6 changed files with 8962 additions and 2 deletions

View File

@@ -293,10 +293,31 @@ async def get_jails(state: JailServiceStateDep) -> JailListResponse:
# Good — pass db=None on GET so geo_service never commits
result = await geo_service.lookup_batch(ips, http_session, db=None)
# Bad — triggers INSERT + COMMIT per IP inside a GET handler
# Bad — triggers INSERT + COMMIT per GET inside a GET handler
result = await geo_service.lookup_batch(ips, http_session, db=app_db)
```
### OpenAPI Schema Synchronization
**Critical:** The OpenAPI schema is the single source of truth for frontend types. When you add, modify, or remove endpoints or response models:
1. **FastAPI automatically updates the schema** based on your Pydantic models and endpoint definitions.
2. **The frontend regenerates types** from the schema on every build: `npm run generate:types`.
3. **Ensure your Pydantic models are accurate** — they are directly serialized into the schema and used to generate frontend types.
4. **Test type generation locally** before committing:
```bash
cd frontend
npm run generate:types # Generates src/types/generated.ts
npm run build # Build should succeed if types match
```
5. **The backend must be running** for type generation to work (the tool fetches `/api/openapi.json`).
6. **Commit generated types** alongside backend changes — they must always be in sync.
**Never:**
- Manually edit `src/types/generated.ts` on the frontend — regenerate from the schema instead.
- Commit backend changes without ensuring the frontend can regenerate types.
- Assume the OpenAPI schema is correct — validate your Pydantic model's `field` descriptions and types are as intended.
```python
from fastapi import APIRouter, Depends, HTTPException, status
from app.models.jail import JailResponse, JailListResponse
@@ -310,6 +331,7 @@ async def list_jails(service: JailService = Depends()) -> JailListResponse:
return JailListResponse(jails=jails)
```
### Dependency Layering: Enforcing the Repository Boundary
The **repository boundary** separates database-aware code from application logic. This is enforced through dependency injection.

View File

@@ -69,6 +69,50 @@ import type { Ban } from "../types/ban";
---
## 2.5. Generated Types from OpenAPI Schema
**Critical:** Frontend types are automatically generated from the backend's OpenAPI schema to prevent type drift. This ensures frontend types always match the backend's Pydantic models.
### Workflow
1. **Backend exposes OpenAPI schema** at `GET /api/openapi.json` (enabled automatically by FastAPI).
2. **Frontend builds include type generation:**
```bash
npm run generate:types # Generates src/types/generated.ts
npm run build # Automatically calls generate:types first
```
3. **Generated types** (`src/types/generated.ts`) are committed to version control and imported wherever needed.
4. **CI validation** ensures generated types stay in sync with the backend:
```bash
npm run validate:types # Fails if types differ from backend schema
```
### When Backend Models Change
1. Modify the Pydantic model in `backend/app/models/` as needed.
2. Ensure the change is reflected in the OpenAPI schema (FastAPI does this automatically).
3. On the next build, `npm run generate:types` regenerates types from the new schema.
4. The build fails if types differ (pre-commit hook can catch this locally).
5. Commit the updated `src/types/generated.ts` alongside your backend changes.
### CI/CD Integration
Add `npm run validate:types` to your CI pipeline to catch type drift:
```yaml
# GitHub Actions example
- name: Validate types
run: npm run validate:types
```
The script returns:
- **Exit 0:** Types are in sync
- **Exit 1:** Generated types differ (run `npm run generate:types` to fix)
- **Exit 2:** Backend is not accessible (set `BANGUI_BACKEND_URL` if needed)
- **Exit 3:** Type generation failed
---
## 3. Type Safety in API Calls
- Every API call must have a **typed request** and **typed response**.