Configuration

December 4, 2025 ยท View on GitHub

This document describes environment variables and configuration options for Santa Tracker.

๐Ÿ” Environment Variables

Required Variables

ADMIN_PASSWORD

Admin dashboard password for authentication.

export ADMIN_PASSWORD="your-secure-password"

Best Practices:

  • Use 16+ characters
  • Include uppercase, lowercase, numbers, symbols
  • Never commit to version control
  • Use different passwords per environment
  • Store in password manager

Optional Variables

FLASK_ENV

Application environment mode.

export FLASK_ENV="development"  # or "production"

Values:

  • development: Development mode with debugging
  • production: Production mode (optimized)

Default: production


FLASK_DEBUG

Enable debug mode and detailed error pages.

export FLASK_DEBUG="True"  # or "False"

Features when enabled:

  • Auto-reload on code changes
  • Interactive debugger
  • Detailed error traces
  • Development tools enabled

Default: False

Warning: Never enable in production!


FLASK_RUN_PORT

Port number for Flask development server.

export FLASK_RUN_PORT="8080"

Default: 5000


SECRET_KEY

Flask session encryption key.

export SECRET_KEY="your-secret-key-here"

Best Practices:

  • Generate with: python -c "import secrets; print(secrets.token_hex(32))"
  • Change between environments
  • Keep secure and private
  • Never commit to version control

Default: Generated randomly (not persistent)


FLASK_RUN_HOST

Host address for Flask development server.

export FLASK_RUN_HOST="0.0.0.0"  # Listen on all interfaces

Default: 127.0.0.1 (localhost only)


LOG_LEVEL

Application logging level. Controls the verbosity of log output.

export LOG_LEVEL="INFO"  # DEBUG, INFO, WARNING, ERROR, CRITICAL

Values:

  • DEBUG: Detailed diagnostic information
  • INFO: General operational information (default)
  • WARNING: Something unexpected but not an error
  • ERROR: A more serious problem
  • CRITICAL: A very serious error

Default: INFO


JSON_LOGS

Enable JSON structured logging format for production log aggregators.

export JSON_LOGS="True"  # or "False"

When enabled:

  • Log output is formatted as JSON objects
  • Each log entry includes: timestamp, name, level, message
  • Compatible with log aggregators like ELK, Splunk, CloudWatch

When disabled (default):

  • Human-readable log format
  • Format: YYYY-MM-DD HH:MM:SS - module_name - LEVEL - message

Default: False


๐Ÿšฉ Feature Flags

Feature flags allow you to enable or disable specific functionality without code changes.

ADVENT_ENABLED

Controls visibility and accessibility of the advent calendar feature.

export ADVENT_ENABLED="True"  # or "False"

