Skip to main content

Architecture Overview

This document provides a high-level overview of the Heimdall platform architecture.

System Architecture

┌──────────────────────────────────────────────────────────────────────────────────┐
│ Internet │
├──────────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Client │ │ Backend │ │ ID │ │ Policies │ │ Docs │ │
│ │ Apps │ │ (Next.js)│ │ (Next.js)│ │ (Next.js)│ │(Docusaur)│ │
│ │ (REST/WS)│ │ :3001 │ │ :3002 │ │ :3004 │ │ :3003 │ │
│ └────┬─────┘ └────┬─────┘ └────┬─────┘ └──────────┘ └──────────┘ │
│ │ │ │ │
│ │ HTTPS │ HTTPS │ HTTPS │
│ │ WebSocket │ GraphQL │ OAuth │
│ │ │ REST │ │
│ │ │ │ │
│ ┌────┴─────────────┴─────────────┴──────────────────────────────────────┐ │
│ │ Load Balancer │ │
│ │ (nginx / cloud LB) │ │
│ └───────────────────────────────┬────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────┐ ┌─────────────┐│ ┌─────────────┐ │
│ │ Discord Bot │ │ Twitch Bot ││ │ YouTube Bot │ │
│ │ (Rust) │ │ (Rust) ││ │ (Rust) │ ◄── Bots (Rust) │
│ │ :3006 │ │ :3007 ││ │ :3008 │ GraphQL, REST, WS │
│ └──────┬──────┘ └──────┬──────┘│ └──────┬──────┘ │
│ │ │ │ │ │
│ └────────────────┼───────┼─────────┘ │
│ │ │ │
│ ┌───────────────────────┴───────┴───────────────────────────────────────┐ │
│ │ Rust API Binary (platform/api) │ │
│ │ (Actix-web Server) │ │
│ │ │ │
│ │ ┌────────────────────────────────────────────────────────────────┐ │ │
│ │ │ 18 Modular Crates (crates/) │ │ │
│ │ │ │ │ │
│ │ │ heimdall-rest heimdall-graphql heimdall-websocket │ │ │
│ │ │ heimdall-auth heimdall-db heimdall-cache │ │ │
│ │ │ heimdall-audit heimdall-audit-logger heimdall-email │ │ │
│ │ │ heimdall-config heimdall-common heimdall-api │ │ │
│ │ │ heimdall-geoip heimdall-integrations heimdall-proto │ │ │
│ │ │ heimdall-storage heimdall-scheduler heimdall-telemetry │ │ │
│ │ └────────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ └───────────────────────┬────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────┴─────────────────────────────────────────┐ │
│ │ Data Layer │ │
│ │ │ │
│ │ ┌─────────────────────┐ ┌─────────────────────┐ ┌──────────┐│ │
│ │ │ PostgreSQL │ │ TimescaleDB │ │ Redis ││ │
│ │ │ (Primary Store) │ │ (Time-Series DB) │ │ (Cache) ││ │
│ │ │ │ │ │ │ ││ │
│ │ │ - Users │ │ - AuditEvent │ │ - Session││ │
│ │ │ - GPS Data │ │ (hypertable) │ │ - Perms ││ │
│ │ │ - API Keys │ │ - Time-based │ │ - Rate ││ │
│ │ │ - Roles/Permissions │ │ partitioning │ │ - Pub/Sub││ │
│ │ │ - OAuth Clients │ │ - Automatic data │ │ ││ │
│ │ │ - 2FA Secrets │ │ retention │ │ ││ │
│ │ │ - Data Exports │ │ - GeoIP enrichment │ │ ││ │
│ │ └─────────────────────┘ └─────────────────────┘ └──────────┘│ │
│ │ │ │
│ └──────────────────────────────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────────────────────┘

Modular Crate Architecture

The backend was split from a monolithic platform/api/ into 18 independent crates under crates/. The platform/api/ binary is now pure glue code (just main.rs, lib.rs, and bin/) that wires the crates together via Actix-web.

Crate Dependency Layers

                        ┌──────────────────┐
│ platform/api │ (binary — pure glue)
│ main.rs, lib.rs │
└────────┬─────────┘

