Skip to main content

Overview

Framefox uses a flexible configuration system that combines YAML files with environment variables, allowing you to manage settings across different environments securely.

Configuration System

Framefox loads configuration from:
  1. YAML files in the config/ directory
  2. Environment variables referenced in YAML files using ${VAR_NAME} syntax
  3. .env file for local environment variables

Environment Variables

Core Variables

These environment variables control fundamental application behavior:
# Application environment (dev or prod)
APP_ENV=prod

# Database connection
DATABASE_URL=postgresql://user:password@localhost:5432/dbname

# Session security
SECRET_KEY=your-very-secure-secret-key-minimum-32-characters
SESSION_SECRET_KEY=another-secure-key-for-sessions

# Redis (optional, for session storage)
REDIS_URL=redis://localhost:6379/0

Database Configuration

Using DATABASE_URL

The simplest way to configure the database:
# PostgreSQL
DATABASE_URL=postgresql://user:password@host:5432/database

# MySQL
DATABASE_URL=mysql://user:password@host:3306/database

# SQLite
DATABASE_URL=sqlite:///./database.db

Detailed Configuration

Alternatively, configure in config/orm.yaml:
database:
  driver: postgresql  # or mysql, sqlite
  host: ${DB_HOST}
  port: ${DB_PORT}
  database: ${DB_NAME}
  username: ${DB_USER}
  password: ${DB_PASSWORD}
  pool_size: 20
  max_overflow: 10
  pool_pre_ping: true
  pool_recycle: 3600
  logging:
    echo_sql: false  # Set to true in development for SQL logging
Environment variables:
DB_HOST=localhost
DB_PORT=5432
DB_NAME=framefox
DB_USER=admin
DB_PASSWORD=secure_password

Security Configuration

Session Management

Configure in config/application.yaml:
application:
  session:
    name: session_id
    secret_key: ${SESSION_SECRET_KEY}
    file_path: var/session/sessions.db
    redis:
      url: ${REDIS_URL}
      prefix: "session:"
      db: 0
Environment variables:
SESSION_SECRET_KEY=your-session-secret-key-here
REDIS_URL=redis://localhost:6379/0
application:
  cookie:
    secure: true        # Only send over HTTPS
    http_only: true     # Not accessible via JavaScript
    same_site: lax      # CSRF protection
    max_age: 3600       # 1 hour in seconds
    path: /

Monitoring and Error Tracking

Sentry Integration

Configure in config/debug.yaml:
debug:
  sentry:
    dsn: ${SENTRY_DSN}
    environment: ${APP_ENV}
    sample_rate: 1.0              # 100% of errors
    traces_sample_rate: 0.1       # 10% of transactions
Environment variable:
SENTRY_DSN=https://[email protected]/67890

Logging Configuration

Configure in config/debug.yaml:
debug:
  logging:
    level: ${LOG_LEVEL}           # DEBUG, INFO, WARNING, ERROR
    file_path: var/log/app.log
    max_size: 100                 # MB
    backup_count: 10
  profiler:
    enabled: ${PROFILER_ENABLED}
    max_files: 1000
    retention_days: 7
    sampling_rate: 1.0
Environment variables:
LOG_LEVEL=INFO
PROFILER_ENABLED=false

Mail Configuration

Configure email settings:
mail:
  url: ${MAIL_URL}
Environment variable (using SMTP URL format):
# SMTP
MAIL_URL=smtp://username:[email protected]:587?tls=true

# SendGrid
MAIL_URL=smtp://apikey:[email protected]:587?tls=true

# Mailgun
MAIL_URL=smtp://[email protected]:[email protected]:587?tls=true

Background Tasks

Configure task processing:
tasks:
  type: ${TASK_BROKER}                    # database, redis, or rabbitmq
  task_transport_url: ${TASK_BROKER_URL}
  worker:
    concurrency: 5
    polling_interval: 5
    default_queues:
      - default
  cleanup:
    interval_hours: 24
    retention_days: 7
  defaults:
    queue: default
    priority: 0
    max_retries: 3
    retry_delay: 300
Environment variables:
TASK_BROKER=redis
TASK_BROKER_URL=redis://localhost:6379/1