Behavior when disabled (default):

  • Advent calendar navigation links are hidden from the UI
  • /advent page returns 404 Not Found
  • All /api/advent/* endpoints return 404 Not Found
  • All /api/admin/advent/* endpoints return 404 Not Found
  • Advent-related JavaScript and CSS are not loaded

Behavior when enabled:

  • Full advent calendar functionality is available
  • Navigation links appear in the header
  • All advent API endpoints are accessible

Default: False

Use case: Keep disabled until the advent calendar feature is complete and ready for production.


๐Ÿ“„ .env File

Creating .env File

Create a .env file in the project root:

# Flask Configuration
FLASK_ENV=development
FLASK_DEBUG=True
FLASK_RUN_PORT=5000
FLASK_RUN_HOST=127.0.0.1

# Security
SECRET_KEY=your-secret-key-here-change-in-production
ADMIN_PASSWORD=your-secure-admin-password

# Feature Flags
ADVENT_ENABLED=False  # Set to True when advent calendar is ready

# Optional: Database (if using external DB)
# DATABASE_URL=postgresql://user:pass@localhost/dbname

# Optional: External APIs
# SANTA_API_KEY=your-api-key
# SANTA_API_URL=https://api.example.com

Loading .env File

The application automatically loads .env using python-dotenv:

from dotenv import load_dotenv
load_dotenv()

Security Note

IMPORTANT: Add .env to .gitignore:

# Environment variables
.env
.env.local
.env.*.local

โš™๏ธ Configuration File (config.py)

Basic Configuration

import os
from dotenv import load_dotenv

load_dotenv()

class Config:
    """Base configuration"""
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key'
    ADMIN_PASSWORD = os.environ.get('ADMIN_PASSWORD')
    
    # Flask
    DEBUG = False
    TESTING = False
    
    # Session
    SESSION_COOKIE_SECURE = True
    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SAMESITE = 'Lax'
    
    # File paths
    ROUTE_DATA_FILE = 'santa_route.txt'
    STATIC_FOLDER = 'static'
    TEMPLATE_FOLDER = 'templates'

class DevelopmentConfig(Config):
    """Development configuration"""
    DEBUG = True
    SESSION_COOKIE_SECURE = False  # Allow HTTP in dev

class ProductionConfig(Config):
    """Production configuration"""
    DEBUG = False
    SESSION_COOKIE_SECURE = True  # Require HTTPS

class TestingConfig(Config):
    """Testing configuration"""
    TESTING = True
    DEBUG = True

Using Configuration

from config import DevelopmentConfig, ProductionConfig

# In app.py
config_class = ProductionConfig if os.environ.get('FLASK_ENV') == 'production' else DevelopmentConfig
app.config.from_object(config_class)

๐Ÿ—„๏ธ Data File Configuration

Route Data File

Location of Santa's route data.

Default: santa_route.txt

ROUTE_DATA_FILE = os.environ.get('ROUTE_DATA_FILE', 'santa_route.txt')

Advent Calendar Data

Location of advent calendar content.

Default: src/static/data/advent_calendar.json

ADVENT_DATA_FILE = 'src/static/data/advent_calendar.json'

Database Files

SQLite databases for geographic data.

Files:

  • cities.sqlite3
  • countries.sqlite3
  • regions.sqlite3
  • states.sqlite3
  • subregions.sqlite3
  • world.sqlite3

๐ŸŒ External API Configuration

Santa Tracking API (Optional)

If integrating with external Santa tracking APIs:

SANTA_API_KEY=your-api-key
SANTA_API_URL=https://api.santatracker.example.com
SANTA_API_TIMEOUT=30
# In config.py
class Config:
    SANTA_API_KEY = os.environ.get('SANTA_API_KEY')
    SANTA_API_URL = os.environ.get('SANTA_API_URL')
    SANTA_API_TIMEOUT = int(os.environ.get('SANTA_API_TIMEOUT', 30))

๐Ÿš€ Production Configuration

Environment Variables for Production

# Production environment
export FLASK_ENV=production
export FLASK_DEBUG=False

# Security (use strong values!)
export SECRET_KEY="$(python -c 'import secrets; print(secrets.token_hex(32))')"
export ADMIN_PASSWORD="your-very-secure-password"

# Server
export FLASK_RUN_HOST=0.0.0.0
export FLASK_RUN_PORT=5000

# Optional: Gunicorn workers
export WEB_CONCURRENCY=4

Gunicorn Configuration

Create gunicorn_config.py:

import os

# Server socket
bind = f"0.0.0.0:{os.environ.get('PORT', '5000')}"
backlog = 2048

# Worker processes
workers = int(os.environ.get('WEB_CONCURRENCY', 4))
worker_class = 'sync'
worker_connections = 1000
timeout = 30
keepalive = 2

# Logging
accesslog = '-'
errorlog = '-'
loglevel = 'info'

# Process naming
proc_name = 'santa-tracker'

# Server mechanics
daemon = False
pidfile = None
umask = 0
user = None
group = None
tmp_upload_dir = None

Run with:

gunicorn -c gunicorn_config.py src.app:app

๐Ÿ”’ Security Hardening

Session Security

# Secure cookies
SESSION_COOKIE_SECURE = True       # HTTPS only
SESSION_COOKIE_HTTPONLY = True     # No JavaScript access
SESSION_COOKIE_SAMESITE = 'Lax'    # CSRF protection

# Session lifetime
PERMANENT_SESSION_LIFETIME = 3600  # 1 hour

HTTPS Configuration

For production behind reverse proxy:

from werkzeug.middleware.proxy_fix import ProxyFix

app.wsgi_app = ProxyFix(
    app.wsgi_app,
    x_proto=1,
    x_host=1
)

Content Security Policy

Add CSP headers:

@app.after_request
def set_csp(response):
    response.headers['Content-Security-Policy'] = (
        "default-src 'self'; "
        "script-src 'self' 'unsafe-inline' cdn.jsdelivr.net unpkg.com; "
        "style-src 'self' 'unsafe-inline' cdn.jsdelivr.net unpkg.com; "
        "img-src 'self' data: https:; "
        "font-src 'self' data:;"
    )
    return response

๐Ÿงช Testing Configuration

Test Environment

# .env.test
FLASK_ENV=testing
FLASK_DEBUG=True
TESTING=True

# Use test password
ADMIN_PASSWORD=test-password

# Test database
DATABASE_URL=sqlite:///test.db

Loading Test Config

# In tests/conftest.py
import os
os.environ['FLASK_ENV'] = 'testing'
os.environ['ADMIN_PASSWORD'] = 'test-password'

๐Ÿ“Š Logging Configuration

Centralized Logging Module

The application uses a centralized logging configuration in src/logging_config.py:

from src.logging_config import configure_logging, get_logger

# Configure logging at application startup (optional, called automatically)
configure_logging()

# Get a module-specific logger
logger = get_logger(__name__)

# Use the logger
logger.info('Application started')
logger.debug('Debug information: %s', variable)
logger.warning('Warning message')
logger.error('Error occurred')
logger.exception('Error with traceback')  # Use in except blocks

Environment-Based Configuration

Control logging via environment variables:

# Set log level
export LOG_LEVEL="DEBUG"  # DEBUG, INFO, WARNING, ERROR, CRITICAL

# Enable JSON structured logs for production
export JSON_LOGS="True"

Basic Module Logging

import logging

# Get a module-specific logger
logger = logging.getLogger(__name__)

# Log messages at appropriate levels
logger.debug('Detailed diagnostic info')
logger.info('General operational info')
logger.warning('Something unexpected')
logger.error('A serious problem')
logger.critical('Application cannot continue')

Production Logging

For production with file rotation:

from logging.handlers import RotatingFileHandler

if not app.debug:
    # File handler with rotation
    file_handler = RotatingFileHandler(
        'santa-tracker.log',
        maxBytes=10240000,
        backupCount=10
    )
    file_handler.setFormatter(logging.Formatter(
        '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
    ))
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)
    
    app.logger.setLevel(logging.INFO)
    app.logger.info('Santa Tracker startup')

Important: No print() in Production Code

Do not use print() statements in src/ modules. The CI pipeline will fail if print statements are detected.

Use logger.info() or other appropriate log levels instead.


๐Ÿ”ง Example Configurations

Development Setup

# .env.development
FLASK_ENV=development
FLASK_DEBUG=True
FLASK_RUN_PORT=5000
SECRET_KEY=dev-secret-key-not-secure
ADMIN_PASSWORD=admin123

Production Setup

# .env.production
FLASK_ENV=production
FLASK_DEBUG=False
FLASK_RUN_HOST=0.0.0.0
FLASK_RUN_PORT=8080
SECRET_KEY=<generated-secure-key>
ADMIN_PASSWORD=<strong-password>

Docker Setup

# Environment in Dockerfile
ENV FLASK_ENV=production
ENV FLASK_DEBUG=False
ENV FLASK_RUN_HOST=0.0.0.0
ENV FLASK_RUN_PORT=5000

# Or use docker-compose.yml
environment:
  - FLASK_ENV=production
  - SECRET_KEY=${SECRET_KEY}
  - ADMIN_PASSWORD=${ADMIN_PASSWORD}

โœ… Configuration Checklist

Development

  • Create .env file
  • Set FLASK_ENV=development
  • Set FLASK_DEBUG=True
  • Set ADMIN_PASSWORD
  • Add .env to .gitignore

Production

  • Set FLASK_ENV=production
  • Set FLASK_DEBUG=False
  • Generate secure SECRET_KEY
  • Set strong ADMIN_PASSWORD
  • Enable HTTPS
  • Configure CSP headers
  • Set up logging
  • Configure reverse proxy
  • Set appropriate worker count
  • Test all endpoints