Architecture Overview¶
Last Updated: 2025-11-25
System Architecture¶
This FastAPI application implements a dual-protocol API server supporting both HTTP REST and WebSocket connections with centralized authentication and authorization.
High-Level Architecture¶
graph TB
subgraph "Client Layer"
HTTP[HTTP Clients<br/>REST API calls]
WS[WebSocket Clients<br/>Real-time bidirectional]
end
subgraph "Protocol Layer"
HTTPEndpoints[HTTP Endpoints<br/>- /authors<br/>- /health<br/>- FastAPI routers]
WSEndpoint[WebSocket Endpoint<br/>- /web<br/>- Connection auth<br/>- Message routing<br/>- PackageRouter dispatch]
end
subgraph "Middleware Layer"
Auth[AuthenticationMiddleware<br/>Keycloak JWT validation]
RBAC[require_roles dependency<br/>RBAC permission checking]
end
subgraph "Business Logic Layer"
HTTPHandlers[HTTP Handlers<br/>app/api/http/]
WSHandlers[WebSocket Handlers<br/>app/api/ws/handlers/<br/>@pkg_router.register]
end
subgraph "Managers & Services"
RBACMgr[RBACManager<br/>permission checking]
KCMgr[KeycloakManager<br/>authentication]
ConnMgr[ConnectionManager<br/>WebSocket connections]
PkgRouter[PackageRouter<br/>WebSocket routing]
end
subgraph "Data Layer"
DB[(PostgreSQL<br/>SQLModel/SQLAlchemy<br/>Async operations)]
Redis[(Redis Cache<br/>Session management<br/>Pub/Sub)]
end
HTTP --> HTTPEndpoints
WS --> WSEndpoint
HTTPEndpoints --> Auth
WSEndpoint --> Auth
Auth --> RBAC
RBAC --> HTTPHandlers
RBAC --> WSHandlers
HTTPHandlers --> RBACMgr
HTTPHandlers --> KCMgr
WSHandlers --> ConnMgr
WSHandlers --> PkgRouter
RBACMgr --> DB
KCMgr --> Redis
ConnMgr --> Redis
PkgRouter --> DB
style HTTP fill:#e1f5ff
style WS fill:#e1f5ff
style HTTPEndpoints fill:#fff3cd
style WSEndpoint fill:#fff3cd
style Auth fill:#d4edda
style RBAC fill:#d4edda
style HTTPHandlers fill:#cce5ff
style WSHandlers fill:#cce5ff
style DB fill:#f8d7da
style Redis fill:#f8d7da Core Components¶
1. Request Flow¶
HTTP Request Flow¶
flowchart TD
A[Client Request] --> B[AuthenticationMiddleware<br/>validates JWT]
B --> C[require_roles dependency<br/>checks RBAC permissions]
C --> D[HTTP Handler<br/>app/api/http/]
D --> E[Database/Redis<br/>operations]
E --> F[Response to Client]
style A fill:#e1f5ff
style B fill:#d4edda
style C fill:#d4edda
style D fill:#cce5ff
style E fill:#f8d7da
style F fill:#e1f5ff WebSocket Request Flow¶
flowchart TD
A[Client Connection] --> B[PackageAuthWebSocketEndpoint<br/>validates JWT from query params]
B --> C[Connection Established]
C --> D[Client sends JSON message<br/>pkg_id, req_id, data]
D --> E[PackageRouter.handle_request]
E --> F[Validation Pipeline]
F --> G[1. Validate request format]
G --> H[2. Check RBAC permissions<br/>RBACManager]
H --> I[3. Validate data<br/>JSON schema]
I --> J[4. Dispatch to<br/>registered handler]
J --> K[Handler processes request]
K --> L[Response Model<br/>pkg_id, req_id, status_code, data]
L --> M[Send to client via WebSocket]
style A fill:#e1f5ff
style B fill:#d4edda
style C fill:#fff3cd
style D fill:#e1f5ff
style E fill:#cce5ff
style F fill:#cce5ff
style G fill:#cce5ff
style H fill:#d4edda
style I fill:#cce5ff
style J fill:#cce5ff
style K fill:#cce5ff
style L fill:#fff3cd
style M fill:#e1f5ff 2. Authentication System¶
Provider: Keycloak (OpenID Connect / OAuth 2.0)
Components: - app/auth.py - Authentication backend for Starlette - app/managers/keycloak_manager.py - Keycloak client wrapper - app/schemas/user.py - User model with roles
Token Flow: 1. User authenticates with Keycloak (username/password or SSO) 2. Keycloak returns JWT access token 3. Client includes token in requests: - HTTP: Authorization: Bearer <token> header - WebSocket: ?Authorization=Bearer <token> query parameter 4. AuthBackend.authenticate() validates and decodes JWT 5. User object with roles attached to request context
Configuration (see app/settings.py): - KEYCLOAK_REALM - Keycloak realm name - KEYCLOAK_CLIENT_ID - OAuth client ID - KEYCLOAK_BASE_URL - Keycloak server URL - EXCLUDED_PATHS - Paths that bypass authentication (e.g., /health)
3. Authorization (RBAC)¶
Current Implementation: Decorator-based roles defined in code
Components: - app/managers/rbac_manager.py - Permission checking logic - app/dependencies/permissions.py - FastAPI dependency for HTTP endpoints - app/routing.py - PackageRouter with permissions registry
Permission Definition:
WebSocket Handlers:
@pkg_router.register(
PkgID.GET_AUTHORS,
json_schema=GetAuthorsModel,
roles=["get-authors"] # Permissions defined here
)
async def get_authors_handler(request: RequestModel) -> ResponseModel:
...
HTTP Endpoints:
from app.dependencies.permissions import require_roles
@router.get(
"/authors",
dependencies=[Depends(require_roles("get-authors"))]
)
async def get_authors():
...
Permission Checking: - WebSocket: RBACManager.check_ws_permission(pkg_id, user) - reads from pkg_router.permissions_registry - HTTP: require_roles(*roles) FastAPI dependency - Default policy: If no roles specified = public access
4. Middleware Stack¶
The application uses a comprehensive middleware stack for cross-cutting concerns. Middlewares process requests and responses in order:
Middleware Execution Order (configured in app/__init__.py):
- TrustedHostMiddleware - Validates Host header against allowed hosts
- Prevents Host header injection attacks
-
Configured via
ALLOWED_HOSTSsetting -
AuthenticationMiddleware (Starlette) - JWT token validation
- Uses
AuthBackend.authenticate()to decode and validate Keycloak tokens - Attaches
UserModelwith roles to request context -
Respects
EXCLUDED_PATHSfor public endpoints -
CorrelationIDMiddleware - Adds X-Correlation-ID for distributed tracing
- Generates UUID v4 if client doesn't provide correlation ID
-
Propagates through logs, audit logs, and metrics
-
LoggingContextMiddleware - Enriches logs with request context
- Adds request_id, user_id, endpoint, method, ip_address to all logs
- Uses contextvars for thread-safe propagation
-
Enables querying logs by correlation ID in Grafana Loki
-
AuditMiddleware - Records user actions for compliance
- Captures request/response metadata (method, path, status, duration)
- Extracts user info from authenticated requests
- Async queue-based processing (non-blocking)
-
Sends to
audit_loggerfor batch database writes -
RequestSizeLimitMiddleware - Protects against large payload attacks
- Checks Content-Length before processing
-
Returns 413 Payload Too Large if exceeds
MAX_REQUEST_BODY_SIZE(1MB default) -
SecurityHeadersMiddleware - Adds security headers
- X-Frame-Options, X-Content-Type-Options, X-XSS-Protection
- Strict-Transport-Security, Content-Security-Policy
-
See Security Guide for details
-
RateLimitMiddleware - Rate limiting for HTTP endpoints
- Redis-based sliding window algorithm
- Returns 429 Too Many Requests when limits exceeded
-
Adds X-RateLimit-* headers to responses
-
PrometheusMiddleware - Metrics collection
- Tracks http_requests_total, http_request_duration_seconds
- http_requests_in_progress gauge
Middleware Architecture Benefits: - Separation of Concerns: Each middleware handles one responsibility - Reusability: Same middleware for all HTTP endpoints - Ordering Control: Execution order defined in application factory - Testability: Each middleware can be tested independently
See Also: - CLAUDE.md - Detailed middleware documentation - Security Guide - Security middleware configuration
5. WebSocket Package Router¶
Purpose: Route WebSocket messages to appropriate handlers based on package ID (PkgID).
Key Files: - app/routing.py - PackageRouter class - app/api/ws/constants.py - PkgID enum definitions - app/api/ws/handlers/ - Handler implementations
Handler Registration:
@pkg_router.register(
PkgID.GET_AUTHORS,
json_schema=GetAuthorsModel,
validator_callback=validator,
roles=["get-authors"] # Permission specification
)
async def get_authors_handler(request: RequestModel) -> ResponseModel:
# Handler implementation
pass
Request/Response Format: - Request: {"pkg_id": 1, "req_id": "uuid", "data": {...}} - Response: {"pkg_id": 1, "req_id": "uuid", "status_code": 0, "data": {...}, "meta": null}
Features: - Automatic JSON schema validation - RBAC permission checking - Request/response correlation via req_id - Error handling with status codes
5. Database Layer¶
Technology: PostgreSQL with async SQLModel/SQLAlchemy
Configuration (see app/storage/db.py): - Connection pooling (configurable pool size) - Async operations (asyncpg driver) - Automatic retry on connection failure
Models: app/models/ - Inherit from SQLModel with table=True - Support async operations - Class methods for common operations
Pagination Helper:
results, meta = await get_paginated_results(
Author,
page=1,
per_page=20,
filters={"status": "active"}
)
6. Connection Management¶
WebSocket Connections: app/managers/websocket_connection_manager.py - Track active connections - Broadcast to all connected clients - Automatic cleanup on disconnect
Redis Sessions: app/storage/redis.py - Session storage - Pub/sub for cross-instance communication - Connection pooling
7. Background Tasks¶
Location: app/tasks/
Current Tasks: - kc_user_session_task - Monitor Keycloak session expiration via Redis pub/sub
Management: - Started in app startup handler - Graceful shutdown on app termination - Tracked in global tasks list
Design Patterns¶
Singleton Pattern¶
Used for managers that should have single instance: - RBACManager - KeycloakManager - Implemented via SingletonMeta metaclass
Decorator Pattern¶
Used for handler registration and enhancement: - @pkg_router.register() - WebSocket handler registration - @router.get/post() - HTTP endpoint registration - Proposed: @require_roles() for inline permission declarations
Repository Pattern¶
Models encapsulate data access: - Class methods for CRUD operations - Async session management - Filter support
Configuration Management¶
File: app/settings.py
Technology: Pydantic Settings (loads from environment variables)
Key Settings: - Database connection parameters - Keycloak configuration - Redis connection - Pool sizes and timeouts - Debug flags (development only)
Security Considerations¶
Current Security Measures¶
- ✅ JWT-based authentication via Keycloak
- ✅ RBAC for endpoint authorization
- ✅ Comprehensive middleware stack (9 middlewares)
- ✅ Security headers (CSP, X-Frame-Options, HSTS, etc.)
- ✅ Rate limiting (HTTP and WebSocket)
- ✅ Request size limits (1MB default, configurable)
- ✅ Host header validation (prevents injection attacks)
- ✅ IP spoofing protection (trusted proxy validation)
- ✅ Excluded paths for public endpoints
- ✅ WebSocket authentication on connection
- ✅ Audit logging for compliance
Resilience Patterns¶
Circuit Breaker Pattern (see Circuit Breaker Guide):
The application implements circuit breaker pattern for external service dependencies to prevent cascading failures:
Protected Services: - Keycloak: Authentication service - Fail-fast when Keycloak is unavailable - Prevents thread exhaustion from connection timeouts - Configurable: KEYCLOAK_CIRCUIT_BREAKER_FAIL_MAX (default: 5), KEYCLOAK_CIRCUIT_BREAKER_TIMEOUT (default: 60s)
- Redis: Caching and rate limiting
- Graceful degradation when Redis is down
- Configurable:
REDIS_CIRCUIT_BREAKER_FAIL_MAX(default: 3),REDIS_CIRCUIT_BREAKER_TIMEOUT(default: 30s)
Circuit Breaker States: - Closed (0): Normal operation, requests pass through - Open (1): Service failing, requests fail fast (no retry) - Half-Open (2): Testing if service recovered
Monitoring: - Prometheus metrics: circuit_breaker_state, circuit_breaker_failures_total, circuit_breaker_state_changes_total - Grafana dashboards: Panels 28-30 visualize circuit breaker health - Alerts: CircuitBreakerOpen (critical), CircuitBreakerFlapping (warning)
Benefits: - Prevents resource exhaustion during outages - Allows services to recover without continued load - Provides clear visibility into service health - Reduces mean time to detection (MTTD) for outages
Known Issues¶
- All major security and resilience features implemented
- Regular security audits recommended
- Monitor Prometheus alerts for circuit breaker state
Performance Considerations¶
Current Optimizations¶
- Async I/O throughout
- Database connection pooling
- Redis for caching and sessions
- Singleton managers
Potential Improvements¶
- Database query optimization (pagination)
- WebSocket broadcast concurrency
- Redis connection pool tuning
- Response caching
Scalability¶
Current Limitations¶
- Single-instance architecture (WebSocket state)
- No load balancing strategy
- File-based RBAC configuration
Future Enhancements¶
- Multi-instance with Redis pub/sub
- Database-backed RBAC for runtime updates
- Distributed session management
- Horizontal scaling with load balancer
Testing Strategy¶
Test Files: tests/
Current Coverage: ~57% (4 of 7 API files)
Test Types: - Unit tests (handlers, managers) - Integration tests (marked with @pytest.mark.integration) - Mock-based authentication tests - Real Keycloak authentication tests
See: Testing Guide
Deployment¶
Dependencies¶
- Python 3.13+
- PostgreSQL 12+
- Redis 6+
- Keycloak 20+
Environment¶
- Docker Compose for local development
- Environment variables for configuration
- Health check endpoint for monitoring
Startup Process¶
- Load settings from environment
- Initialize database connection
- Wait for database availability
- Register WebSocket handlers
- Register HTTP routers
- Start background tasks
- Start server
Related Documentation¶
- RBAC System - Role-based access control implementation
- Design Patterns - Repository + Command + DI patterns
- Request Flow - Detailed sequence diagrams
- Testing Guide - How to test the application
- Authentication Guide - Working with Keycloak
Diagrams¶
Component Interaction¶
graph TD
Client[Client]
FastAPI[FastAPI<br/>Application]
Keycloak[Keycloak<br/>Auth]
PostgreSQL[PostgreSQL<br/>DB]
Redis[Redis<br/>Cache]
Managers[Managers<br/>RBAC, Keycloak]
Client --> FastAPI
FastAPI --> Keycloak
FastAPI --> PostgreSQL
FastAPI --> Redis
FastAPI --> Managers
style Client fill:#e1f5ff,stroke:#333,stroke-width:2px
style FastAPI fill:#f9f,stroke:#333,stroke-width:3px
style Keycloak fill:#ffe1f5,stroke:#333,stroke-width:2px
style PostgreSQL fill:#e1ffe1,stroke:#333,stroke-width:2px
style Redis fill:#ffe1e1,stroke:#333,stroke-width:2px
style Managers fill:#fff4e1,stroke:#333,stroke-width:2px Maintenance¶
Code Organization: - Follow existing package structure - Keep handlers thin (business logic in services/managers) - Use type hints throughout - Maintain 80%+ docstring coverage
Adding New Features: 1. Define models in app/models/ 2. Create schemas in app/schemas/ 3. Implement handlers in app/api/http/ or app/api/ws/handlers/ 4. Specify required roles in handler decorators (WebSocket: roles=[], HTTP: require_roles()) 5. Write tests in tests/ 6. Update documentation