Skip to content

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):

  1. TrustedHostMiddleware - Validates Host header against allowed hosts
  2. Prevents Host header injection attacks
  3. Configured via ALLOWED_HOSTS setting

  4. AuthenticationMiddleware (Starlette) - JWT token validation

  5. Uses AuthBackend.authenticate() to decode and validate Keycloak tokens
  6. Attaches UserModel with roles to request context
  7. Respects EXCLUDED_PATHS for public endpoints

  8. CorrelationIDMiddleware - Adds X-Correlation-ID for distributed tracing

  9. Generates UUID v4 if client doesn't provide correlation ID
  10. Propagates through logs, audit logs, and metrics

  11. LoggingContextMiddleware - Enriches logs with request context

  12. Adds request_id, user_id, endpoint, method, ip_address to all logs
  13. Uses contextvars for thread-safe propagation
  14. Enables querying logs by correlation ID in Grafana Loki

  15. AuditMiddleware - Records user actions for compliance

  16. Captures request/response metadata (method, path, status, duration)
  17. Extracts user info from authenticated requests
  18. Async queue-based processing (non-blocking)
  19. Sends to audit_logger for batch database writes

  20. RequestSizeLimitMiddleware - Protects against large payload attacks

  21. Checks Content-Length before processing
  22. Returns 413 Payload Too Large if exceeds MAX_REQUEST_BODY_SIZE (1MB default)

  23. SecurityHeadersMiddleware - Adds security headers

  24. X-Frame-Options, X-Content-Type-Options, X-XSS-Protection
  25. Strict-Transport-Security, Content-Security-Policy
  26. See Security Guide for details

  27. RateLimitMiddleware - Rate limiting for HTTP endpoints

  28. Redis-based sliding window algorithm
  29. Returns 429 Too Many Requests when limits exceeded
  30. Adds X-RateLimit-* headers to responses

  31. PrometheusMiddleware - Metrics collection

  32. Tracks http_requests_total, http_request_duration_seconds
  33. 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

  1. Load settings from environment
  2. Initialize database connection
  3. Wait for database availability
  4. Register WebSocket handlers
  5. Register HTTP routers
  6. Start background tasks
  7. Start server

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