┌──────────────────┼──────────────────┐
│ │ │
┌─────────┴────────┐ ┌─────┴─────┐ ┌─────────┴────────┐
│ heimdall-rest │ │ heimdall- │ │ heimdall- │
│ (REST handlers, │ │ graphql │ │ websocket │
│ routes, OAuth, │ │ (types, │ │ (WS server, │
│ middleware) │ │ resolvers,│ │ sessions, │
│ │ │ schema) │ │ message types) │
└────────┬─────────┘ └─────┬─────┘ └────────┬─────────┘
│ │ │
└──────────────────┼───────────────────┘

┌─────────────────┼─────────────────┐
│ │ │
┌─────────┴─────┐ ┌───────┴──────┐ ┌───────┴────────┐
│ heimdall-auth │ │ heimdall- │ │ heimdall- │
│ (JWT, RBAC, │ │ audit-logger │ │ integrations │
│ TOTP, crypto)│ │ (AuditLogger │ │ (Twitch/YT/ │
│ │ │ + GeoIP) │ │ Kick/Trovo) │
└───────┬───────┘ └──────┬───────┘ └───────┬────────┘
│ │ │
└─────────────────┼───────────────────┘

┌────────────────────────┼───────────────────────────┐
│ │ │ │ │
┌────┴────┐ ┌────┴────┐ ┌────┴────┐ ┌───┴──────┐ ┌───────┴───────┐
│heimdall-│ │heimdall-│ │heimdall-│ │heimdall- │ │ heimdall- │
│ db │ │ cache │ │ email │ │ geoip │ │ storage │
│(models, │ │(Redis │ │(SMTP + │ │(MaxMind │ │(S3 client, │
│ queries)│ │ client) │ │ sailfish│ │ GeoLite2)│ │ file upload) │
└────┬────┘ └────┬────┘ │ tmpl) │ └──────────┘ └───────────────┘
│ │ └────────┘
│ │
┌────┴───────────┴──────────────────────────────────────┐
│ Foundation layer │
│ ┌────────────┐ ┌────────────┐ ┌────────────────────┐ │
│ │ heimdall- │ │ heimdall- │ │ heimdall- │ │
│ │ config │ │ common │ │ telemetry │ │
│ │ (4-tier │ │ (errors, │ │ (tracing, │ │
│ │ config) │ │ pagination,│ │ Sentry) │ │
│ │ │ │ responses) │ │ │ │
│ └────────────┘ └────────────┘ └────────────────────┘ │
│ │
│ ┌────────────┐ ┌────────────┐ ┌────────────────────┐ │
│ │ heimdall- │ │ heimdall- │ │ heimdall- │ │
│ │ api │ │ audit │ │ scheduler │ │
│ │ (CORS, │ │ (event │ │ (background │ │
│ │ health, │ │ types & │ │ jobs, cron) │ │
│ │ helpers) │ │ constants) │ │ │ │
│ └────────────┘ └────────────┘ └────────────────────┘ │
│ │
│ ┌────────────┐ │
│ │ heimdall- │ │
│ │ proto │ │
│ │ (protobuf │ │
│ │ WS types) │ │
│ └────────────┘ │
└────────────────────────────────────────────────────────┘

Crate Summary

