# Baron SSO용 Docker Compose 헬퍼 # 환경 변수 로드 ifneq (,$(wildcard ./.env)) include .env export endif # Compose 파일 경로 COMPOSE_INFRA := compose.infra.yaml COMPOSE_ORY := compose.ory.yaml COMPOSE_APP := docker-compose.yaml AUTH_CONFIG_ENV := config/.generated/auth-config.env DEV_SERVICES ?= backend adminfront devfront orgfront userfront DEV_NETWORKS := baron_net ory-net hydranet kratosnet public_net INFRA_CONTAINERS := baron_postgres baron_clickhouse baron_redis baron_gateway ORY_CONTAINERS := ory_postgres ory_kratos ory_hydra ory_keto ory_oathkeeper ory_clickhouse ory_vector APP_CONTAINERS := baron_backend baron_adminfront baron_devfront baron_orgfront baron_userfront DROP_CONTAINERS := $(INFRA_CONTAINERS) $(ORY_CONTAINERS) $(APP_CONTAINERS) ory_stack_check COMPOSE_CLI_ENV_ARGS := ifneq (,$(wildcard ./.env)) COMPOSE_CLI_ENV_ARGS += --env-file .env endif COMPOSE_CLI_ENV_ARGS += --env-file $(AUTH_CONFIG_ENV) COMPOSE_DROP_ENV_ARGS := ifneq (,$(wildcard ./.env)) COMPOSE_DROP_ENV_ARGS += --env-file .env endif DUMP_SERVICES ?= all RESTORE_SERVICES ?= all FILE_PATH ?= RESTORE_INPUT ?= $(or $(FILE_PATH),$(word 2,$(MAKECMDGOALS))) CONFIRM_RESTORE ?= ALLOW_NON_EMPTY_RESTORE ?= false DUMP_MODE ?= maintenance BACKUP_USE_DOCKER ?= true BACKUP_TOOLS_IMAGE ?= baron-sso-backup-tools:local BACKUP_TOOLS_DOCKERFILE ?= docker/backup-tools/Dockerfile BACKUP_DOCKER_ENV_ARGS := ifneq (,$(wildcard ./.env)) BACKUP_DOCKER_ENV_ARGS += --env-file .env endif ifneq (,$(wildcard ./$(AUTH_CONFIG_ENV))) BACKUP_DOCKER_ENV_ARGS += --env-file $(AUTH_CONFIG_ENV) endif BACKUP_DOCKER_RUN = docker run --rm $(BACKUP_DOCKER_ENV_ARGS) -e BACKUP_REPO_ROOT=/workspace -v /var/run/docker.sock:/var/run/docker.sock -v "$(CURDIR)":/workspace -v /tmp:/tmp -w /workspace $(BACKUP_TOOLS_IMAGE) .PHONY: help build-auth-config validate-auth-config verify-auth-config render-ory-config up up-all up-infra up-ory up-app up-backend ensure-networks ensure-infra ensure-ory ensure-restore-containers up-dev up-front-dev dev dev-debug down drop down-app down-backend down-infra down-ory check-infra ps logs-infra logs-ory logs-app backup-tools-build dump restore dump-verify restore-verify dump-list restore-plan upload-cloud dump-upload-cloud help: ## 생성된 타깃과 옵션 목록 표시 @printf "Usage:\n make [OPTION=value ...]\n\n" @printf "Targets:\n" @awk ' \ BEGIN { current = ""; printed_section = 0 } \ /^# --- .+ ---/ { \ current = $$0; \ gsub(/^# ---[[:space:]]*/, "", current); \ gsub(/[[:space:]]*---$$/, "", current); \ next; \ } \ /^[[:alnum:]_.-]+:([^=]|$$)/ { \ line = $$0; \ target = line; \ sub(/:.*/, "", target); \ if (target ~ /^\.|%/) { next } \ if (seen[target]++) { next } \ desc = ""; \ if (line ~ /##/) { \ desc = line; \ sub(/^.*##[[:space:]]*/, "", desc); \ } \ if (current != "" && current != printed_section) { \ printf "\n %s\n", current; \ printed_section = current; \ } \ if (desc != "") { \ printf " %-36s %s\n", target, desc; \ } else { \ printf " %-36s\n", target; \ } \ } \ ' Makefile @printf "\nOptions:\n" @awk ' \ /^[A-Z][A-Z0-9_]+[[:space:]]*\?=/ { \ name = $$1; \ value = $$0; \ sub(/[[:space:]]*\?=.*/, "", name); \ sub(/^[^?]+\?=[[:space:]]*/, "", value); \ printf " %-32s default: %s\n", name, value; \ } \ ' Makefile @printf "\nRestore Safety:\n" @printf " CONFIRM_RESTORE=baron-sso 복구 실행 의도를 명시하는 필수 확인값\n" @printf " ALLOW_NON_EMPTY_RESTORE=true 비어 있지 않은 복구 대상에 덮어쓰는 승인된 복구에서만 사용\n" @printf "\nRestore Examples:\n" @printf " make restore-plan FILE_PATH=stg.today.tar.gz CONFIRM_RESTORE=baron-sso\n" @printf " make restore FILE_PATH=stg.today.tar.gz CONFIRM_RESTORE=baron-sso ALLOW_NON_EMPTY_RESTORE=true\n" # --- 인증 설정 빌드/검증 --- build-auth-config: ## 인증 설정 파일 생성 @echo "Building auth config..." @mkdir -p config/.generated @bash scripts/auth_config.sh build validate-auth-config: build-auth-config ## 인증 설정 값 검증 @echo "Validating auth config..." @bash scripts/auth_config.sh validate verify-auth-config: validate-auth-config ## 인증 설정 연결 상태 확인 @echo "Verifying auth config wiring..." @bash scripts/auth_config.sh verify render-ory-config: validate-auth-config ## Ory 설정 파일 렌더링 @echo "Rendering Ory config..." @bash scripts/render_ory_config.sh # --- 기본 실행 --- # 주의: --remove-orphan 사용 금지 (다른 스택이 orphan으로 판단되어 종료될 수 있음) up: up-all ## 전체 로컬 스택 실행 up-all: ensure-networks render-ory-config ## 인프라, Ory, 앱 스택 모두 실행 @echo "Starting ALL stacks (infra + ory + app)..." docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_INFRA) -f $(COMPOSE_ORY) -f $(COMPOSE_APP) up --build -d docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_INFRA) -f $(COMPOSE_ORY) -f $(COMPOSE_APP) restart kratos # --- 개별 스택 실행 --- up-infra: ensure-networks ## 인프라 스택 실행 @echo "Starting Infra stack (postgres/clickhouse/redis)..." docker compose -f $(COMPOSE_INFRA) up -d up-ory: ensure-networks render-ory-config ## Ory 스택 실행 @echo "Starting Ory stack (kratos/hydra/keto/oathkeeper)..." docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_ORY) up -d docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_ORY) restart kratos up-app: ensure-networks render-ory-config ## 앱 스택 실행 @echo "Starting App stack (backend/userfront/adminfront/devfront/orgfront)..." docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_APP) up --build -d up-backend: ensure-networks render-ory-config ## 백엔드 컨테이너만 실행 @echo "Starting Backend only..." docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_APP) up --build -d backend ensure-networks: ## 개발용 Docker 네트워크 보장 @echo "Ensuring Docker networks..." @for network in $(DEV_NETWORKS); do \ if ! docker network inspect "$$network" >/dev/null 2>&1; then \ echo "Creating Docker network $$network..."; \ docker network create "$$network"; \ else \ echo "Docker network $$network already exists."; \ fi; \ done ensure-infra: ensure-networks ## 인프라 스택 실행 상태 보장 @echo "Ensuring Infra stack..." @missing=0; \ for container in $(INFRA_CONTAINERS); do \ if [ "$$(docker inspect -f '{{.State.Running}}' "$$container" 2>/dev/null)" != "true" ]; then \ missing=1; \ break; \ fi; \ done; \ if [ "$$missing" -eq 1 ]; then \ echo "Starting missing Infra stack containers in daemon mode..."; \ docker compose -f $(COMPOSE_INFRA) up -d; \ else \ echo "Infra stack is already running."; \ fi ensure-ory: ensure-networks render-ory-config ## Ory 스택 실행 상태 보장 @echo "Ensuring Ory stack..." @missing=0; \ for container in $(ORY_CONTAINERS); do \ if [ "$$(docker inspect -f '{{.State.Running}}' "$$container" 2>/dev/null)" != "true" ]; then \ missing=1; \ break; \ fi; \ done; \ if [ "$$missing" -eq 1 ]; then \ echo "Starting missing Ory stack containers in daemon mode..."; \ docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_ORY) up -d; \ else \ echo "Ory stack is already running. Restarting Kratos to apply rendered dev config..."; \ docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_ORY) restart kratos; \ fi ensure-restore-containers: ## 복구 대상 저장소 컨테이너 실행 상태 보장 @echo "Ensuring restore target containers..." @if [ "$(CONFIRM_RESTORE)" != "baron-sso" ]; then \ echo "Skipping restore target container startup until CONFIRM_RESTORE=baron-sso is provided."; \ exit 0; \ fi @$(MAKE) --no-print-directory ensure-networks @ensure_restore_container() { \ container="$$1"; \ compose_file="$$2"; \ compose_service="$$3"; \ if docker inspect -f '{{.State.Running}}' "$$container" 2>/dev/null | grep -qx 'true'; then \ echo "Restore target container $$container is already running."; \ return 0; \ fi; \ if docker inspect "$$container" >/dev/null 2>&1; then \ echo "Starting stopped restore target container $$container..."; \ docker start "$$container"; \ else \ echo "Creating restore target container $$container via $$compose_file service $$compose_service..."; \ docker compose -f "$$compose_file" up -d "$$compose_service"; \ fi; \ for attempt in 1 2 3 4 5 6 7 8 9 10; do \ if docker inspect -f '{{.State.Running}}' "$$container" 2>/dev/null | grep -qx 'true'; then \ return 0; \ fi; \ sleep 1; \ done; \ echo "ERROR: restore target container $$container did not reach running state." >&2; \ return 1; \ }; \ services="$(RESTORE_SERVICES)"; \ if [ -z "$$services" ] || [ "$$services" = "all" ]; then \ services="postgres ory-postgres clickhouse ory-clickhouse config"; \ else \ services="$$(printf '%s' "$$services" | tr ',' ' ')"; \ fi; \ for service in $$services; do \ case "$$service" in \ postgres) ensure_restore_container baron_postgres compose.infra.yaml postgres ;; \ ory-postgres) ensure_restore_container ory_postgres compose.ory.yaml postgres ;; \ clickhouse) ensure_restore_container baron_clickhouse compose.infra.yaml clickhouse ;; \ ory-clickhouse) ensure_restore_container ory_clickhouse compose.ory.yaml ory_clickhouse ;; \ config) ;; \ *) echo "ERROR: unknown restore service: $$service" >&2; exit 1 ;; \ esac; \ done up-dev: ensure-infra ensure-ory ## 개발 기본 스택 준비 @echo "Dev stack is up (infra + ory)." up-front-dev: up-infra up-ory up-backend ## 프론트 개발용 의존 스택 준비 @echo "Dev stack is up (infra + ory + backend)." dev: up-dev ## 개발 앱 컨테이너를 포그라운드로 실행 @echo "Starting development app containers in foreground attach mode..." BACKEND_LOG_LEVEL=info CLIENT_LOG_DEBUG=false VITE_CLIENT_LOG_DEBUG=false docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_APP) up --build $(DEV_SERVICES) dev-debug: up-dev ## 디버그 로그로 개발 앱 컨테이너 실행 @echo "Starting development app containers in foreground attach debug mode..." BACKEND_LOG_LEVEL=debug CLIENT_LOG_DEBUG=true VITE_CLIENT_LOG_DEBUG=true USERFRONT_FLUTTER_RUN_FLAGS=--debug docker compose $(COMPOSE_CLI_ENV_ARGS) -f $(COMPOSE_APP) up --build $(DEV_SERVICES) # --- 종료 (Down) --- down: ## 전체 로컬 스택 중지 @echo "Stopping ALL stacks (infra + ory + app)..." docker compose -f $(COMPOSE_INFRA) -f $(COMPOSE_ORY) -f $(COMPOSE_APP) down drop: ## 로컬 스택 컨테이너, 볼륨, 로컬 이미지 제거 @echo "Dropping Baron SSO local Docker stack containers, volumes, and local images..." -docker compose $(COMPOSE_DROP_ENV_ARGS) -f $(COMPOSE_INFRA) -f $(COMPOSE_ORY) -f $(COMPOSE_APP) down -v --rmi local @echo "Removing any remaining fixed-name Baron SSO containers..." @for container in $(DROP_CONTAINERS); do \ docker rm -f "$$container" >/dev/null 2>&1 || true; \ done @echo "Drop complete. External Docker networks are preserved." down-app: ## 앱 스택 중지 @echo "Stopping App stack..." docker compose -f $(COMPOSE_APP) down down-backend: ## 백엔드 컨테이너 중지 @echo "Stopping Backend only..." docker compose -f $(COMPOSE_APP) stop backend down-infra: ## 인프라 스택 중지 @echo "Stopping Infra stack..." docker compose -f $(COMPOSE_INFRA) down down-ory: ## Ory 스택 중지 @echo "Stopping Ory stack..." docker compose -f $(COMPOSE_ORY) down # --- 유틸리티 --- # 인프라 상태 확인 check-infra: ## 인프라 헬스 상태 확인 @echo "Checking infra status..." @if [ "$$(docker inspect -f '{{.State.Health.Status}}' baron_postgres 2>/dev/null)" != "healthy" ]; then \ echo "Error: PostgreSQL is not running or not healthy."; \ echo "Please run 'make up-infra' first."; \ exit 1; \ else \ echo "PostgreSQL is healthy."; \ fi ps: ## 전체 Compose 컨테이너 상태 조회 docker compose -f $(COMPOSE_INFRA) -f $(COMPOSE_ORY) -f $(COMPOSE_APP) ps logs-infra: ## 인프라 스택 로그 팔로우 docker compose -f $(COMPOSE_INFRA) logs -f logs-ory: ## Ory 스택 로그 팔로우 docker compose -f $(COMPOSE_ORY) logs -f logs-app: ## 앱 스택 로그 팔로우 docker compose -f $(COMPOSE_APP) logs -f # --- 백업/복구 --- backup-tools-build: ## 백업 도구 Docker 이미지 빌드 docker build -f $(BACKUP_TOOLS_DOCKERFILE) -t $(BACKUP_TOOLS_IMAGE) . ifeq ($(BACKUP_USE_DOCKER),true) dump: backup-tools-build ## 백업 덤프 생성 $(BACKUP_DOCKER_RUN) bash -lc 'DUMP_SERVICES="$(DUMP_SERVICES)" DUMP_MODE="$(DUMP_MODE)" BACKUP="$(BACKUP)" BACKUP_ROOT="$(BACKUP_ROOT)" scripts/backup/dump.sh' restore: backup-tools-build ensure-restore-containers ## 백업 덤프 복구 $(BACKUP_DOCKER_RUN) bash -lc 'RESTORE_INPUT="$(RESTORE_INPUT)" BACKUP="$(BACKUP)" DUMP_FILE="$(DUMP_FILE)" RESTORE_SERVICES="$(RESTORE_SERVICES)" CONFIRM_RESTORE="$(CONFIRM_RESTORE)" ALLOW_NON_EMPTY_RESTORE="$(ALLOW_NON_EMPTY_RESTORE)" RESTORE_REPORT="$(RESTORE_REPORT)" scripts/backup/restore.sh' dump-verify: backup-tools-build ## 백업 덤프 검증 $(BACKUP_DOCKER_RUN) bash -lc 'BACKUP="$(BACKUP)" scripts/backup/verify-dump.sh' restore-verify: backup-tools-build ## 복구 결과 검증 $(BACKUP_DOCKER_RUN) bash -lc 'BACKUP="$(BACKUP)" scripts/backup/verify-restore.sh' dump-list: backup-tools-build ## 사용 가능한 백업 덤프 목록 조회 $(BACKUP_DOCKER_RUN) bash -lc 'BACKUP_ROOT="$(BACKUP_ROOT)" scripts/backup/dump-list.sh' restore-plan: backup-tools-build ## 복구 실행 계획 출력 $(BACKUP_DOCKER_RUN) bash -lc 'RESTORE_INPUT="$(RESTORE_INPUT)" BACKUP="$(BACKUP)" DUMP_FILE="$(DUMP_FILE)" RESTORE_SERVICES="$(RESTORE_SERVICES)" CONFIRM_RESTORE="$(CONFIRM_RESTORE)" RESTORE_REPORT="$(RESTORE_REPORT)" scripts/backup/restore-plan.sh' upload-cloud: backup-tools-build ## 백업 덤프 클라우드 업로드 $(BACKUP_DOCKER_RUN) bash -lc 'WORKS_DRIVE_DRY_RUN="$(WORKS_DRIVE_DRY_RUN)" BACKUP="$(BACKUP)" scripts/backup/upload_cloud.sh' else dump: ## 백업 덤프 생성 DUMP_SERVICES="$(DUMP_SERVICES)" DUMP_MODE="$(DUMP_MODE)" BACKUP="$(BACKUP)" BACKUP_ROOT="$(BACKUP_ROOT)" scripts/backup/dump.sh restore: ensure-restore-containers ## 백업 덤프 복구 RESTORE_INPUT="$(RESTORE_INPUT)" BACKUP="$(BACKUP)" DUMP_FILE="$(DUMP_FILE)" RESTORE_SERVICES="$(RESTORE_SERVICES)" CONFIRM_RESTORE="$(CONFIRM_RESTORE)" ALLOW_NON_EMPTY_RESTORE="$(ALLOW_NON_EMPTY_RESTORE)" RESTORE_REPORT="$(RESTORE_REPORT)" scripts/backup/restore.sh dump-verify: ## 백업 덤프 검증 BACKUP="$(BACKUP)" scripts/backup/verify-dump.sh restore-verify: ## 복구 결과 검증 BACKUP="$(BACKUP)" scripts/backup/verify-restore.sh dump-list: ## 사용 가능한 백업 덤프 목록 조회 BACKUP_ROOT="$(BACKUP_ROOT)" scripts/backup/dump-list.sh restore-plan: ## 복구 실행 계획 출력 RESTORE_INPUT="$(RESTORE_INPUT)" BACKUP="$(BACKUP)" DUMP_FILE="$(DUMP_FILE)" RESTORE_SERVICES="$(RESTORE_SERVICES)" CONFIRM_RESTORE="$(CONFIRM_RESTORE)" RESTORE_REPORT="$(RESTORE_REPORT)" scripts/backup/restore-plan.sh upload-cloud: ## 백업 덤프 클라우드 업로드 WORKS_DRIVE_DRY_RUN="$(WORKS_DRIVE_DRY_RUN)" BACKUP="$(BACKUP)" scripts/backup/upload_cloud.sh endif dump-upload-cloud: dump upload-cloud ## 백업 덤프 생성 후 클라우드 업로드 # --- 로컬 통합 코드 체크 --- PLAYWRIGHT_BROWSERS_PATH := $(HOME)/.cache/ms-playwright PLAYWRIGHT_CHROMIUM_COMPLETE := $(PLAYWRIGHT_BROWSERS_PATH)/chromium-1208/INSTALLATION_COMPLETE PLAYWRIGHT_FIREFOX_COMPLETE := $(PLAYWRIGHT_BROWSERS_PATH)/firefox-1509/INSTALLATION_COMPLETE PLAYWRIGHT_WEBKIT_COMPLETE := $(PLAYWRIGHT_BROWSERS_PATH)/webkit-2248/INSTALLATION_COMPLETE PLAYWRIGHT_INSTALL_ALL := sh -c 'if [ -f "$(PLAYWRIGHT_CHROMIUM_COMPLETE)" ] && [ -f "$(PLAYWRIGHT_FIREFOX_COMPLETE)" ] && [ -f "$(PLAYWRIGHT_WEBKIT_COMPLETE)" ]; then echo "Playwright browsers already installed"; else npx playwright install; fi' PLAYWRIGHT_INSTALL_CHROMIUM := sh -c 'if [ -f "$(PLAYWRIGHT_CHROMIUM_COMPLETE)" ]; then echo "Playwright chromium already installed"; else npx playwright install chromium; fi' .PHONY: code-check code-check-lint code-check-test-jobs code-check-i18n code-check-i18n-values code-check-go-lint code-check-sync-userfront-locales code-check-userfront-install code-check-userfront-lint code-check-front-lint code-check-backend-tests code-check-userfront-tests code-check-adminfront-tests code-check-devfront-tests code-check-orgfront-tests code-check-userfront-e2e-tests CODE_CHECK_TEST_JOBS ?= 1 PLAYWRIGHT_WORKERS ?= 1 FLUTTER_TEST_CONCURRENCY ?= 1 code-check: code-check-lint code-check-test-jobs ## 로컬 CI 상당 코드 검사 실행 @echo "code-check complete." code-check-lint: code-check-i18n code-check-i18n-values code-check-front-lint code-check-go-lint code-check-sync-userfront-locales code-check-userfront-install code-check-userfront-lint ## 로컬 린트와 정적 검사 실행 code-check-test-jobs: ## 코드 검사 테스트 작업 실행 @echo "==> run CI-equivalent test jobs (parallel)" @$(MAKE) --no-print-directory -j$(CODE_CHECK_TEST_JOBS) --output-sync=target \ code-check-backend-tests \ code-check-userfront-tests \ code-check-userfront-e2e-tests \ code-check-adminfront-tests \ code-check-devfront-tests \ code-check-orgfront-tests code-check-i18n: ## i18n 리소스 검사 @echo "==> i18n resource check" @mkdir -p reports node tools/i18n-scanner/index.js node tools/i18n-scanner/report.js @cat reports/i18n-report.txt code-check-i18n-values: ## i18n 번역 값 품질 검사 @echo "==> i18n value quality check" @mkdir -p reports node tools/i18n-scanner/value-check.js @cat reports/i18n-value-report.txt code-check-go-lint: ## Go 포맷과 린트 검사 @echo "==> go lint/format check" @if command -v golangci-lint >/dev/null 2>&1; then \ cd backend && golangci-lint fmt -E gofmt -E gofumpt -d; \ elif command -v docker >/dev/null 2>&1; then \ docker run --rm \ -v "$$(pwd)/backend:/app" \ -w /app \ golangci/golangci-lint:v2.10.1 \ golangci-lint fmt -E gofmt -E gofumpt -d; \ else \ echo "ERROR: golangci-lint not found and docker is unavailable."; \ echo "Install golangci-lint v2.10.1 or Docker to match CI lint step."; \ exit 1; \ fi code-check-sync-userfront-locales: ## UserFront 로케일 동기화 검사 @echo "==> sync userfront locales" /bin/sh ./scripts/sync_userfront_locales.sh code-check-userfront-install: ## UserFront 의존성 설치 @echo "==> install userfront dependencies" @if command -v flutter >/dev/null 2>&1; then \ cd userfront && flutter pub get; \ else \ echo "WARNING: flutter not found, skipping userfront dependencies install."; \ fi code-check-userfront-lint: ## UserFront 포맷과 analyze 검사 @echo "==> userfront format/analyze" @if command -v dart >/dev/null 2>&1; then \ cd userfront && dart format --output=none --set-exit-if-changed lib test; \ else \ echo "WARNING: dart not found, skipping userfront format check."; \ fi @if command -v flutter >/dev/null 2>&1; then \ cd userfront && flutter analyze --no-fatal-warnings --no-fatal-infos; \ else \ echo "WARNING: flutter not found, skipping userfront analyze."; \ fi code-check-front-lint: ## 프론트엔드 Biome 린트와 포맷 검사 @echo "==> adminfront biome lint/format check" rm -rf adminfront/playwright-report adminfront/test-results @if [ -d adminfront/node_modules ]; then \ echo "adminfront/node_modules already present; skipping pnpm install."; \ else \ cd adminfront && CI=true npx pnpm install --frozen-lockfile --ignore-scripts; \ fi cd adminfront && npx biome lint . cd adminfront && npx biome format . @echo "==> devfront biome lint/format check" rm -rf devfront/playwright-report devfront/test-results @if [ -d devfront/node_modules ]; then \ echo "devfront/node_modules already present; skipping npm install."; \ else \ cd devfront && npm ci --ignore-scripts; \ fi cd devfront && npx biome lint . cd devfront && npx biome format . @echo "==> orgfront biome lint/format check" rm -rf orgfront/playwright-report orgfront/test-results @if [ -d orgfront/node_modules ]; then \ echo "orgfront/node_modules already present; skipping npm install."; \ else \ cd orgfront && npm ci --ignore-scripts; \ fi cd orgfront && ./node_modules/@biomejs/biome/bin/biome lint . cd orgfront && ./node_modules/@biomejs/biome/bin/biome format . code-check-backend-tests: ## 백엔드 Go 테스트 실행 @echo "==> backend tests" cd backend && GOCACHE=/tmp/baron-sso-go-cache go test -v ./... code-check-userfront-tests: ## UserFront Flutter 테스트 실행 @echo "==> userfront tests (isolated workspace)" @if ! command -v flutter >/dev/null 2>&1; then \ echo "WARNING: flutter not found, skipping userfront tests."; \ exit 0; \ fi; \ tmp_dir="$$(mktemp -d /tmp/baron-sso-userfront-tests.XXXXXX)"; \ trap 'rm -rf "$$tmp_dir"' EXIT INT TERM; \ mkdir -p "$$tmp_dir/scripts"; \ cp scripts/sync_userfront_locales.sh "$$tmp_dir/scripts/"; \ cp -R locales "$$tmp_dir/locales"; \ if command -v rsync >/dev/null 2>&1; then \ rsync -a --delete \ --exclude '.dart_tool' \ --exclude 'build' \ --exclude '.pub-cache' \ --exclude '.flutter-plugins' \ --exclude '.flutter-plugins-dependencies' \ userfront/ "$$tmp_dir/userfront/"; \ else \ cp -R userfront "$$tmp_dir/userfront"; \ rm -rf "$$tmp_dir/userfront/.dart_tool" "$$tmp_dir/userfront/build"; \ fi; \ cd "$$tmp_dir" && /bin/sh ./scripts/sync_userfront_locales.sh; \ cd "$$tmp_dir/userfront" && flutter test --concurrency=$(FLUTTER_TEST_CONCURRENCY) code-check-adminfront-tests: ## AdminFront 테스트 실행 @echo "==> adminfront tests" PLAYWRIGHT_WORKERS=$(PLAYWRIGHT_WORKERS) ./scripts/run_adminfront_ci_tests.sh adminfront-tests code-check-devfront-tests: ## DevFront 테스트 실행 @echo "==> devfront tests" @mkdir -p reports/devfront @rm -rf reports/devfront/playwright-report reports/devfront/test-results @status=0; \ preview_pattern='[v]ite preview --host 127.0.0.1 --strictPort --port 4174'; \ pkill -f "$$preview_pattern" >/dev/null 2>&1 || true; \ trap 'pkill -f "$$preview_pattern" >/dev/null 2>&1 || true' EXIT INT TERM; \ if [ -d devfront/node_modules ]; then \ echo "devfront/node_modules already present; skipping npm install."; \ else \ (cd devfront && npm ci --ignore-scripts) || status=$$?; \ fi; \ if [ $$status -eq 0 ]; then \ (cd devfront && $(PLAYWRIGHT_INSTALL_ALL)) || status=$$?; \ fi; \ if [ $$status -eq 0 ]; then \ (cd devfront && PLAYWRIGHT_WORKERS=$(PLAYWRIGHT_WORKERS) npm test) || status=$$?; \ fi; \ [ -d devfront/playwright-report ] && cp -R devfront/playwright-report reports/devfront/ || true; \ [ -d devfront/test-results ] && cp -R devfront/test-results reports/devfront/ || true; \ exit $$status code-check-orgfront-tests: ## OrgFront 테스트 실행 @echo "==> orgfront tests" @mkdir -p reports/orgfront @rm -rf reports/orgfront/playwright-report reports/orgfront/test-results @status=0; \ (cd orgfront && npm ci --ignore-scripts) || status=$$?; \ if [ $$status -eq 0 ]; then \ (cd orgfront && $(PLAYWRIGHT_INSTALL_ALL)) || status=$$?; \ fi; \ if [ $$status -eq 0 ]; then \ (cd orgfront && PLAYWRIGHT_WORKERS=$(PLAYWRIGHT_WORKERS) npm test) || status=$$?; \ fi; \ [ -d orgfront/playwright-report ] && cp -R orgfront/playwright-report reports/orgfront/ || true; \ [ -d orgfront/test-results ] && cp -R orgfront/test-results reports/orgfront/ || true; \ exit $$status code-check-userfront-e2e-tests: ## UserFront WASM E2E 테스트 실행 @echo "==> userfront wasm playwright e2e tests (isolated workspace)" @if ! command -v flutter >/dev/null 2>&1; then \ echo "WARNING: flutter not found, skipping userfront e2e tests."; \ exit 0; \ fi; \ mkdir -p reports/userfront-e2e; \ rm -rf reports/userfront-e2e/playwright-report reports/userfront-e2e/test-results; \ tmp_dir="$$(mktemp -d /tmp/baron-sso-userfront-e2e-tests.XXXXXX)"; \ trap 'rm -rf "$$tmp_dir"' EXIT INT TERM; \ mkdir -p "$$tmp_dir/scripts"; \ cp scripts/sync_userfront_locales.sh "$$tmp_dir/scripts/"; \ cp -R locales "$$tmp_dir/locales"; \ if command -v rsync >/dev/null 2>&1; then \ rsync -a --delete \ --exclude '.dart_tool' \ --exclude 'build' \ --exclude '.pub-cache' \ --exclude '.flutter-plugins' \ --exclude '.flutter-plugins-dependencies' \ userfront/ "$$tmp_dir/userfront/"; \ rsync -a --delete \ --exclude 'node_modules' \ --exclude 'playwright-report' \ --exclude 'test-results' \ userfront-e2e/ "$$tmp_dir/userfront-e2e/"; \ else \ cp -R userfront "$$tmp_dir/userfront"; \ rm -rf "$$tmp_dir/userfront/.dart_tool" "$$tmp_dir/userfront/build"; \ cp -R userfront-e2e "$$tmp_dir/userfront-e2e"; \ rm -rf "$$tmp_dir/userfront-e2e/node_modules" "$$tmp_dir/userfront-e2e/playwright-report" "$$tmp_dir/userfront-e2e/test-results"; \ fi; \ status=0; \ (cd "$$tmp_dir" && /bin/sh ./scripts/sync_userfront_locales.sh) || status=$$?; \ if [ $$status -eq 0 ]; then \ (cd "$$tmp_dir/userfront-e2e" && npm ci) || status=$$?; \ fi; \ if [ $$status -eq 0 ]; then \ (cd "$$tmp_dir/userfront" && flutter build web --wasm --release) || status=$$?; \ fi; \ if [ $$status -eq 0 ]; then \ (cd "$$tmp_dir/userfront-e2e" && $(PLAYWRIGHT_INSTALL_ALL)) || status=$$?; \ fi; \ if [ $$status -eq 0 ]; then \ port="$$(node -e "const net=require('node:net'); const s=net.createServer(); s.listen(0,'127.0.0.1',()=>{console.log(s.address().port); s.close();});")"; \ echo "==> userfront-e2e using PORT=$$port"; \ (cd "$$tmp_dir/userfront-e2e" && PORT=$$port PLAYWRIGHT_WORKERS=$(PLAYWRIGHT_WORKERS) npm test) || status=$$?; \ fi; \ [ -d "$$tmp_dir/userfront-e2e/playwright-report" ] && cp -R "$$tmp_dir/userfront-e2e/playwright-report" reports/userfront-e2e/ || true; \ [ -d "$$tmp_dir/userfront-e2e/test-results" ] && cp -R "$$tmp_dir/userfront-e2e/test-results" reports/userfront-e2e/ || true; \ exit $$status