# Or for RabbitMQ
TASK_BROKER=rabbitmq
TASK_BROKER_URL=amqp://guest:guest@localhost:5672/%2F

.env File

Create a .env file in your project root:
# .env - DO NOT COMMIT THIS FILE

# Application
APP_ENV=dev

# Database
DATABASE_URL=postgresql://framefox:password@localhost:5432/framefox

# Security
SECRET_KEY=dev-secret-key-change-in-production
SESSION_SECRET_KEY=dev-session-key-change-in-production

# Redis
REDIS_URL=redis://localhost:6379/0

# Email
MAIL_URL=smtp://user:[email protected]:587?tls=true

# Error Tracking
SENTRY_DSN=

# Logging
LOG_LEVEL=DEBUG
PROFILER_ENABLED=true

# Tasks
TASK_BROKER=database
TASK_BROKER_URL=

.env.example

Commit an example file without sensitive data:
# .env.example - Safe to commit

# Application
APP_ENV=dev

# Database
DATABASE_URL=postgresql://user:password@localhost:5432/dbname

# Security
SECRET_KEY=change-me-in-production
SESSION_SECRET_KEY=change-me-in-production

# Redis (optional)
REDIS_URL=redis://localhost:6379/0

# Email
MAIL_URL=smtp://username:[email protected]:587?tls=true

# Error Tracking (optional)
SENTRY_DSN=

# Logging
LOG_LEVEL=INFO
PROFILER_ENABLED=false

# Tasks
TASK_BROKER=database
TASK_BROKER_URL=

Configuration Files

Application Configuration

config/application.yaml:
application:
  # API Documentation (only in dev)
  openapi_url: /openapi.json
  redoc_url: /redoc

  # Directories
  controller:
    dir: src/controller
  template_dir: templates

  # Session
  session:
    name: session_id
    secret_key: ${SESSION_SECRET_KEY}
    file_path: var/session/sessions.db
    redis:
      url: ${REDIS_URL}
      prefix: "session:"
      db: 0

  # Cookies
  cookie:
    secure: true
    http_only: true
    same_site: lax
    max_age: 3600
    path: /

  # CORS
  cors:
    allow_origins:
      - https://yourdomain.com
    allow_methods:
      - GET
      - POST
      - PUT
      - DELETE
    allow_headers:
      - "*"
    allow_credentials: true

Security Configuration

config/security.yaml:
security:
  providers:
    user_provider:
      entity: src.entity.user.User
      property: email

  firewalls:
    main:
      pattern: ^/
      stateless: false
      provider: user_provider
      entry_point: /login
      login:
        login_path: /login
        check_path: /login
        default_target_path: /dashboard
      logout:
        path: /logout
        target: /

  access_control:
    - { path: ^/login, roles: PUBLIC }
    - { path: ^/register, roles: PUBLIC }
    - { path: ^/admin, roles: ROLE_ADMIN }
    - { path: ^/, roles: ROLE_USER }

ORM Configuration

config/orm.yaml:
database:
  url: ${DATABASE_URL}
  pool_size: 20
  max_overflow: 10
  pool_pre_ping: true
  pool_recycle: 3600
  logging:
    echo_sql: false

Debug Configuration

config/debug.yaml:
debug:
  logging:
    level: ${LOG_LEVEL}
    file_path: var/log/app.log
    max_size: 100
    backup_count: 10

  profiler:
    enabled: ${PROFILER_ENABLED}
    max_files: 1000
    retention_days: 7
    sampling_rate: 1.0
    max_memory: 50

  sentry:
    dsn: ${SENTRY_DSN}
    environment: ${APP_ENV}
    sample_rate: 1.0
    traces_sample_rate: 0.1

Accessing Configuration in Code

Using Settings Class

Framefox provides a Settings class to access configuration:
from framefox.core.config.settings import Settings

settings = Settings()

# Access properties
app_env = settings.app_env  # 'dev' or 'prod'
is_debug = settings.is_debug  # True if APP_ENV=dev

# Database
db_url = settings.database_url
db_echo = settings.database_echo

# Session
session_name = settings.session_name
session_secret = settings.session_secret_key