CrateLocationPurpose
heimdall-configcrates/heimdall-config/4-tier config loading: default.toml -> {env}.toml -> local.toml -> HEIMDALL__* env vars
heimdall-commoncrates/heimdall-common/Shared error types, pagination, response wrappers
heimdall-dbcrates/heimdall-db/Database pool management, domain models, SQL queries
heimdall-cachecrates/heimdall-cache/Redis client wrapper (sessions, permissions, rate limiting)
heimdall-telemetrycrates/heimdall-telemetry/Tracing subscriber and Sentry initialization
heimdall-apicrates/heimdall-api/Actix-web infrastructure: CORS, health, response helpers
heimdall-auditcrates/heimdall-audit/Shared audit event types and constants
heimdall-audit-loggercrates/heimdall-audit-logger/AuditLogger service (writes to TimescaleDB + GeoIP enrichment)
heimdall-authcrates/heimdall-auth/JWT, OAuth, RBAC, TOTP/2FA, crypto utilities
heimdall-emailcrates/heimdall-email/SMTP email service with Sailfish templates + rust-i18n
heimdall-geoipcrates/heimdall-geoip/MaxMind GeoLite2 IP-to-location lookup
heimdall-integrationscrates/heimdall-integrations/Platform OAuth: Twitch, YouTube, Kick, Trovo token management
heimdall-restcrates/heimdall-rest/REST handlers, routes, OAuth endpoints, middleware
heimdall-graphqlcrates/heimdall-graphql/GraphQL types, resolvers, and schema (async-graphql)
heimdall-websocketcrates/heimdall-websocket/WebSocket server, session management, channel pub/sub
heimdall-schedulercrates/heimdall-scheduler/Background jobs and scheduled tasks
heimdall-protocrates/heimdall-proto/Protobuf definitions for WebSocket communication
heimdall-storagecrates/heimdall-storage/S3-compatible storage client and file upload

How the API Binary Wires Everything

The platform/api/ binary contains only main.rs, lib.rs, and bin/ scripts. It:

  1. Loads configuration via heimdall-config
  2. Initializes telemetry via heimdall-telemetry
  3. Creates database pools via heimdall-db
  4. Creates Redis client via heimdall-cache
  5. Injects services as web::Data<T> into Actix-web (no global AppState struct)
  6. Registers routes from heimdall-rest::routes and heimdall-graphql
  7. Starts the WebSocket server from heimdall-websocket
  8. Starts background jobs from heimdall-scheduler

Services are injected individually via web::Data<T> (e.g., web::Data<PgPool>, web::Data<RedisClient>, web::Data<GeoIpReader>), or via ServiceContext for handlers that need multiple services.

Build System

All crates are built via Bazel with BuildBuddy remote cache for fast CI builds. Standard cargo build also works for local development.

Component Overview

Rust API (platform/api)

The core backend service, handling all API requests. This is a thin binary that wires together the 18 modular crates.

Technology Stack:

  • Framework: Actix-web 4
  • Database: SQLx with PostgreSQL (primary) + TimescaleDB (time-series)
  • GraphQL: async-graphql
  • OpenAPI: utoipa with Swagger UI
  • Caching: Redis (via heimdall-cache)
  • GeoIP: MaxMind GeoLite2 (via heimdall-geoip)

Responsibilities:

  • REST API endpoints (via heimdall-rest)
  • GraphQL queries and mutations (via heimdall-graphql)
  • WebSocket connections for real-time updates (via heimdall-websocket)
  • Authentication and authorization (via heimdall-auth)
  • Rate limiting (via heimdall-rest::middleware)
  • Data persistence (via heimdall-db)

Backend (platform/backend)

Administrative interface for platform management.

Technology Stack:

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Styling: TailwindCSS 4
  • Auth: NextAuth.js 5
  • GraphQL: Apollo Client

Responsibilities:

  • Admin dashboard
  • GPS data visualization
  • User management
  • Role management
  • API key management
  • Developer tools (OAuth apps)

ID (platform/id)

Identity and authentication service with GDPR compliance.

Technology Stack:

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Styling: TailwindCSS 4
  • Auth: NextAuth.js 5
  • i18n: next-intl

Responsibilities:

  • User registration and login
  • Two-factor authentication (TOTP)
  • OAuth 2.0 provider functionality
  • Account management
  • Account linking (multiple providers)
  • Connected apps management
  • GDPR data export
  • Account deletion with grace period
  • Session management

Policies (platform/policies)

Legal, privacy, and compliance content.

Technology Stack:

  • Framework: Next.js 16 (App Router)
  • Language: TypeScript
  • Styling: TailwindCSS 4
  • i18n: next-intl

Responsibilities:

  • Privacy policy
  • Terms of service
  • Cookie policy
  • Security information
  • FAQ

Documentation (platform/docs)

This documentation site.

Technology Stack:

  • Framework: Docusaurus 3
  • Language: TypeScript/MDX

Discord Bot (platform/discord_bot)

Discord integration bot for the Heimdall platform.

