Loading repository data…
Loading repository data…
fandangolas / repository
High-performance authentication service built with Clean Architecture and CQRS, optimized for extreme read-heavy workloads (1M+ token validations/minute). Features FastAPI + PostgreSQL with functional programming patterns.
A transparent discovery signal based on current public GitHub metadata.
This score does not audit code, security, maintainers, documentation quality, or suitability. Verify the repository and its current documentation before adoption.
Heimdall is an authentication service designed to handle extreme read-heavy workloads typical in banking and financial systems. The project demonstrates a pragmatic blend of functional programming and object-oriented design, optimized for scenarios where token validations vastly outnumber user registrations.
In Norse mythology, Heimdall is the vigilant guardian of Bifrost, the rainbow bridge connecting the realms. He possesses extraordinary senses and can see across all nine worlds, making him the perfect sentinel to detect any threat.
Just like his mythological namesake, our Heimdall stands guard at the gateway of your system, deciding who has permission to enter. With his all-seeing capabilities, Heimdall authenticates and authorizes every request, ensuring only legitimate users gain access to your protected resources.
"None shall pass without Heimdall's approval."
In a typical banking system processing 1,000,000+ operations per minute:
This 1000:1 read/write ratio drove our architectural decisions toward CQRS (Command Query Responsibility Segregation) to optimize for the dominant use case.
We use each paradigm where it's strongest:
| Component | Approach | Reasoning |
|---|---|---|
| Use Cases | 🟡 Functional | Pure transformations, easier testing |
| Value Objects | 🟡 Functional | Immutable data, no identity |
| Domain Events |
| 🟡 Functional |
| Immutable event data, no behavior needed |
| DTOs | 🟡 Functional | Pure data containers for boundaries |
| Entities | 🔵 OOP | Identity + behavior, natural domain modeling |
| Services | 🟡 Functional | Stateless operations, better composition |
| Repositories | 🔵 OOP | Abstract interfaces, familiar patterns |
async def login_user(request, deps) -> responseNamedTuple + factory functionsUserCreated(user_id, email) -> DomainEventValueLoginRequest(email, password) -> LoginRequestValue# Pure function use case
async def login_user(request: LoginRequest, deps: Dependencies) -> LoginResponse:
user = await deps.user_repository.find_by_email(email)
session = user.authenticate(password) # Entity method
return LoginResponse(access_token=token.value)
# Immutable value object
class EmailValue(NamedTuple):
value: str
domain: str
def Email(email_string: str) -> EmailValue:
# Validation + normalization
return EmailValue(value=normalized, domain=domain)
# Entity with identity and behavior
class User:
def authenticate(self, password: Password) -> Session:
if not self.password_hash.verify(password):
raise ValueError("Invalid credentials")
return Session.create_for_user(self.id, self.email, self.permissions)
This hybrid approach gives us immutability where it matters (value objects, use cases) and rich domain models where appropriate (entities with business logic).
The project follows a phased approach to CQRS adoption:
src/
├── heimdall/
│ ├── domain/ # Business rules & entities
│ │ ├── entities/ # User, Session (OOP)
│ │ ├── value_objects/ # Email, Password, Token (Functional)
│ │ ├── events/ # Domain events (Functional)
│ │ └── repositories/ # Abstract interfaces (OOP)
│ │ ├── read_repositories.py # Read-optimized (CQRS)
│ │ └── write_repositories.py # Write-optimized (CQRS)
│ ├── application/ # Use cases & orchestration
│ │ ├── commands/ # Write operations (CQRS - 1% traffic)
│ │ ├── queries/ # Read operations (CQRS - 99% traffic)
│ │ ├── cqrs.py # Unified CQRS facade
│ │ ├── dto/ # Data Transfer Objects (Functional)
│ │ └── services/ # Function composition (Functional)
│ ├── infrastructure/ # External integrations
│ │ └── persistence/ # Data persistence layer
│ │ └── postgres/ # PostgreSQL implementation
│ │ ├── database.py # Connection management
│ │ ├── dependencies.py # PostgreSQL dependencies
│ │ ├── mappers.py # Database ↔ domain mapping
│ │ ├── user_repository.py # User persistence
│ │ └── session_repository.py # Session persistence
│ └── presentation/ # Interface adapters
│ └── api/ # FastAPI application
│ ├── main.py # FastAPI app configuration
│ ├── routes.py # Authentication endpoints
│ ├── dependencies.py # Dynamic dependency injection
│ ├── schemas.py # Pydantic request/response schemas
│ └── health.py # Health check endpoints
└── tests/
├── unit/ # 87 tests - Domain & CQRS logic
└── integration/ # 36 tests - Full-stack API testing
├── aux/ # Test infrastructure utilities
│ ├── api_fixtures.py # FastAPI fixtures (api_client) - pytest_plugins
│ ├── api_helpers.py # Functional API helpers (register_user, etc.)
│ └── postgres_helpers.py # PostgreSQL utilities (connection, cleanup)
└── usecases/ # Organized by CQRS patterns
├── commands/ # Write operation tests (1% traffic)
└── queries/ # Read operation tests (99% traffic)
# Default: Run all test suites (requires PostgreSQL)
make test # 123 tests in ~14s (unit + integration)
# Specific test suites
make test-unit # 87 tests in ~5s (fast feedback)
make test-integration # 36 tests in ~9s (API integration with PostgreSQL)
make test-postgres # Alias for test-integration (PostgreSQL required)
# Development workflows
make quick # Same as test-unit (fast development)
make workflow # Full development pipeline
make ci-test # Complete CI validation
# Unit tests only
PYTHONPATH=src python -m pytest src/tests/unit/ -v
# Integration tests (requires PostgreSQL to be running)
docker-compose up -d postgres # Start PostgreSQL container
PYTHONPATH=src python -m pytest src/tests/integration/ -v
Integration tests require PostgreSQL to be running and use production-like persistence:
# Start PostgreSQL first (required)
docker-compose up -d postgres
# Run integration tests with PostgreSQL
make test-integration
Key Features:
For detailed architectural decisions and trade-offs, see Technical Assessment.
Complete command/query separation with FastAPI presentation layer, optimized for the 100:1 read/write ratio typical in authentication systems.
# FastAPI routes with dependency injection
@router.post("/auth/login")
async def login(
request: LoginRequestSchema,
auth_functions: dict = Depends(get_auth_functions)
) -> LoginResponseSchema:
response = await auth_functions["login"](request.to_domain())
return LoginResponseSchema.from_domain(response)
@router.post("/auth/validate")
async def validate_token(
request: ValidateTokenRequestSchema,
auth_functions: dict = Depends(get_auth_functions)
) -> ValidateTokenResponseSchema:
response = await auth_functions["validate"](request.token)
return ValidateTokenResponseSchema.from_domain(response)
# Create optimized dependencies for commands and queries
command_deps = CommandDependencies(user_repo, session_repo, token_service, event_bus)
query_deps = QueryDependencies(cached_session_repo, token_service) # Minimal deps
# Curry CQRS functions with dependencies baked in
auth_functions = curry_cqrs_functions(command_deps, query_deps)
# Use the curried functions - dependencies already applied
await auth_functions["login"](request) # Write operation (1% traffic)
await auth_functions["validate"](token) # Read operation (99% traffic)
login_user_command, register_user_command, logout_user_command/auth/login, /auth/register, /auth/logout