Initialize Sneaky Klaus project with: - uv package management and pyproject.toml - Flask application structure (app.py, config.py) - SQLAlchemy models for Admin and Exchange - Alembic database migrations - Pre-commit hooks configuration - Development tooling (pytest, ruff, mypy) Initial structure follows design documents in docs/: - src/app.py: Application factory with Flask extensions - src/config.py: Environment-based configuration - src/models/: Admin and Exchange models - migrations/: Alembic migration setup 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
121 lines
3.2 KiB
Python
121 lines
3.2 KiB
Python
"""Configuration management for Sneaky Klaus application.
|
|
|
|
This module defines configuration classes for different environments
|
|
(development, production, testing) with environment variable support.
|
|
"""
|
|
|
|
import os
|
|
from datetime import timedelta
|
|
from pathlib import Path
|
|
|
|
|
|
class Config:
|
|
"""Base configuration class with common settings."""
|
|
|
|
# Base paths
|
|
BASE_DIR = Path(__file__).parent.parent
|
|
DATA_DIR = BASE_DIR / "data"
|
|
|
|
# Security
|
|
SECRET_KEY = os.environ.get("SECRET_KEY") or "dev-secret-key-change-in-production"
|
|
|
|
# Database
|
|
SQLALCHEMY_DATABASE_URI = os.environ.get(
|
|
"DATABASE_URL", f"sqlite:///{DATA_DIR / 'sneaky-klaus.db'}"
|
|
)
|
|
SQLALCHEMY_TRACK_MODIFICATIONS = False
|
|
|
|
# Session management
|
|
SESSION_TYPE = "sqlalchemy"
|
|
SESSION_PERMANENT = True
|
|
SESSION_USE_SIGNER = True
|
|
SESSION_KEY_PREFIX = "sk:"
|
|
PERMANENT_SESSION_LIFETIME = timedelta(days=7)
|
|
SESSION_COOKIE_SECURE = True # HTTPS only
|
|
SESSION_COOKIE_HTTPONLY = True
|
|
SESSION_COOKIE_SAMESITE = "Lax"
|
|
|
|
# Flask-WTF CSRF Protection
|
|
WTF_CSRF_ENABLED = True
|
|
WTF_CSRF_TIME_LIMIT = None # No time limit for CSRF tokens
|
|
|
|
# Email service (Resend)
|
|
RESEND_API_KEY = os.environ.get("RESEND_API_KEY")
|
|
|
|
# Application URLs
|
|
APP_URL = os.environ.get("APP_URL", "http://localhost:5000")
|
|
|
|
# Timezone
|
|
TIMEZONE = os.environ.get("TZ", "UTC")
|
|
|
|
# Password requirements
|
|
MIN_PASSWORD_LENGTH = 12
|
|
|
|
|
|
class DevelopmentConfig(Config):
|
|
"""Development environment configuration."""
|
|
|
|
DEBUG = True
|
|
TESTING = False
|
|
SESSION_COOKIE_SECURE = False # Allow HTTP in development
|
|
SQLALCHEMY_ECHO = True # Log SQL queries
|
|
|
|
|
|
class ProductionConfig(Config):
|
|
"""Production environment configuration."""
|
|
|
|
DEBUG = False
|
|
TESTING = False
|
|
|
|
# Ensure critical environment variables are set
|
|
@classmethod
|
|
def validate(cls):
|
|
"""Validate that required production configuration is present."""
|
|
required_vars = ["SECRET_KEY", "RESEND_API_KEY", "APP_URL"]
|
|
missing_vars = [var for var in required_vars if not os.environ.get(var)]
|
|
if missing_vars:
|
|
raise ValueError(
|
|
f"Missing required environment variables: {', '.join(missing_vars)}"
|
|
)
|
|
|
|
|
|
class TestConfig(Config):
|
|
"""Test environment configuration."""
|
|
|
|
TESTING = True
|
|
DEBUG = True
|
|
SESSION_COOKIE_SECURE = False
|
|
|
|
# Use in-memory database for tests
|
|
SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:"
|
|
|
|
# Disable CSRF for easier testing
|
|
WTF_CSRF_ENABLED = False
|
|
|
|
# Use a predictable secret key for tests
|
|
SECRET_KEY = "test-secret-key"
|
|
|
|
|
|
# Configuration dictionary for easy access
|
|
config = {
|
|
"development": DevelopmentConfig,
|
|
"production": ProductionConfig,
|
|
"testing": TestConfig,
|
|
"default": DevelopmentConfig,
|
|
}
|
|
|
|
|
|
def get_config(env: str | None = None) -> type[Config]:
|
|
"""Get configuration class based on environment.
|
|
|
|
Args:
|
|
env: Environment name (development, production, testing).
|
|
If None, uses FLASK_ENV environment variable.
|
|
|
|
Returns:
|
|
Configuration class for the specified environment.
|
|
"""
|
|
if env is None:
|
|
env = os.environ.get("FLASK_ENV", "development")
|
|
return config.get(env, config["default"])
|