453 lines
14 KiB
Python
453 lines
14 KiB
Python
# /home/ram/aparsoft/backend/config/settings/development.py
|
|
|
|
# config/settings/development.py
|
|
|
|
from .base import *
|
|
import os
|
|
from decouple import config
|
|
from datetime import timedelta
|
|
|
|
# SECURITY WARNING: don't run with debug turned on in production!
|
|
DEBUG = True
|
|
|
|
# Create logs directory if it doesn't exist
|
|
LOGS_DIR = BASE_DIR / "logs"
|
|
if not LOGS_DIR.exists():
|
|
os.makedirs(LOGS_DIR, exist_ok=True)
|
|
|
|
MIDDLEWARE = [
|
|
"django.middleware.security.SecurityMiddleware",
|
|
"corsheaders.middleware.CorsMiddleware",
|
|
"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",
|
|
# Add the account middleware:
|
|
"allauth.account.middleware.AccountMiddleware",
|
|
]
|
|
|
|
AUTHENTICATION_BACKENDS = (
|
|
# 'users.backends.EmailBackend',
|
|
# 'social_core.backends.google.GoogleOAuth2',
|
|
# Needed to login by username in Django admin, regardless of `allauth`
|
|
"django.contrib.auth.backends.ModelBackend",
|
|
# `allauth` specific authentication methods, such as login by email
|
|
"allauth.account.auth_backends.AuthenticationBackend",
|
|
)
|
|
|
|
# Postgres
|
|
DATABASES = {
|
|
"default": {
|
|
"ENGINE": "django.db.backends.postgresql",
|
|
"NAME": config("DB_NAME", default="chatbotdb"),
|
|
"USER": config("DB_USER", default="chatbot_user"),
|
|
"PASSWORD": config("DB_PASSWORD", default="chatbot_pass"),
|
|
"HOST": config("DB_HOST", default="localhost"),
|
|
"PORT": config("DB_PORT", default="5432"),
|
|
"OPTIONS": {
|
|
"sslmode": "disable", # Disables SSL for local development
|
|
},
|
|
}
|
|
}
|
|
|
|
PGVECTOR_CONNECTION_STRING = config("PGVECTOR_CONNECTION_STRING")
|
|
PG_CHECKPOINT_URI = config("PG_CHECKPOINT_URI")
|
|
|
|
# Fix the encoding issue - add these lines
|
|
if "\\x3a" in PGVECTOR_CONNECTION_STRING:
|
|
PGVECTOR_CONNECTION_STRING = PGVECTOR_CONNECTION_STRING.replace("\\x3a", ":")
|
|
|
|
if "\\x3a" in PG_CHECKPOINT_URI:
|
|
PG_CHECKPOINT_URI = PG_CHECKPOINT_URI.replace("\\x3a", ":")
|
|
|
|
STATIC_URL = "/static/"
|
|
STATICFILES_DIRS = [
|
|
BASE_DIR / "static",
|
|
]
|
|
# Ensure static files directory exists
|
|
STATIC_ROOT = BASE_DIR / "staticfiles"
|
|
STATIC_ROOT.mkdir(exist_ok=True)
|
|
if STATIC_ROOT.exists():
|
|
os.chmod(STATIC_ROOT, 0o755)
|
|
|
|
MEDIA_URL = "/media/"
|
|
MEDIA_ROOT = BASE_DIR / "media"
|
|
MEDIA_ROOT.mkdir(exist_ok=True)
|
|
if MEDIA_ROOT.exists():
|
|
os.chmod(MEDIA_ROOT, 0o755)
|
|
|
|
# File upload configurations
|
|
FILE_UPLOAD_PERMISSIONS = 0o644
|
|
FILE_UPLOAD_DIRECTORY_PERMISSIONS = 0o755
|
|
FILE_UPLOAD_MAX_MEMORY_SIZE = 5242880 # 5 MB
|
|
|
|
STATICFILES_STORAGE = "django.contrib.staticfiles.storage.StaticFilesStorage"
|
|
STATICFILES_FINDERS = [
|
|
"django.contrib.staticfiles.finders.FileSystemFinder",
|
|
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
|
|
]
|
|
|
|
ALLOWED_HOSTS = [
|
|
"127.0.0.1",
|
|
"localhost",
|
|
]
|
|
|
|
# Custom admin URL
|
|
ADMIN_URL = config("DJANGO_ADMIN_URL", default="chatbot-admin/")
|
|
|
|
# SECURITY WARNING: keep the secret key used in production secret!
|
|
SECRET_KEY = config(
|
|
"DJANGO_SECRET_KEY",
|
|
"django-insecure-p!1w7j+^j5v8y-@$_9j*8mr-)l#$u=08=c)!=(b1dleci18$7+",
|
|
)
|
|
|
|
# Password validation
|
|
AUTH_PASSWORD_VALIDATORS = [
|
|
{
|
|
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
|
},
|
|
{
|
|
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
|
"OPTIONS": {
|
|
"min_length": 8,
|
|
},
|
|
},
|
|
{
|
|
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
|
},
|
|
{
|
|
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
|
},
|
|
]
|
|
|
|
DJANGO_PUBLIC_BASE_URL = config(
|
|
"DJANGO_PUBLIC_BASE_URL", default="http://localhost:8000"
|
|
)
|
|
DJANGO_PUBLIC_API_URL = config(
|
|
"DJANGO_PUBLIC_API_URL", default="http://localhost:8000/api/v1"
|
|
)
|
|
|
|
|
|
# API Keys with defaults (for build process)
|
|
OPENAI_API_KEY = config("OPENAI_API_KEY")
|
|
TAVILY_API_KEY = config("TAVILY_API_KEY")
|
|
ANTHROPIC_API_KEY = config("ANTHROPIC_API_KEY")
|
|
|
|
|
|
# If you need separate keys for dev and prod, you can set them here
|
|
DEFAULT_LLM_PROVIDER = "openai"
|
|
DEFAULT_LLM_MODEL = "gpt-4o-mini"
|
|
DEFAULT_EMBEDDING_MODEL = "text-embedding-3-small"
|
|
REQUEST_GPT_TIMEOUT = 30
|
|
|
|
CORS_ALLOW_CREDENTIALS = True
|
|
# CORS settings
|
|
CORS_ALLOWED_ORIGINS = [
|
|
"http://localhost:3000", # Next.js development server
|
|
"http://127.0.0.1:3000",
|
|
"http://localhost:8000",
|
|
"http://docserve.localhost:8000",
|
|
]
|
|
|
|
# CSRF Trusted Origins
|
|
CSRF_TRUSTED_ORIGINS = [
|
|
"http://localhost:3000",
|
|
"http://127.0.0.1:3000",
|
|
"http://localhost:8000",
|
|
"http://docserve.localhost:8000",
|
|
]
|
|
|
|
CSRF_COOKIE_SECURE = False # Set to True in production with HTTPS
|
|
CSRF_COOKIE_HTTPONLY = False # Set to True in production
|
|
CSRF_COOKIE_SAMESITE = "Lax"
|
|
CSRF_USE_SESSIONS = False
|
|
CSRF_COOKIE_NAME = "csrftoken"
|
|
|
|
SESSION_COOKIE_SECURE = False # Set to True in production with HTTPS
|
|
SESSION_COOKIE_HTTPONLY = True
|
|
SESSION_COOKIE_SAMESITE = "Lax"
|
|
|
|
CORS_ALLOW_METHODS = [
|
|
"DELETE",
|
|
"GET",
|
|
"OPTIONS",
|
|
"PATCH",
|
|
"POST",
|
|
"PUT",
|
|
]
|
|
CORS_ALLOW_HEADERS = [
|
|
"accept",
|
|
"accept-encoding",
|
|
"authorization",
|
|
"content-type",
|
|
"dnt",
|
|
"origin",
|
|
"user-agent",
|
|
"x-csrftoken",
|
|
"x-csrf-token",
|
|
"csrf-token",
|
|
"csrftoken",
|
|
"x-requested-with",
|
|
"cache-control",
|
|
"pragma",
|
|
"expires",
|
|
]
|
|
|
|
# Redis and Celery Configuration
|
|
REDIS_URL = config("REDIS_URL", default="redis://localhost:6379/0")
|
|
|
|
# Celery Settings
|
|
CELERY_BROKER_URL = config("CELERY_BROKER_URL", default="redis://localhost:6379/1")
|
|
CELERY_RESULT_BACKEND = config("CELERY_RESULT_BACKEND", default="redis://localhost:6379/2")
|
|
|
|
# Celery Configuration Options
|
|
CELERY_TASK_TRACK_STARTED = True
|
|
CELERY_TASK_TIME_LIMIT = 30 * 60
|
|
CELERY_ACCEPT_CONTENT = ["json"]
|
|
CELERY_TASK_SERIALIZER = "json"
|
|
CELERY_RESULT_SERIALIZER = "json"
|
|
CELERY_TIMEZONE = "UTC"
|
|
|
|
# Broker and Result Backend Transport Options
|
|
CELERY_BROKER_TRANSPORT_OPTIONS = {
|
|
"visibility_timeout": 3600, # 1 hour
|
|
"max_retries": 3,
|
|
}
|
|
|
|
CELERY_RESULT_BACKEND_TRANSPORT_OPTIONS = {
|
|
"retry_policy": {
|
|
"timeout": 5.0,
|
|
"max_retries": 3,
|
|
}
|
|
}
|
|
|
|
# Channel Layers Configuration (for Django Channels)
|
|
CHANNEL_LAYERS = {
|
|
"default": {
|
|
"BACKEND": "channels_redis.core.RedisChannelLayer",
|
|
"CONFIG": {
|
|
"hosts": [REDIS_URL],
|
|
"capacity": 1500,
|
|
"expiry": 20,
|
|
},
|
|
},
|
|
}
|
|
|
|
# Cache Configuration
|
|
CACHES = {
|
|
"default": {
|
|
"BACKEND": "django.core.cache.backends.redis.RedisCache",
|
|
"LOCATION": REDIS_URL,
|
|
"OPTIONS": {
|
|
"db": "1",
|
|
"pool_class": "redis.connection.ConnectionPool",
|
|
"socket_timeout": 5,
|
|
"socket_connect_timeout": 5,
|
|
"retry_on_timeout": True,
|
|
"max_connections": 100,
|
|
},
|
|
"KEY_PREFIX": "nlp_playground",
|
|
}
|
|
}
|
|
|
|
# Base REST_FRAMEWORK settings (can be extended in environment settings)
|
|
REST_FRAMEWORK = {
|
|
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.LimitOffsetPagination",
|
|
"PAGE_SIZE": int(config("DJANGO_PAGINATION_LIMIT", 18)),
|
|
"DEFAULT_FILTER_BACKENDS": [
|
|
"django_filters.rest_framework.DjangoFilterBackend",
|
|
"rest_framework.filters.OrderingFilter",
|
|
],
|
|
"DEFAULT_AUTHENTICATION_CLASSES": [
|
|
# "accounts.services.CustomJWTCookieAuthentication",
|
|
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
|
"rest_framework.authentication.SessionAuthentication",
|
|
"rest_framework.authentication.BasicAuthentication",
|
|
],
|
|
"DEFAULT_PERMISSION_CLASSES": [
|
|
"rest_framework.permissions.IsAuthenticated",
|
|
],
|
|
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
|
"DEFAULT_THROTTLE_CLASSES": [
|
|
"rest_framework.throttling.AnonRateThrottle",
|
|
"rest_framework.throttling.UserRateThrottle",
|
|
"rest_framework.throttling.ScopedRateThrottle",
|
|
],
|
|
"DEFAULT_THROTTLE_RATES": {
|
|
"anon": "100/minute",
|
|
"user": "200/minute",
|
|
"login": "30/minute",
|
|
},
|
|
}
|
|
|
|
# Security headers
|
|
SECURE_BROWSER_XSS_FILTER = True
|
|
SECURE_CONTENT_TYPE_NOSNIFF = True
|
|
X_FRAME_OPTIONS = "DENY"
|
|
SESSION_EXPIRE_AT_BROWSER_CLOSE = False
|
|
|
|
SIMPLE_JWT = {
|
|
# Token lifetimes
|
|
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
|
|
"REFRESH_TOKEN_LIFETIME": timedelta(days=7),
|
|
# Token rotation settings
|
|
# Disable token rotation to prevent blacklisting issues
|
|
"ROTATE_REFRESH_TOKENS": True, # Enable rotation
|
|
"BLACKLIST_AFTER_ROTATION": True, # Enable blacklisting
|
|
"UPDATE_LAST_LOGIN": False, # Reduce DB hits
|
|
"AUTH_HEADER_TYPES": ("Bearer",),
|
|
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
|
|
# Signing settings
|
|
# 'ALGORITHM': 'HS256',
|
|
# 'SIGNING_KEY': SECRET_KEY,
|
|
# 'VERIFYING_KEY': None,
|
|
# Token validation settings
|
|
# 'AUDIENCE': None,
|
|
# 'ISSUER': None,
|
|
# Header settings
|
|
# 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
|
|
# User settings
|
|
# 'USER_ID_FIELD': 'id',
|
|
# 'USER_ID_CLAIM': 'user_id',
|
|
# Token classes and claims
|
|
# 'TOKEN_TYPE_CLAIM': 'token_type',
|
|
# 'JTI_CLAIM': 'jti',
|
|
# Additional security settings
|
|
# 'TOKEN_USER_CLASS': 'django.contrib.auth.models.User',
|
|
# Use them if required: sliding token settings
|
|
# 'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
|
|
# 'SLIDING_TOKEN_LIFETIME': timedelta(minutes=30),
|
|
# 'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
|
|
}
|
|
|
|
# Frontend URL for email links
|
|
FRONTEND_URL = config("NEXTAUTH_URL", default="http://localhost:3000")
|
|
|
|
# Newsletter email settings for development
|
|
CONTACT_EMAIL = config("CONTACT_EMAIL", default="contact@aparsoft.com")
|
|
AI_TEAM_EMAIL = config("AI_TEAM_EMAIL", default="ai@aparsoft.com")
|
|
ENTERPRISE_TEAM_EMAIL = config(
|
|
"ENTERPRISE_TEAM_EMAIL", default="enterprise@aparsoft.com"
|
|
)
|
|
CONSULTING_TEAM_EMAIL = config(
|
|
"CONSULTING_TEAM_EMAIL", default="consulting@aparsoft.com"
|
|
)
|
|
PARTNERSHIPS_EMAIL = config("PARTNERSHIPS_EMAIL", default="partnerships@aparsoft.com")
|
|
HR_EMAIL = config("HR_EMAIL", default="hr@aparsoft.com")
|
|
SUPPORT_EMAIL = config("SUPPORT_EMAIL", default="support@aparsoft.com")
|
|
|
|
# Email configuration for development (optional)
|
|
# Print emails to console
|
|
EMAIL_BACKEND = "django.core.mail.backends.console.EmailBackend"
|
|
DEFAULT_FROM_EMAIL = config("DEFAULT_FROM_EMAIL", default="noreply@aparsoft.com")
|
|
|
|
# OAuth settings
|
|
OAUTH = {
|
|
"GOOGLE": {
|
|
"CLIENT_ID": "your-google-client-id",
|
|
"CLIENT_SECRET": "your-google-client-secret",
|
|
"REDIRECT_URI": "https://aparsoft.com/auth/callback/google",
|
|
},
|
|
"GITHUB": {
|
|
"CLIENT_ID": "your-github-client-id",
|
|
"CLIENT_SECRET": "your-github-client-secret",
|
|
"REDIRECT_URI": "https://aparsoft.com/auth/callback/github",
|
|
},
|
|
# Add other OAuth providers as needed
|
|
}
|
|
|
|
|
|
LOGGING = {
|
|
"version": 1,
|
|
"disable_existing_loggers": False,
|
|
"formatters": {
|
|
"verbose": {
|
|
# Added {name}
|
|
"format": "[{asctime}] {levelname} [{name}] {message}",
|
|
"style": "{",
|
|
"datefmt": "%Y-%m-%d %H:%M:%S",
|
|
},
|
|
"simple": {
|
|
"format": "[{levelname}] {message}",
|
|
"style": "{",
|
|
},
|
|
},
|
|
"handlers": {
|
|
"console": {
|
|
"class": "logging.StreamHandler",
|
|
"formatter": "simple",
|
|
"level": "INFO",
|
|
},
|
|
"file": {
|
|
"class": "logging.handlers.RotatingFileHandler", # Changed to RotatingFileHandler
|
|
"filename": BASE_DIR / "logs" / "dev-debug.log",
|
|
"formatter": "verbose",
|
|
"level": "INFO",
|
|
"maxBytes": 1024 * 1024 * 5, # 5 MB
|
|
"backupCount": 5,
|
|
"delay": True, # Delay creation until first log record is written
|
|
},
|
|
},
|
|
"loggers": {
|
|
"": { # Root logger
|
|
"handlers": ["console", "file"],
|
|
"level": "INFO",
|
|
"propagate": True,
|
|
},
|
|
"django": {
|
|
"handlers": ["console", "file"],
|
|
"level": "WARNING",
|
|
"propagate": False,
|
|
},
|
|
"django.server": {
|
|
"handlers": ["console"],
|
|
"level": "INFO",
|
|
"propagate": False,
|
|
},
|
|
"accounts": { # Your app logger
|
|
"handlers": ["console", "file"],
|
|
"level": "INFO",
|
|
"propagate": False,
|
|
},
|
|
"jazzmin": {
|
|
"handlers": ["console", "file"],
|
|
"level": "ERROR", # Change to ERROR to suppress warnings
|
|
"propagate": False,
|
|
},
|
|
},
|
|
}
|
|
|
|
JAZZMIN_UI_TWEAKS = {
|
|
"navbar_small_text": False,
|
|
"footer_small_text": False,
|
|
"body_small_text": False,
|
|
"brand_small_text": False,
|
|
"brand_colour": False,
|
|
"accent": "accent-primary",
|
|
"navbar": "navbar-white navbar-light",
|
|
"no_navbar_border": False,
|
|
"navbar_fixed": False,
|
|
"layout_boxed": False,
|
|
"footer_fixed": False,
|
|
"sidebar_fixed": False,
|
|
"sidebar": "sidebar-dark-primary",
|
|
"sidebar_nav_small_text": False,
|
|
"sidebar_disable_expand": False,
|
|
"sidebar_nav_child_indent": False,
|
|
"sidebar_nav_compact_style": False,
|
|
"sidebar_nav_legacy_style": False,
|
|
"sidebar_nav_flat_style": False,
|
|
"theme": "cerulean",
|
|
"dark_mode_theme": None,
|
|
"button_classes": {
|
|
"primary": "btn-outline-primary",
|
|
"secondary": "btn-outline-secondary",
|
|
"info": "btn-info",
|
|
"warning": "btn-warning",
|
|
"danger": "btn-danger",
|
|
"success": "btn-success",
|
|
},
|
|
}
|