# ============================================================ # Frappe ERP — управление стеком # Использование: make # ============================================================ SHELL := /bin/bash SITE ?= erp.local TAG ?= v16 COMPOSE_OVERRIDES := \ -f compose.yaml \ -f overrides/compose.mariadb.yaml \ -f overrides/compose.redis.yaml \ -f overrides/compose.assets-volume.yaml \ -f overrides/compose.noproxy.yaml \ -f overrides/compose.local-origin.yaml \ -f overrides/compose.backup-cron.yaml COMPOSE_DEV := $(COMPOSE_OVERRIDES) \ -f overrides/compose.picking-dev.yaml APPS_JSON_B64 := $(shell base64 -w 0 apps.json) # Приложения с pre-built esbuild-бандлами (public/dist/). # Vue SPA (crm, builder, helpdesk, insights, gameplan, drive) используют public/frontend/ — # они синхронизируются отдельной веткой внутри sync-assets. DIST_APPS := frappe erpnext hrms lms print_designer webshop education lending newsletter # Имя именованного тома Docker Compose (проект = имя директории) COMPOSE_PROJECT := $(notdir $(CURDIR)) ASSETS_VOL := $(COMPOSE_PROJECT)_assets .PHONY: help build up down restart recreate-frontend update migrate assets sync-assets backup logs ps shell # ── Справка ───────────────────────────────────────────────── help: @echo "" @echo " Frappe ERP — доступные команды:" @echo "" @echo " Образ:" @echo " make build — собрать frappe-custom:$(TAG) из apps.json" @echo " make build TAG=v17 — собрать с другим тегом" @echo "" @echo " Стек:" @echo " make up — запустить все контейнеры" @echo " make down — остановить и удалить контейнеры" @echo " make restart — перезапустить backend/frontend" @echo " make ps — статус контейнеров" @echo "" @echo " Обновление:" @echo " make update — rebuild образа + up + migrate + assets" @echo " make migrate — bench migrate на сайте $(SITE)" @echo " make assets — пересобрать JS/CSS бандлы и синхронизировать" @echo " make sync-assets — скопировать dist в assets volume (очищает кэш, затем копирует)" @echo "" @echo " Обслуживание:" @echo " make backup — создать резервную копию сайта" @echo " make logs — логи backend (live)" @echo " make shell — bash в backend контейнере" @echo "" # ── Сборка образа ──────────────────────────────────────────── build: @echo "→ Сборка frappe-custom:$(TAG) из apps.json..." docker build \ --build-arg APPS_JSON_BASE64=$(APPS_JSON_B64) \ --build-arg FRAPPE_BRANCH=version-16 \ -t frappe-custom:$(TAG) \ -f images/layered/Containerfile \ . @echo "✓ Образ frappe-custom:$(TAG) готов" # ── Запуск стека ───────────────────────────────────────────── up: docker compose $(COMPOSE_OVERRIDES) up -d @echo "✓ Стек запущен. Сайт: http://localhost:$${HTTP_PUBLISH_PORT:-8090}" down: docker compose $(COMPOSE_OVERRIDES) down restart: docker compose $(COMPOSE_OVERRIDES) restart backend frontend websocket recreate-frontend: docker compose $(COMPOSE_OVERRIDES) up -d --no-deps --force-recreate frontend ps: docker compose $(COMPOSE_OVERRIDES) ps # ── Обновление (полный цикл) ───────────────────────────────── update: build @echo "→ Пересоздаём контейнеры с новым образом..." docker compose $(COMPOSE_OVERRIDES) up -d --no-deps backend websocket queue-short queue-long scheduler @echo "→ Ждём готовности backend..." sleep 10 $(MAKE) migrate $(MAKE) assets docker compose $(COMPOSE_OVERRIDES) restart frontend @echo "✓ Обновление завершено" # ── Миграции БД ────────────────────────────────────────────── migrate: @echo "→ bench migrate --site $(SITE)..." docker compose $(COMPOSE_OVERRIDES) exec backend \ bench --site $(SITE) migrate @echo "✓ Миграция завершена" # ── Пересборка JS/CSS ──────────────────────────────────────── assets: @echo "→ Пересборка assets (bench build --production)..." docker compose $(COMPOSE_OVERRIDES) exec backend bench build --production $(MAKE) sync-assets @echo "✓ Assets пересобраны" # ── Синхронизация dist → frappe-project_assets volume ──────── # bench build пишет файлы в overlay-слой backend-контейнера, а nginx # читает из именованного тома. Эта цель копирует dist-файлы туда. sync-assets: @echo "→ Сброс кэша перед синхронизацией (предотвращает пересоздание симлинков)..." @docker compose $(COMPOSE_OVERRIDES) exec backend \ bench --site $(SITE) clear-cache @docker compose $(COMPOSE_OVERRIDES) exec backend bash -c \ ". /home/frappe/frappe-bench/env/bin/activate && \ python -c \"import redis; r=redis.Redis(host='redis-cache'); \ deleted=r.delete('assets_json'); \ print('assets_json удалён из Redis' if deleted else 'assets_json отсутствовал')\"" @echo "→ Синхронизация dist-файлов в $(ASSETS_VOL)..." @TMPDIR=$$(mktemp -d) && \ trap "rm -rf $$TMPDIR" EXIT && \ BACKEND=$$(docker compose $(COMPOSE_OVERRIDES) ps -q backend) && \ docker cp $$BACKEND:/home/frappe/frappe-bench/sites/assets/assets.json \ $$TMPDIR/assets.json && \ for app in $(DIST_APPS); do \ SRC=/home/frappe/frappe-bench/apps/$$app/$$app/public/dist; \ if docker cp $$BACKEND:$$SRC $$TMPDIR/$$app-dist 2>/dev/null; then \ echo " ✓ $$app"; \ else \ echo " - $$app (нет dist, пропущено)"; \ fi; \ done && \ docker run --rm \ -v $$TMPDIR:/src:ro \ -v $(ASSETS_VOL):/assets \ alpine sh -c ' \ cp -f /src/assets.json /assets/assets.json; \ for d in /src/*-dist; do \ [ -d "$$d" ] || continue; \ app=$$(basename "$$d" -dist); \ if [ -L "/assets/$$app" ]; then rm -f "/assets/$$app"; \ elif [ -d "/assets/$$app" ]; then rm -rf "/assets/$$app"; fi; \ mkdir -p "/assets/$$app/dist"; \ cp -rf "$$d/." "/assets/$$app/dist/"; \ done \ ' @docker compose $(COMPOSE_OVERRIDES) up -d --no-deps --force-recreate frontend @echo "✓ Синхронизация завершена" # ── Резервная копия ────────────────────────────────────────── backup: @echo "→ Создание резервной копии сайта $(SITE)..." docker compose $(COMPOSE_OVERRIDES) exec backend \ bench --site $(SITE) backup --with-files @echo "✓ Бэкап создан (см. sites/$(SITE)/private/backups/)" # ── Разработка picking_app ─────────────────────────────────── # Монтирует /home/mkr/picking_app как volume — изменения в VS Code # сразу видны без пересборки образа. dev-up: docker compose $(COMPOSE_DEV) up -d --no-deps --force-recreate \ backend websocket queue-short queue-long scheduler @echo "→ Пересоздаём frontend (сброс кешированных IP backend)..." docker compose $(COMPOSE_OVERRIDES) up -d --no-deps --force-recreate frontend @echo "✓ Dev-режим активен. Исходники: /home/mkr/picking_app" @echo " Страница: http://localhost:8090/app/picking-mobile" dev-down: docker compose $(COMPOSE_OVERRIDES) up -d --no-deps --force-recreate \ backend websocket queue-short queue-long scheduler docker compose $(COMPOSE_OVERRIDES) restart frontend @echo "✓ Dev-режим выключен, volume-монтирование снято" dev-reload: @echo "→ Сброс кэша Frappe..." docker compose $(COMPOSE_DEV) exec backend bench --site $(SITE) clear-cache @echo "✓ Кэш сброшен — перезагрузи страницу в браузере" # ── Логи и отладка ─────────────────────────────────────────── logs: docker compose $(COMPOSE_OVERRIDES) logs -f backend logs-picking: docker compose $(COMPOSE_OVERRIDES) logs -f backend | grep -i "picking\|error\|exception\|traceback" --color shell: docker compose $(COMPOSE_OVERRIDES) exec backend bash