Files
accounting-backend/config/settings.py
AmirAli Angha 2a1918b47c Prepare accounting backend for production behind nginx and CDN proxy.
Add reverse-proxy settings, stricter CORS origin parsing, and production env defaults for acc.zoneco.org and the admin panel.
2026-07-08 02:11:32 +03:30

159 lines
4.5 KiB
Python

"""
Settings for the standalone FunZone Accounting backend.
This service is fully decoupled from the main FunZone backend. It stores its own
accounting data in its own database and authorizes requests statelessly using
admin JWTs minted by the FunZone backend (validated with the shared SECRET_KEY).
"""
from datetime import timedelta
from pathlib import Path
from decouple import config
BASE_DIR = Path(__file__).resolve().parent.parent
# Must match the FunZone backend SECRET_KEY so admin JWTs validate here.
SECRET_KEY = config('SECRET_KEY', default='your-super-secret-key-change-in-production')
DEBUG = config('DEBUG', default=True, cast=bool)
ALLOWED_HOSTS = [
host.strip()
for host in config(
'ALLOWED_HOSTS',
default='localhost,127.0.0.1,0.0.0.0,testserver',
).split(',')
if host.strip()
]
# Behind nginx / CDN reverse proxy
USE_X_FORWARDED_HOST = config('USE_X_FORWARDED_HOST', default=False, cast=bool)
if config('SECURE_PROXY_SSL_HEADER', default=False, cast=bool):
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
INSTALLED_APPS = [
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.staticfiles',
'rest_framework',
'rest_framework_simplejwt',
'corsheaders',
'accounting',
]
MIDDLEWARE = [
'corsheaders.middleware.CorsMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.middleware.common.CommonMiddleware',
]
ROOT_URLCONF = 'config.urls'
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {'context_processors': []},
},
]
WSGI_APPLICATION = 'config.wsgi.application'
ASGI_APPLICATION = 'config.asgi.application'
# Database: SQLite by default for zero-setup standalone runs; override via env.
DATABASE_URL = config('DATABASE_URL', default=None)
if DATABASE_URL:
import re
match = re.match(r'postgresql://([^:]+):([^@]+)@([^:]+):(\d+)/(.+)', DATABASE_URL)
if match:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': match.group(5),
'USER': match.group(1),
'PASSWORD': match.group(2),
'HOST': match.group(3),
'PORT': match.group(4),
}
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': config('SQLITE_PATH', default=str(BASE_DIR / 'db.sqlite3')),
}
}
else:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': config('SQLITE_PATH', default=str(BASE_DIR / 'db.sqlite3')),
}
}
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_TZ = True
STATIC_URL = '/static/'
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
REST_FRAMEWORK = {
'DEFAULT_RENDERER_CLASSES': ['rest_framework.renderers.JSONRenderer'],
'DEFAULT_PARSER_CLASSES': ['rest_framework.parsers.JSONParser'],
# Stateless: build the user from token claims, never touch a user table.
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTTokenUserAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated'],
}
# Mirror the FunZone JWT settings so tokens validate identically.
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=60),
'REFRESH_TOKEN_LIFETIME': timedelta(days=7),
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'AUTH_HEADER_TYPES': ('Bearer',),
'USER_ID_FIELD': 'id',
'USER_ID_CLAIM': 'user_id',
'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
'TOKEN_TYPE_CLAIM': 'token_type',
'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
}
# CORS: allow the accounting frontend (and others) in development.
CORS_ALLOW_ALL_ORIGINS = config('CORS_ALLOW_ALL_ORIGINS', default=True, cast=bool)
CORS_ALLOW_CREDENTIALS = True
CORS_ALLOWED_ORIGINS = [
origin.strip()
for origin in config(
'CORS_ALLOWED_ORIGINS',
default='http://localhost:5176,http://127.0.0.1:5176',
).split(',')
if origin.strip()
]
CORS_ALLOW_HEADERS = [
'accept',
'accept-encoding',
'authorization',
'content-type',
'dnt',
'origin',
'user-agent',
'x-csrftoken',
'x-requested-with',
]
CORS_ALLOW_METHODS = [
'DELETE',
'GET',
'OPTIONS',
'PATCH',
'POST',
'PUT',
]