# Custom parameters
api_key = settings.get_param("custom_variables.api_key", default="")

Custom Parameters

Add custom parameters in any YAML file:
parameters:
  app_name: "My Framefox App"
  api_version: "v1"
  features:
    analytics: true
    notifications: false
  external_apis:
    stripe_key: ${STRIPE_API_KEY}
    sendgrid_key: ${SENDGRID_API_KEY}
Access in code:
app_name = settings.get_param("app_name")
api_version = settings.get_param("api_version")
analytics_enabled = settings.get_param("features.analytics")
stripe_key = settings.get_param("external_apis.stripe_key")

Environment-Specific Configuration

Development Settings

# .env.dev
APP_ENV=dev
DATABASE_URL=sqlite:///./dev.db
LOG_LEVEL=DEBUG
PROFILER_ENABLED=true
REDIS_URL=
SENTRY_DSN=

Production Settings

# .env.prod
APP_ENV=prod
DATABASE_URL=postgresql://user:password@prod-db:5432/framefox
LOG_LEVEL=WARNING
PROFILER_ENABLED=false
REDIS_URL=redis://redis:6379/0
SENTRY_DSN=https://[email protected]/project

Loading Specific Environment

# Development
cp .env.dev .env
framefox run

# Production
cp .env.prod .env
uvicorn main:app --host 0.0.0.0 --port 8000

Security Best Practices

Never Commit Secrets

Add to .gitignore:
# Environment files
.env
.env.local
.env.*.local
.env.prod
.env.production

# Secrets
secrets/
*.key
*.pem

Generate Secure Keys

# Generate a secure secret key
import secrets
print(secrets.token_urlsafe(32))
# Output: xhC8Lj3K_vQR9mN2pB7sT4wF6dY5uH1aE0qZ
Or using command line:
python -c "import secrets; print(secrets.token_urlsafe(32))"

Use Environment Variables in Production

Don’t use .env files in production. Set environment variables directly:
# Systemd service
[Service]
Environment="APP_ENV=prod"
Environment="SECRET_KEY=your-secret-key"
Environment="DATABASE_URL=postgresql://..."
# Docker
docker run -e APP_ENV=prod -e SECRET_KEY=... framefox-app
# Kubernetes
apiVersion: v1
kind: Secret
metadata:
  name: framefox-secrets
type: Opaque
data:
  secret-key: base64-encoded-secret
  database-url: base64-encoded-url

Validate Configuration

Add validation in your application:
from framefox.core.config.settings import Settings

def validate_config():
    settings = Settings()
    
    # Check production requirements
    if settings.app_env == "prod":
        if settings.session_secret_key == "default_secret":
            raise ValueError("Production requires a secure SESSION_SECRET_KEY")
        
        if not settings.cookie_secure:
            raise ValueError("Production requires secure cookies (HTTPS)")
        
        if settings.is_debug:
            raise ValueError("Debug mode must be disabled in production")
    
    return True

Configuration Precedence

Framefox follows this precedence order (highest to lowest):
  1. Environment variables set in the shell
  2. .env file variables
  3. YAML configuration files with ${VAR} placeholders
  4. Default values in the Settings class

Troubleshooting

Configuration Not Found Error

ConfigurationFileNotFoundError: Configuration folder './config' not found
Ensure your project has a config/ directory with YAML files.

Environment Variable Not Found

EnvironmentVariableNotFoundError: Environment variable 'DATABASE_URL' not found
Set the variable in your .env file or environment.

Invalid Configuration

InvalidConfigurationError: Invalid YAML format in 'application.yaml'
Check YAML syntax:
  • Proper indentation (2 spaces)
  • Quoted strings with special characters
  • Valid YAML structure

Database Connection Issues

Verify your DATABASE_URL format:
# Correct format
DATABASE_URL=postgresql://user:password@host:5432/database

# Common mistakes
# Missing port: postgresql://user:password@host/database
# Wrong scheme: postgres:// (should be postgresql://)
# Special characters not encoded: password with @ or /

Next Steps

Production Deployment

Deploy your configured application

Docker Deployment

Use Docker with environment variables

Build docs developers (and LLMs) love