From 2da6c8e240375cfc81eed18dbde17cc03f41de7e Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Thu, 19 Feb 2026 18:23:11 +0100 Subject: [PATCH 1/3] fixed container dns resolution, improved scheduling timezone logic, and renamed sync job --- backend/api/migrations/0029_alter_job_name.py | 18 ++++++++++++++++++ backend/api/models.py | 2 +- backend/api/views.py | 9 ++++++++- docker-compose.yml | 6 ++++++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 backend/api/migrations/0029_alter_job_name.py diff --git a/backend/api/migrations/0029_alter_job_name.py b/backend/api/migrations/0029_alter_job_name.py new file mode 100644 index 0000000..8cb8538 --- /dev/null +++ b/backend/api/migrations/0029_alter_job_name.py @@ -0,0 +1,18 @@ +# Generated by Django 6.0.2 on 2026-02-19 17:22 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('api', '0028_job_systemconfig'), + ] + + operations = [ + migrations.AlterField( + model_name='job', + name='name', + field=models.CharField(choices=[('sync_flavors', 'Sync Holy Flavors'), ('cleanup_duplicates', 'Cleanup Duplicate Flavors'), ('backup_db', 'Database Backup'), ('seed_legacy', 'Seed Legacy Data')], max_length=100), + ), + ] diff --git a/backend/api/models.py b/backend/api/models.py index 1c61c37..0a86957 100644 --- a/backend/api/models.py +++ b/backend/api/models.py @@ -241,7 +241,7 @@ class SystemConfig(models.Model): class Job(models.Model): """Tracks background jobs, their status and scheduling.""" JOB_TYPES = [ - ('sync_flavors', 'Sync Shopify Flavors'), + ('sync_flavors', 'Sync Holy Flavors'), ('cleanup_duplicates', 'Cleanup Duplicate Flavors'), ('backup_db', 'Database Backup'), ('seed_legacy', 'Seed Legacy Data'), diff --git a/backend/api/views.py b/backend/api/views.py index b523b06..24f1e11 100644 --- a/backend/api/views.py +++ b/backend/api/views.py @@ -919,7 +919,14 @@ class AdminViewSet(viewsets.ViewSet): if next_run is not None: from django.utils.dateparse import parse_datetime - job.next_run = parse_datetime(next_run) + from django.utils import timezone + parsed_dt = parse_datetime(next_run) + if parsed_dt: + # If it's naive (has no timezone info), assume it's local time + if timezone.is_naive(parsed_dt): + job.next_run = timezone.make_aware(parsed_dt, timezone.get_current_timezone()) + else: + job.next_run = parsed_dt elif interval is not None and job.interval_hours > 0 and not job.next_run: from django.utils import timezone job.next_run = timezone.now() diff --git a/docker-compose.yml b/docker-compose.yml index 6250a53..de97f3a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,6 +14,9 @@ services: - ./legacy:/app/legacy environment: - PYTHONUNBUFFERED=1 + dns: + - 8.8.8.8 + - 1.1.1.1 labels: - "traefik.enable=true" - "traefik.docker.network=narl" @@ -38,6 +41,9 @@ services: restart: unless-stopped networks: - internal + dns: + - 8.8.8.8 + - 1.1.1.1 env_file: - .env volumes: From 8d3e8ebf1850b8a206033e1a997ed2c06efeb85e Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Thu, 19 Feb 2026 18:27:19 +0100 Subject: [PATCH 2/3] simplified .env configuration with DOMAIN-based defaults and improved docker-compose orchestration --- .env.example | 24 ++++++++++++------------ backend/holy_backend/settings.py | 21 ++++++++++++++------- docker-compose.yml | 9 ++++++--- 3 files changed, 32 insertions(+), 22 deletions(-) diff --git a/.env.example b/.env.example index e6a8dd7..529be19 100644 --- a/.env.example +++ b/.env.example @@ -1,4 +1,7 @@ -# --- Application Security --- +# --- Essential Site Configuration --- +# Your primary domain (e.g., holy.narl.io). Used to derive ALLOWED_HOSTS, CORS, and CSRF settings. +DOMAIN="localhost" + # Set to a long, random string in production (e.g. 50+ chars) SECRET_KEY="django-insecure-replace-this-in-production" @@ -8,15 +11,12 @@ DEBUG=true # Custom URL for the Django Admin interface (e.g., my-secret-admin/) ADMIN_URL="admin" -# --- Hosting & Networking --- -# The primary domain where your app is hosted (e.g., holy.narl.io) -ALLOWED_HOSTS=localhost,127.0.0.1,backend,holy.narl.io - -# CSRF protection: Comma-separated list of trusted origins (MUST start with https:// in production) -CSRF_TRUSTED_ORIGINS=https://holy.narl.io - -# CORS protection: Comma-separated list of allowed origins -CORS_ALLOWED_ORIGINS=https://holy.narl.io +# --- Advanced Networking (Optional, derived from DOMAIN if unset) --- +# ALLOWED_HOSTS=holy.narl.io,another-domain.com +# CSRF_TRUSTED_ORIGINS=https://holy.narl.io +# CORS_ALLOWED_ORIGINS=https://holy.narl.io +# FRONTEND_URL=https://holy.narl.io +# VITE_API_URL=https://holy.narl.io/api/ # --- SMTP Configuration (Required for Email Verification) --- # For development, if EMAIL_HOST is empty, emails are printed to the console. @@ -32,8 +32,8 @@ EMAIL_HOST_PASSWORD="your-password" EMAIL_SKIP_CERT_VERIFICATION=false # --- Frontend Configuration --- -# The base URL of the backend API (MUST end with /api/) -VITE_API_URL=https://holy.narl.io/api/ +# Optional: defaults to ${DOMAIN}/api/ if not set +# VITE_API_URL=https://holy.narl.io/api/ VITE_ALLOWED_HOSTS=localhost,holy.narl.io # --- Impressum / Contact Details (Required for German Law ยง 5 TMG) --- diff --git a/backend/holy_backend/settings.py b/backend/holy_backend/settings.py index 7ec54cf..3ad0a8d 100644 --- a/backend/holy_backend/settings.py +++ b/backend/holy_backend/settings.py @@ -26,8 +26,17 @@ SECRET_KEY = os.environ.get('SECRET_KEY', 'django-insecure-zos99ue2a89!4jrv4g@_b # SECURITY WARNING: don't run with debug turned on in production! DEBUG = os.environ.get('DEBUG', 'false').lower() == 'true' -ALLOWED_HOSTS_STRING = os.environ.get('ALLOWED_HOSTS', 'localhost,127.0.0.1,backend,holy.narl.io') -ALLOWED_HOSTS = [host.strip() for host in ALLOWED_HOSTS_STRING.split(',')] +# Simplification: Use a single DOMAIN variable to derive multiple settings +DOMAIN = os.environ.get('DOMAIN', 'holy.narl.io') + +# Helper to build lists from env or defaults +def get_env_list(var_name, default_list): + val = os.environ.get(var_name) + if val: + return [item.strip() for item in val.split(',')] + return default_list + +ALLOWED_HOSTS = get_env_list('ALLOWED_HOSTS', ['localhost', '127.0.0.1', 'backend', 'worker', DOMAIN]) # Application definition @@ -166,8 +175,7 @@ if not DEBUG: SECURE_HSTS_PRELOAD = True # Read CSRF trusted origins from environment variable -CSRF_TRUSTED_ORIGINS_STRING = os.environ.get('CSRF_TRUSTED_ORIGINS', 'https://holy.narl.io,http://localhost:5173') -CSRF_TRUSTED_ORIGINS = [origin.strip() for origin in CSRF_TRUSTED_ORIGINS_STRING.split(',')] +CSRF_TRUSTED_ORIGINS = get_env_list('CSRF_TRUSTED_ORIGINS', [f'https://{DOMAIN}', 'http://localhost:5173']) # Custom User Model AUTH_USER_MODEL = 'api.User' @@ -188,10 +196,9 @@ REST_FRAMEWORK = { } # CORS -CORS_ALLOWED_ORIGINS_STRING = os.environ.get('CORS_ALLOWED_ORIGINS', 'https://holy.narl.io,http://localhost:5173,http://127.0.0.1:5173') -CORS_ALLOWED_ORIGINS = [origin.strip() for origin in CORS_ALLOWED_ORIGINS_STRING.split(',')] +CORS_ALLOWED_ORIGINS = get_env_list('CORS_ALLOWED_ORIGINS', [f'https://{DOMAIN}', 'http://localhost:5173', 'http://127.0.0.1:5173']) -FRONTEND_URL = os.environ.get('FRONTEND_URL', 'https://holy.narl.io').rstrip('/') +FRONTEND_URL = os.environ.get('FRONTEND_URL', f'https://{DOMAIN}').rstrip('/') import os # ... (near top of file) diff --git a/docker-compose.yml b/docker-compose.yml index de97f3a..fc3ecd1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -14,6 +14,7 @@ services: - ./legacy:/app/legacy environment: - PYTHONUNBUFFERED=1 + - DOMAIN=${DOMAIN:-holy.narl.io} dns: - 8.8.8.8 - 1.1.1.1 @@ -22,7 +23,7 @@ services: - "traefik.docker.network=narl" # Ultra-clean rule for maximum Traefik compatibility - "traefik.http.routers.holy-energy-backend.priority=100" - - "traefik.http.routers.holy-energy-backend.rule=Host(`holy.narl.io`) && (PathPrefix(`/api`) || PathPrefix(`/admin/`) || PathPrefix(`/static`) || PathPrefix(`/media`))" + - "traefik.http.routers.holy-energy-backend.rule=Host(`${DOMAIN:-holy.narl.io}`) && (PathPrefix(`/api`) || PathPrefix(`/admin/`) || PathPrefix(`/static`) || PathPrefix(`/media`))" - "traefik.http.routers.holy-energy-backend.entrypoints=websecure" - "traefik.http.routers.holy-energy-backend.tls.certresolver=https_resolver" - "traefik.http.services.holy-energy-backend.loadbalancer.server.port=8000" @@ -46,6 +47,8 @@ services: - 1.1.1.1 env_file: - .env + environment: + - DOMAIN=${DOMAIN:-holy.narl.io} volumes: - ./backend:/app - ./legacy:/app/legacy @@ -57,7 +60,7 @@ services: build: context: ./frontend args: - - VITE_API_URL=https://holy.narl.io/api/ + - VITE_API_URL=https://${DOMAIN:-holy.narl.io}/api/ - VITE_IMPRESSUM_NAME=${VITE_IMPRESSUM_NAME} - VITE_IMPRESSUM_STREET=${VITE_IMPRESSUM_STREET} - VITE_IMPRESSUM_CITY=${VITE_IMPRESSUM_CITY} @@ -76,7 +79,7 @@ services: - "traefik.enable=true" - "traefik.docker.network=narl" - "traefik.http.routers.holy-energy-frontend.priority=10" - - "traefik.http.routers.holy-energy-frontend.rule=Host(`holy.narl.io`)" + - "traefik.http.routers.holy-energy-frontend.rule=Host(`${DOMAIN:-holy.narl.io}`)" - "traefik.http.routers.holy-energy-frontend.entrypoints=websecure" - "traefik.http.routers.holy-energy-frontend.tls.certresolver=https_resolver" - "traefik.http.services.holy-energy-frontend.loadbalancer.server.port=80" From 89a4e51101eec69f51f5c59bbd3de5639f1c01ff Mon Sep 17 00:00:00 2001 From: Nils Pukropp Date: Thu, 19 Feb 2026 18:31:03 +0100 Subject: [PATCH 3/3] added backups and media to gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 99a7f6d..00f5b51 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,5 @@ Thumbs.db !.env.example frontend/.env* backend/django_cache/ +backend/backups/ +backend/media/