Technology Stack:

  • Framework: Poise (on Serenity-rs)
  • Language: Rust 2024 edition
  • API Communication: GraphQL, REST, WebSocket (Protobuf)
  • i18n: rust-i18n

Responsibilities:

  • Slash commands and prefix commands
  • RBAC permission checking via Heimdall API
  • Audit event logging to Heimdall
  • Real-time event notifications via WebSocket
  • Moderation commands (warn, kick, ban, mute)
  • Admin settings management

Twitch Bot (platform/twitch_bot)

Twitch integration bot for the Heimdall platform.

Technology Stack:

  • Framework: twitch-irc (Rust)
  • Language: Rust 2024 edition
  • API Communication: GraphQL, REST, WebSocket (Protobuf)

Responsibilities:

  • Chat commands
  • Stream event handling
  • Audit event logging to Heimdall
  • Real-time notifications

Data Flow

REST API Request Flow

Client Request


┌─────────────┐
│ CORS │ (heimdall-api)
│ Middleware │
└──────┬──────┘


┌─────────────┐
│ Logger │ (heimdall-telemetry)
│ Middleware │
└──────┬──────┘


┌─────────────┐
│ Auth │ (heimdall-rest::middleware)
│ Middleware │
└──────┬──────┘


┌─────────────┐
│ Rate Limit │ (heimdall-rest::middleware)
│ Middleware │
└──────┬──────┘


┌─────────────┐
│ Handler │ (heimdall-rest::handlers)
│ Function │
└──────┬──────┘


┌─────────────┐
│ Database │ (heimdall-db)
│ Query │
└──────┬──────┘


Response

WebSocket Connection Flow

Client Connect


┌─────────────┐
│ WebSocket │ (heimdall-websocket::route)
│ Upgrade │
└──────┬──────┘


┌─────────────┐
│ State │
│ Manager │──────┐
└──────┬──────┘ │
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Connection │ │ Channel │
│ Handler │ │ Manager │
└──────┬──────┘ └──────┬──────┘
│ │
▼ ▼
┌─────────────┐ ┌─────────────┐
│ Subscribe/ │ │ Publish │
│ Unsubscribe │ │ Updates │
└─────────────┘ └─────────────┘

Database Architecture

Heimdall uses a dual-database architecture:

  1. PostgreSQL (Primary) - Core application data (users, sessions, API keys, etc.)
  2. TimescaleDB (Time-Series) - Audit events stored in a hypertable with automatic time-based partitioning

This separation provides:

  • Optimized time-series queries for audit logs with automatic compression
  • Independent scaling for OLTP vs analytics workloads
  • GeoIP enrichment for security monitoring (country, city, region)
  • Automatic data retention policies for compliance

Core Tables (PostgreSQL)

-- Users (managed by Heimdall ID)
User
├── id (UUID)
├── twitch_id
├── username
├── email
├── avatar_url
├── created_at
└── updated_at

-- Sessions (NextAuth)
Session
├── id (UUID)
├── user_id → User
├── session_token
├── expires
└── created_at

-- API Keys
ApiKey
├── id (UUID)
├── key (hashed)
├── name
├── description
├── user_id → User (optional)
├── scopes[]
├── is_active
├── expires_at
├── last_used_at
└── created_at

-- Roles
Role
├── id (UUID)
├── name (unique)
├── description
├── is_system
└── created_at

-- Permissions
Permission
├── id (UUID)
├── resource
├── action
├── description
└── created_at

-- GPS Data
GpsData
├── id (UUID)
├── latitude
├── longitude
├── altitude
├── speed
├── timestamp
└── created_at

-- Settings
Setting
├── key (primary)
├── value (JSON)
├── is_public
└── updated_at

-- OAuth Clients
OAuthClient
├── id (UUID)
├── client_id
├── client_secret (hashed)
├── name
├── redirect_uris[]
├── user_id → User
└── created_at

Audit Events (TimescaleDB)

Audit events are stored in a TimescaleDB hypertable with automatic time-based partitioning and GeoIP enrichment:

