Files
thrillwiki_django_no_react/backend/config/django/base.py
pacnpal edcd8f2076 Add secret management guide, client-side performance monitoring, and search accessibility enhancements
- Introduced a comprehensive Secret Management Guide detailing best practices, secret classification, development setup, production management, rotation procedures, and emergency protocols.
- Implemented a client-side performance monitoring script to track various metrics including page load performance, paint metrics, layout shifts, and memory usage.
- Enhanced search accessibility with keyboard navigation support for search results, ensuring compliance with WCAG standards and improving user experience.
2025-12-23 16:41:42 -05:00

281 lines
11 KiB
Python

"""
Base Django settings for thrillwiki project.
This file contains only core Django settings that are common across all
environments. Environment-specific settings are in local.py, production.py,
and test.py. Modular configuration is imported from config/settings/.
Structure:
- Core settings (SECRET_KEY, DEBUG, ALLOWED_HOSTS)
- Application definition (INSTALLED_APPS, MIDDLEWARE)
- URL and template configuration
- Internationalization
- Imports from modular settings (database, cache, security, etc.)
"""
import sys
from pathlib import Path
from decouple import config
# =============================================================================
# Path Configuration
# =============================================================================
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent.parent
# Add apps directory to sys.path so Django can find the apps
apps_dir = BASE_DIR / "apps"
if apps_dir.exists() and str(apps_dir) not in sys.path:
sys.path.insert(0, str(apps_dir))
# =============================================================================
# Core Settings
# =============================================================================
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = config("SECRET_KEY")
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = config("DEBUG", default=True, cast=bool)
# Allowed hosts (comma-separated in .env)
ALLOWED_HOSTS = config(
"ALLOWED_HOSTS",
default="localhost,127.0.0.1",
cast=lambda v: [s.strip() for s in v.split(",") if s.strip()]
)
# CSRF trusted origins (comma-separated in .env)
CSRF_TRUSTED_ORIGINS = config(
"CSRF_TRUSTED_ORIGINS",
default="",
cast=lambda v: [s.strip() for s in v.split(",") if s.strip()]
)
# =============================================================================
# Application Definition
# =============================================================================
DJANGO_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"django.contrib.sites",
"django.contrib.gis", # GeoDjango
]
THIRD_PARTY_APPS = [
# Django Cloudflare Images Toolkit - moved to top to avoid circular imports
"django_cloudflareimages_toolkit",
"rest_framework", # Django REST Framework
# Token authentication (kept for backward compatibility)
"rest_framework.authtoken",
"rest_framework_simplejwt", # JWT authentication
"rest_framework_simplejwt.token_blacklist", # JWT token blacklist
"dj_rest_auth", # REST authentication with JWT support
"dj_rest_auth.registration", # REST registration support
"drf_spectacular", # OpenAPI 3.0 documentation
"corsheaders", # CORS headers for API
"pghistory", # django-pghistory
"pgtrigger", # Required by django-pghistory
"django_fsm_log", # FSM transition logging
"allauth",
"allauth.account",
"allauth.socialaccount",
"allauth.socialaccount.providers.google",
"allauth.socialaccount.providers.discord",
"django_cleanup",
"django_filters",
"django_htmx",
"whitenoise",
"django_tailwind_cli",
"autocomplete", # Django HTMX Autocomplete
"health_check", # Health checks
"health_check.db",
"health_check.cache",
"health_check.storage",
"health_check.contrib.migrations",
"health_check.contrib.redis",
"django_celery_beat", # Celery beat scheduler
"django_celery_results", # Celery result backend
"django_extensions", # Django Extensions for enhanced development tools
]
LOCAL_APPS = [
"apps.core",
"apps.accounts",
"apps.parks",
"apps.rides",
"api", # Centralized API app (located at backend/api/)
"django_forwardemail", # New PyPI package for email service
"apps.moderation",
]
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS
# =============================================================================
# Middleware Configuration
# =============================================================================
MIDDLEWARE = [
"django.middleware.cache.UpdateCacheMiddleware", # Must be first for cache middleware
"django.middleware.gzip.GZipMiddleware", # Response compression
"corsheaders.middleware.CorsMiddleware", # CORS middleware for API
"django.middleware.security.SecurityMiddleware",
"apps.core.middleware.security_headers.SecurityHeadersMiddleware", # Custom security headers
"apps.core.middleware.rate_limiting.AuthRateLimitMiddleware", # Rate limiting
"whitenoise.middleware.WhiteNoiseMiddleware",
"apps.core.middleware.performance_middleware.PerformanceMiddleware", # Performance monitoring
"apps.core.middleware.performance_middleware.QueryCountMiddleware", # Database query monitoring
"django.contrib.sessions.middleware.SessionMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"apps.core.middleware.analytics.PgHistoryContextMiddleware", # History context tracking
"allauth.account.middleware.AccountMiddleware",
"django_htmx.middleware.HtmxMiddleware",
"django.middleware.cache.FetchFromCacheMiddleware", # Must be last for cache middleware
]
# =============================================================================
# URL Configuration
# =============================================================================
ROOT_URLCONF = "thrillwiki.urls"
WSGI_APPLICATION = "thrillwiki.wsgi.application"
# =============================================================================
# Template Configuration
# =============================================================================
# Toggle to enable/disable Django template support via env var
TEMPLATES_ENABLED = config("TEMPLATES_ENABLED", default=True, cast=bool)
if TEMPLATES_ENABLED:
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"apps.moderation.context_processors.moderation_access",
"apps.core.context_processors.fsm_context",
"apps.core.context_processors.breadcrumbs",
"apps.core.context_processors.page_meta",
]
},
}
]
else:
# When templates are disabled, still need APP_DIRS=True for DRF Spectacular
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"APP_DIRS": True,
"DIRS": [BASE_DIR / "templates/" / "404"],
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"apps.moderation.context_processors.moderation_access",
"apps.core.context_processors.fsm_context",
"apps.core.context_processors.breadcrumbs",
"apps.core.context_processors.page_meta",
]
},
}
]
# =============================================================================
# Custom User Model
# =============================================================================
AUTH_USER_MODEL = "accounts.User"
# =============================================================================
# Internationalization
# =============================================================================
LANGUAGE_CODE = "en-us"
TIME_ZONE = "America/New_York"
USE_I18N = True
USE_TZ = True
# =============================================================================
# Default Primary Key
# =============================================================================
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
# =============================================================================
# Test Runner
# =============================================================================
TEST_RUNNER = "django.test.runner.DiscoverRunner"
# =============================================================================
# Import Modular Settings
# =============================================================================
# Import settings from modular configuration files.
# These imports add/override settings defined above.
# Database configuration (DATABASES, GDAL_LIBRARY_PATH, GEOS_LIBRARY_PATH)
from config.settings.database import * # noqa: F401,F403,E402
# Cache configuration (CACHES, SESSION_*, CACHE_MIDDLEWARE_*)
from config.settings.cache import * # noqa: F401,F403,E402
# Security configuration (SECURE_*, CSRF_*, SESSION_COOKIE_*, AUTH_PASSWORD_VALIDATORS)
from config.settings.security import * # noqa: F401,F403,E402
# Email configuration (EMAIL_*, FORWARD_EMAIL_*)
from config.settings.email import * # noqa: F401,F403,E402
# Logging configuration (LOGGING)
from config.settings.logging import * # noqa: F401,F403,E402
# REST Framework configuration (REST_FRAMEWORK, CORS_*, SIMPLE_JWT, REST_AUTH, SPECTACULAR_SETTINGS)
from config.settings.rest_framework import * # noqa: F401,F403,E402
# Third-party configuration (ACCOUNT_*, SOCIALACCOUNT_*, CLOUDFLARE_IMAGES, etc.)
from config.settings.third_party import * # noqa: F401,F403,E402
# Storage configuration (STATIC_*, MEDIA_*, STORAGES, WHITENOISE_*, FILE_UPLOAD_*)
from config.settings.storage import * # noqa: F401,F403,E402
# =============================================================================
# Post-Import Overrides
# =============================================================================
# Settings that need to reference values from imported modules
# Update SimpleJWT to use the SECRET_KEY
SIMPLE_JWT["SIGNING_KEY"] = SECRET_KEY # noqa: F405
# =============================================================================
# Startup Validation
# =============================================================================
# Run configuration validation after all settings are loaded.
# These validations catch configuration errors early during Django startup.
from config.settings.secrets import run_startup_validation as validate_secrets # noqa: E402
from config.settings.validation import run_startup_validation as validate_config # noqa: E402
# Run secret validation (fails fast in production, warns in development)
validate_secrets()
# Run configuration validation (fails fast in production, warns in development)
validate_config()