From 70151f1225d042df1a074e7130642af9e11ac9fe Mon Sep 17 00:00:00 2001 From: Bleese B Date: Sun, 12 Jul 2026 22:44:03 +0200 Subject: [PATCH] production with django admin template --- backend/core/settings/base.py | 9 +++ backend/entrypoint.sh | 103 ++++------------------------------ docker-compose.prod.yml | 101 +++++++++++++++++++++++++++++++++ docker-compose.yml | 4 +- 4 files changed, 124 insertions(+), 93 deletions(-) create mode 100644 docker-compose.prod.yml diff --git a/backend/core/settings/base.py b/backend/core/settings/base.py index fdfbd19..213ef06 100644 --- a/backend/core/settings/base.py +++ b/backend/core/settings/base.py @@ -11,6 +11,7 @@ SECRET_KEY = os.environ.get('SECRET_KEY', 'django-insecure-fk#ywtdyi8=t6^vdbo!=b DEBUG = os.environ.get('DEBUG', 'True') == 'True' INSTALLED_APPS = [ + 'unfold', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -27,6 +28,14 @@ INSTALLED_APPS = [ 'modules.crm', 'modules.fleet' ] + +UNFOLD = { + 'SITE_TITLE': 'ERP Admin', + 'SITE_HEADER': 'ERP Administration', + 'SITE_SYMBOL': 'dashboard', + 'SHOW_HISTORY': True, +} + MIDDLEWARE = [ 'corsheaders.middleware.CorsMiddleware', # Mora biti prvi 'django.middleware.security.SecurityMiddleware', diff --git a/backend/entrypoint.sh b/backend/entrypoint.sh index 2e20369..b54cee5 100755 --- a/backend/entrypoint.sh +++ b/backend/entrypoint.sh @@ -1,101 +1,22 @@ #!/bin/sh set -e -export PATH="/usr/local/bin:$PATH" - -APP_DIR="/app" -APP_USER="appuser" -APP_UID=1000 -STATIC_ROOT="${STATIC_ROOT:-/app/staticfiles}" -MEDIA_ROOT="${MEDIA_ROOT:-/app/media}" - -# Kreiraj korisnika 'appuser' s UID 1000 ako ne postoji -if ! getent passwd "${APP_USER}" > /dev/null; then - echo "--> Kreiram ${APP_USER}..." - addgroup --system --gid ${APP_UID} ${APP_USER} || true - adduser --system --uid ${APP_UID} --ingroup ${APP_USER} --no-create-home --disabled-login ${APP_USER} || true -fi - -# Ako smo root, pokušaj osigurati ownership. Ako nismo root, samo logiramo i nastavljamo. -if [ "$(id -u)" -eq 0 ]; then - echo "--> (root) Kreiram/ajustiram direktorije i dozvole..." - mkdir -p "${STATIC_ROOT}" "${MEDIA_ROOT}" "${APP_DIR}" - # pokušaj chown, ali ne izlazi na grešku ako neuspije (možda host FS to ne dozvoljava) - if chown -R ${APP_USER}:${APP_USER} "${STATIC_ROOT}" "${MEDIA_ROOT}" "${APP_DIR}"; then - echo "--> Chown uspješan." - else - echo "--> Upozorenje: chown nije uspio (moguće root_squash ili mount bez chown dopuštenja)." - fi -else - echo "--> Nismo root (uid=$(id -u)), preskačem chown. Provjeri vlasništvo na hostu ako su problemi s permisijama." -fi - -# Helper: run command as appuser but return to the script (do not replace shell) -run_as_appuser_now() { - if command -v gosu >/dev/null 2>&1; then - gosu ${APP_USER} "$@" - elif command -v su-exec >/dev/null 2>&1; then - su-exec ${APP_USER} "$@" - elif command -v runuser >/dev/null 2>&1; then - runuser -u ${APP_USER} -- "$@" - else - # If we're already non-root (appuser), run directly; if root and no helpers, run directly anyway (with warning) - if [ "$(id -u)" -ne 0 ]; then - "$@" - else - echo "--> Upozorenje: nema gosu/su-exec/runuser; izvršavam kao root (nepoželjno)." - "$@" - fi - fi -} - -# Helper: exec the given command as appuser (replace current shell / PID 1) -exec_as_appuser() { - # Ako smo već appuser, samo izvrši naredbu direktno - if [ "$(id -u -n)" = "${APP_USER}" ]; then - exec "$@" - # Inače, pokušaj koristiti alate za switch - elif command -v gosu >/dev/null 2>&1; then - exec gosu ${APP_USER} "$@" - elif command -v su-exec >/dev/null 2>&1; then - exec su-exec ${APP_USER} "$@" - else - # Fallback - exec "$@" - fi -} - if [ "$1" = "gunicorn" ]; then - echo "--> Pokrećem migracije..." - # Ako smo root, pokrenimo migrate kao appuser; ako smo non-root (već appuser), pokreni direktno - if [ "$(id -u)" -eq 0 ]; then - run_as_appuser_now python manage.py migrate --noinput - else - python manage.py migrate --noinput - fi + echo "--> Pokrećem migracije..." + python manage.py migrate --noinput - echo "--> Osiguravam prava nad statikom prije collectstatic..." - mkdir -p "${STATIC_ROOT}" - if [ "$(id -u)" -eq 0 ]; then - chown -R ${APP_USER}:${APP_USER} "${STATIC_ROOT}" || echo "--> chown statika nije uspio" - fi + echo "--> Skupljam statiku..." + python manage.py collectstatic --noinput - echo "--> Skupljam statiku..." - if command -v gosu >/dev/null 2>&1 || command -v su-exec >/dev/null 2>&1 || command -v runuser >/dev/null 2>&1; then - run_as_appuser_now python manage.py collectstatic --noinput - else - python manage.py collectstatic --noinput - fi - - echo "--> Pokrećem Gunicorn kao appuser..." - exec_as_appuser gunicorn --bind 0.0.0.0:8000 --workers 3 core.wsgi:application + echo "--> Pokrećem Gunicorn..." + exec gunicorn --bind 0.0.0.0:8000 --workers 3 core.wsgi:application elif [ "$1" = "celery" ]; then - echo "--> Pokrećem Celery kao appuser..." - shift - # Replace PID1 with celery running as appuser - exec_as_appuser celery "$@" + echo "--> Pokrećem Celery..." + shift + exec celery "$@" else - exec "$@" -fi \ No newline at end of file + exec "$@" +fi + diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml new file mode 100644 index 0000000..56f9fbd --- /dev/null +++ b/docker-compose.prod.yml @@ -0,0 +1,101 @@ +services: + db: + restart: unless-stopped + + redis: + restart: unless-stopped + + backend: + build: + context: ./backend + dockerfile: Dockerfile + container_name: 004erpbackend + restart: unless-stopped + env_file: + - .env + environment: + DJANGO_SETTINGS_MODULE: core.settings.production + command: gunicorn core.wsgi:application --bind 0.0.0.0:8000 --workers 3 --timeout 120 + volumes: + - media_volume:/app/media + ports: + - "8001:8000" + depends_on: + db: + condition: service_healthy + redis: + condition: service_started + + worker: + build: + context: ./backend + dockerfile: Dockerfile + container_name: 004erpworker + restart: unless-stopped + env_file: + - .env + environment: + DEBUG: "False" + DJANGO_SETTINGS_MODULE: core.settings.production + command: celery -A core worker --loglevel=info + volumes: + - media_volume:/app/media + depends_on: + db: + condition: service_healthy + redis: + condition: service_started + + flower: + build: + context: ./backend + dockerfile: Dockerfile + container_name: 004erpflower + restart: unless-stopped + env_file: + - .env + environment: + DEBUG: "False" + DJANGO_SETTINGS_MODULE: core.settings.production + command: celery -A core flower --port=5555 + ports: + - "5555:5555" + depends_on: + redis: + condition: service_started + worker: + condition: service_started + + frontend: + build: + context: ./frontend + dockerfile: Dockerfile + container_name: 004erpfrontend + restart: unless-stopped + environment: + NODE_ENV: production + PUBLIC_API_URL: ${PUBLIC_API_URL} + command: sh -c "npm run build && node ./dist/server/entry.mjs" + ports: + - "4321:4321" + depends_on: + backend: + condition: service_started + + webhook: + build: /opt/erp/deploy-webhook + container_name: 004erpwebhook + restart: unless-stopped + environment: + WEBHOOK_SECRET: ${GITEA_WEBHOOK_SECRET} + ports: + - "9001:9001" + volumes: + - /opt/erp/app:/opt/erp/app + - /var/run/docker.sock:/var/run/docker.sock + +volumes: + postgres_data: + redis_data: + media_volume: + external: true diff --git a/docker-compose.yml b/docker-compose.yml index 1608c2c..c840959 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -27,7 +27,7 @@ services: context: ./backend dockerfile: Dockerfile command: celery -A core worker --loglevel=info - user: "1000:1000" + user: "1001:1001" volumes: - ./backend:/app - media_volume:/app/media @@ -44,4 +44,4 @@ services: volumes: postgres_data: redis_data: - media_volume: # Ovo je ključno za tvoj ERP \ No newline at end of file + media_volume: # Ovo je ključno za tvoj ERP