-- Audit Events (TimescaleDB Hypertable)
AuditEvent
├── id (UUID)
├── user_id (optional, can be Heimdall UUID or external ID like Discord snowflake)
├── event_type (string)
├── resource_type (optional)
├── resource_id (optional)
├── actor_id (optional, for admin actions)
├── ip_address (optional)
├── user_agent (optional)
├── description (optional)
├── metadata (JSONB)
├── status (success/failure)
├── error_message (optional)
├── country_code (ISO 3166-1 alpha-2, auto-enriched from IP)
├── country_name (auto-enriched from IP)
├── city (auto-enriched from IP)
├── region (auto-enriched from IP)
├── source_service (optional)
├── is_reported (boolean, for suspicious activity reports)
└── created_at (partitioning key)

Key Features:

  • Hypertable: Automatic time-based partitioning (7-day chunks)
  • GeoIP Enrichment: Country, city, region automatically added from IP address
  • Compression: Automatic compression after 30 days
  • Retention: Configurable data retention policies

Audit Event Types

Event TypeDescription
Authentication
loginUser signed in
login_failedSign-in attempt failed
logoutUser signed out
password_changedPassword was changed
password_reset_requestedPassword reset requested
Two-Factor Auth
2fa_enabled2FA was enabled
2fa_disabled2FA was disabled
2fa_verified2FA code verified
2fa_backup_codes_regeneratedBackup codes regenerated
Sessions
session_createdNew session created
session_revokedSession was revoked
all_sessions_revokedAll other sessions revoked
Account
user_createdAccount created
user_updatedProfile updated
user_deletedAccount deleted
deletion_scheduledAccount deletion scheduled
deletion_cancelledScheduled deletion cancelled
Account Links
account_linkedPlatform account linked
account_unlinkedPlatform account unlinked
account_reconnectedPlatform account reconnected
primary_account_changedPrimary account changed
OAuth
consent_grantedOAuth consent given
consent_revokedOAuth consent revoked
token_createdOAuth token created
token_revokedOAuth token revoked
client_createdOAuth client created
client_updatedOAuth client updated
client_deletedOAuth client deleted
client_secret_regeneratedOAuth client secret regenerated
API Keys
api_key_createdAPI key was created
api_key_updatedAPI key was updated
api_key_revokedAPI key was revoked
Admin
user_bannedUser was banned
user_unbannedUser was unbanned
role_assignedRole assigned to user
role_removedRole removed from user
permission_changedPermission changed
Data
data_exportedGDPR data export completed
activity_reportedSuspicious activity reported
Bot Events
bot_command_executedBot command executed
bot_config_changedBot configuration changed
bot_moderation_actionBot moderation action
bot_guild_configuredDiscord guild configured
Integrations
integration_connectedPlatform integration connected
integration_reconnectedIntegration re-authorized
integration_disconnectedIntegration disconnected
integration_token_refreshedToken automatically refreshed
integration_status_updatedIntegration status updated

Source Services

The source_service field tracks which application created the audit event:

Source ServiceDescription
apiDirect API access
idHeimdall ID webapp
backendBackend dashboard
policiesPolicies webapp
discord_botDiscord bot
twitch_botTwitch bot

Junction Tables

UserRole (user_id, role_id)
ApiKeyRole (api_key_id, role_id)
RolePermission (role_id, permission_id)
LinkedAccount (user_id, provider, provider_account_id)

Deployment Architecture

Development

┌───────────────────────────────────────────────────────────────────────────┐
│ Local Development │
├───────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ API │ │Backend │ │ ID │ │ Docs │ │Policies│ │
│ │ :3000 │ │ :3001 │ │ :3002 │ │ :3003 │ │ :3004 │ │
│ └───┬────┘ └───┬────┘ └───┬────┘ └────────┘ └────────┘ │
│ │ │ │ │
│ └───────────┼───────────┘ │
│ │ │
│ ┌───────────────┼───────────────────────────────────────┐ │
│ │ │ │ │
│ │ ┌────────────┴────────────┐ ┌────────────────────┐ │ │
│ │ │ Discord Bot │ │ Twitch Bot │ │ │
│ │ │ :3006 │ │ :3007 │ │ Rust Bots │
│ │ └────────────┬────────────┘ └─────────┬──────────┘ │ │
│ │ └──────────────┬──────────┘ │ │
│ └──────────────────────────────┼────────────────────────┘ │
│ │ │
│ ┌──────────────────────────────┴────────────────────────────────┐ │
│ │ Docker Compose │ │
│ │ ┌────────────┐ ┌────────────┐ ┌────────────┐ ┌─────────┐ │ │
│ │ │ PostgreSQL │ │TimescaleDB │ │ Redis │ │ MailDev │ │ │
│ │ │ :5432 │ │ :5433 │ │ :6379 │ │ :1080 │ │ │
│ │ └────────────┘ └────────────┘ └────────────┘ └─────────┘ │ │
│ └───────────────────────────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────────────┘

Production

┌───────────────────────────────────────────────────────────────────┐
│ Production Deployment │
├───────────────────────────────────────────────────────────────────┤
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ CDN / Edge Network │ │
│ │ (Cloudflare / Vercel Edge) │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────┴────────────────────────────────┐ │
│ │ Load Balancer │ │
│ │ (nginx / Cloud LB) │ │
│ └───────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────┼────────────────────────────────┐ │
│ │ ┌──────────┐ ┌───────┴────┐ ┌──────────┐ │ │
│ │ │ API Pod │ │ API Pod │ │ API Pod │ │ │
│ │ │ #1 │ │ #2 │ │ #3 │ │ │
│ │ └──────────┘ └────────────┘ └──────────┘ │ │
│ │ (Kubernetes) │ │
│ └───────────────────────────┬────────────────────────────────┘ │
│ │ │
│ ┌───────────────────────────┼────────────────────────────────┐ │
│ │ ┌─────────────────┐ │ ┌─────────────────┐ │ │
│ │ │ PostgreSQL │ │ │ Redis │ │ │
│ │ │ (Primary) │◄─────┴─────►│ (Cluster) │ │ │
│ │ └────────┬────────┘ └─────────────────┘ │ │
│ │ │ │ │
│ │ ┌────────┴────────┐ │ │
│ │ │ PostgreSQL │ │ │
│ │ │ (Replica) │ │ │
│ │ └─────────────────┘ │ │
│ │ (Managed Database) │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ Next.js Apps │ │
│ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │
│ │ │ Backend │ │ ID │ │ Policies │ │ Docs │ │ │
│ │ │ (Vercel) │ │ (Vercel) │ │ (Vercel) │ │ (Vercel) │ │ │
│ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
└───────────────────────────────────────────────────────────────────┘

Security Architecture

Authentication Layers

  1. Session-based (Next.js apps via NextAuth)

    • HTTP-only secure cookies
    • JWT tokens with short expiry
    • Automatic refresh
  2. Token-based (API access)

    • Bearer tokens in Authorization header
    • API keys for programmatic access
    • OAuth 2.0 for third-party apps
  3. Two-Factor Authentication

    • TOTP-based (RFC 6238)
    • Backup codes for recovery
    • Role-based 2FA requirements

Authorization Model

Request


┌─────────────────────┐
│ Extract Auth Token │
└──────────┬──────────┘


┌─────────────────────┐
│ Lookup Token │
│ (JWT or API Key) │
└──────────┬──────────┘


┌─────────────────────┐
│ Get User/Key │
│ Roles │
└──────────┬──────────┘


┌─────────────────────┐
│ Aggregate │
│ Permissions │
└──────────┬──────────┘


┌─────────────────────┐
│ Check Permission │
│ (resource:action) │
└──────────┬──────────┘

┌─────┴─────┐
│ │
▼ ▼
Allow Deny

Configuration System

Heimdall uses a 4-tier configuration system (via heimdall-config):

  1. config/default.toml -- Base defaults for all environments
  2. config/{env}.toml -- Environment-specific overrides (e.g., production.toml)
  3. config/local.toml -- Local developer overrides (git-ignored)
  4. HEIMDALL__* env vars -- Runtime overrides (highest priority, double underscore for nesting)

Example: HEIMDALL__DATABASE__URL=postgres://... overrides [database] url in TOML.

Next Steps