# ============================================================================== # VEZA MONOREPO - ULTIMATE CONTROL PLANE # ============================================================================== # Stack: Docker + Incus (LXD) Support # System: Linux / Bash # ============================================================================== # --- Auto-Configuration --- -include .env # Shell setup SHELL := /bin/bash .ONESHELL: .DEFAULT_GOAL := help # --- Variables --- PROJECT_NAME := veza COMPOSE_FILE := docker-compose.yml COMPOSE_PROD := docker-compose.prod.yml # Services SERVICES := backend-api chat-server stream-server web haproxy INFRA_SERVICES := postgres redis rabbitmq # Ports PORT_GO ?= 8080 PORT_CHAT ?= 3000 PORT_STREAM ?= 3001 PORT_WEB ?= 5173 PORT_HAPROXY ?= 80 # Database & Infra DB_USER ?= veza DB_PASS ?= password DB_NAME ?= veza DB_HOST ?= localhost DB_PORT ?= 5432 # Connection Strings DATABASE_URL = postgres://$(DB_USER):$(DB_PASS)@$(DB_HOST):$(DB_PORT)/$(DB_NAME)?sslmode=disable REDIS_URL = redis://localhost:6379 AMQP_URL = amqp://$(DB_USER):$(DB_PASS)@localhost:5672 # Directories DIR_GO := veza-backend-api DIR_CHAT := veza-chat-server DIR_STREAM := veza-stream-server DIR_WEB := apps/web # Deployment DEPLOY_TARGET ?= docker INCUS_PROFILE := veza-profile INCUS_NETWORK := veza-network # --- Aesthetics & UI --- BOLD := \033[1m RED := \033[0;31m GREEN := \033[0;32m YELLOW := \033[0;33m BLUE := \033[0;34m PURPLE := \033[0;35m CYAN := \033[0;36m NC := \033[0m ECHO_CMD = echo -e # ============================================================================== # HELP & DASHBOARD # ============================================================================== .PHONY: help help: ## Show this dashboard @$(ECHO_CMD) "" @$(ECHO_CMD) "${BOLD}${PURPLE}โšก VEZA MONOREPO CLI โšก${NC}" @$(ECHO_CMD) "=================================================================" @$(ECHO_CMD) "${BOLD}INFRASTRUCTURE:${NC}" @printf " ${CYAN}%-15s${NC} %s\n" "Postgres" "${DATABASE_URL}" @printf " ${CYAN}%-15s${NC} %s\n" "Redis" "${REDIS_URL}" @printf " ${CYAN}%-15s${NC} %s\n" "RabbitMQ" "UI: http://localhost:15672 (veza/password)" @$(ECHO_CMD) "" @$(ECHO_CMD) "${BOLD}${GREEN}HIGH LEVEL COMMANDS:${NC}" @grep -E '^[a-zA-Z0-9_-]+:.*?## \[HIGH\] .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " ${YELLOW}%-25s${NC} %s\n", $$1, $$2}' @$(ECHO_CMD) "" @$(ECHO_CMD) "${BOLD}${BLUE}INTERMEDIATE COMMANDS:${NC}" @grep -E '^[a-zA-Z0-9_-]+:.*?## \[MID\] .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " ${CYAN}%-25s${NC} %s\n", $$1, $$2}' @$(ECHO_CMD) "" @$(ECHO_CMD) "${BOLD}${PURPLE}LOW LEVEL / DEBUG:${NC}" @grep -E '^[a-zA-Z0-9_-]+:.*?## \[LOW\] .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf " ${PURPLE}%-25s${NC} %s\n", $$1, $$2}' @$(ECHO_CMD) "" # ============================================================================== # HIGH LEVEL COMMANDS # ============================================================================== .PHONY: setup stop-all restart-all clean deploy-docker deploy-incus status-full setup: check-tools install-tools install-deps ## [HIGH] Full project initialization @$(ECHO_CMD) "${BOLD}${GREEN}โœ… Setup Complete! Ready to rock with 'make dev'.${NC}" web-minimal: ## [HIGH] Start Veza Web Minimal Journey (Backend + Frontend + DB) @./scripts/start_minimal.sh stop-minimal: ## [HIGH] Stop Minimal Stack @./scripts/stop_minimal.sh stop-all: ## [HIGH] Stop all services (Docker + Local) @$(ECHO_CMD) "${RED}๐Ÿ›‘ Stopping all services...${NC}" @docker compose -f $(COMPOSE_FILE) down 2>/dev/null || true @docker compose -f $(COMPOSE_PROD) down 2>/dev/null || true @$(MAKE) -s stop-local-services @$(ECHO_CMD) "${GREEN}โœ… All services stopped.${NC}" restart-all: stop-all ## [HIGH] Restart all services @$(ECHO_CMD) "${BLUE}๐Ÿ”„ Restarting all services...${NC}" @$(MAKE) -s infra-up @$(MAKE) -s dev @$(ECHO_CMD) "${GREEN}โœ… All services restarted.${NC}" clean: ## [HIGH] Clean build artifacts and caches @$(ECHO_CMD) "${YELLOW}๐Ÿงน Cleaning build artifacts...${NC}" @rm -rf $(DIR_WEB)/node_modules/.cache @rm -rf $(DIR_CHAT)/target/debug $(DIR_STREAM)/target/debug @find . -type d -name "node_modules" -prune -o -type f -name "*.log" -delete @$(ECHO_CMD) "${GREEN}โœ… Clean complete.${NC}" clean-deep: ## [HIGH] โš ๏ธ Nuclear Clean (Confirm required) @read -p "${RED}Are you sure? This will delete ALL builds, volumes, and caches! [y/N]${NC} " ans && [ $${ans:-N} = y ] @$(ECHO_CMD) "${RED}โ˜ข๏ธ DESTROYING ARTIFACTS...${NC}" @rm -rf $(DIR_WEB)/node_modules @rm -rf $(DIR_CHAT)/target $(DIR_STREAM)/target @docker compose -f $(COMPOSE_FILE) down -v 2>/dev/null || true @docker compose -f $(COMPOSE_PROD) down -v 2>/dev/null || true @$(ECHO_CMD) "${GREEN}System Cleaned.${NC}" deploy-docker: build-all ## [HIGH] Deploy all services with Docker + HAProxy @$(ECHO_CMD) "${BOLD}${BLUE}๐Ÿณ Deploying with Docker...${NC}" @docker compose -f $(COMPOSE_PROD) up -d --build @$(MAKE) -s wait-for-services @$(ECHO_CMD) "${GREEN}โœ… Deployment complete! Access via http://localhost:$(PORT_HAPROXY)${NC}" deploy-incus: build-all-native ## [HIGH] Deploy all services with Incus containers (native, no Docker) @$(ECHO_CMD) "${BOLD}${BLUE}๐Ÿ“ฆ Deploying with Incus (native)...${NC}" @$(MAKE) -s incus-setup-network @$(MAKE) -s incus-deploy-infra @$(MAKE) -s incus-deploy-all-native @$(MAKE) -s incus-start-all @$(ECHO_CMD) "${GREEN}โœ… Incus deployment complete!${NC}" @$(ECHO_CMD) "${BLUE}Access services at:${NC}" @$(ECHO_CMD) " Backend API: http://10.10.10.2:8080" @$(ECHO_CMD) " Chat Server: http://10.10.10.3:8081" @$(ECHO_CMD) " Stream Server: http://10.10.10.4:3002" @$(ECHO_CMD) " Web Frontend: http://10.10.10.5:80" @$(ECHO_CMD) " HAProxy: http://10.10.10.6:80" status-full: ## [HIGH] Show complete system status @$(ECHO_CMD) "${BOLD}${CYAN}๐Ÿ“Š SYSTEM STATUS${NC}" @$(ECHO_CMD) "" @$(ECHO_CMD) "${BOLD}Docker Containers:${NC}" @docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep -E "NAME|veza" || echo " No containers running" @$(ECHO_CMD) "" @$(ECHO_CMD) "${BOLD}Local Processes:${NC}" @lsof -i :$(PORT_GO) -i :$(PORT_CHAT) -i :$(PORT_STREAM) -i :$(PORT_WEB) 2>/dev/null | grep LISTEN || echo " No local processes" @$(ECHO_CMD) "" @$(ECHO_CMD) "${BOLD}Incus Containers:${NC}" @incus list veza- 2>/dev/null | grep -E "NAME|veza" || echo " No Incus containers" @$(ECHO_CMD) "" # ============================================================================== # INTERMEDIATE COMMANDS # ============================================================================== .PHONY: start-service stop-service restart-service logs-service build-service start-service: ## [MID] Start a specific service (usage: make start-service SERVICE=backend-api) @if [ -z "$(SERVICE)" ]; then \ $(ECHO_CMD) "${RED}โŒ Please specify SERVICE=name${NC}"; \ exit 1; \ fi @$(ECHO_CMD) "${BLUE}๐Ÿš€ Starting $(SERVICE)...${NC}" @docker compose -f $(COMPOSE_PROD) up -d $(SERVICE) || \ $(MAKE) -s start-local-service SERVICE=$(SERVICE) @$(ECHO_CMD) "${GREEN}โœ… $(SERVICE) started.${NC}" stop-service: ## [MID] Stop a specific service (usage: make stop-service SERVICE=backend-api) @if [ -z "$(SERVICE)" ]; then \ $(ECHO_CMD) "${RED}โŒ Please specify SERVICE=name${NC}"; \ exit 1; \ fi @$(ECHO_CMD) "${YELLOW}๐Ÿ›‘ Stopping $(SERVICE)...${NC}" @docker compose -f $(COMPOSE_PROD) stop $(SERVICE) 2>/dev/null || \ $(MAKE) -s stop-local-service SERVICE=$(SERVICE) @$(ECHO_CMD) "${GREEN}โœ… $(SERVICE) stopped.${NC}" restart-service: stop-service ## [MID] Restart a specific service (usage: make restart-service SERVICE=backend-api) @$(ECHO_CMD) "${BLUE}๐Ÿ”„ Restarting $(SERVICE)...${NC}" @$(MAKE) -s start-service SERVICE=$(SERVICE) @$(ECHO_CMD) "${GREEN}โœ… $(SERVICE) restarted.${NC}" logs-service: ## [MID] Show logs for a service (usage: make logs-service SERVICE=backend-api) @if [ -z "$(SERVICE)" ]; then \ $(ECHO_CMD) "${RED}โŒ Please specify SERVICE=name${NC}"; \ exit 1; \ fi @docker compose -f $(COMPOSE_PROD) logs -f $(SERVICE) || \ $(ECHO_CMD) "${YELLOW}Service not running in Docker, check local logs${NC}" build-service: ## [MID] Build a specific service (usage: make build-service SERVICE=backend-api) @if [ -z "$(SERVICE)" ]; then \ $(ECHO_CMD) "${RED}โŒ Please specify SERVICE=name${NC}"; \ exit 1; \ fi @$(ECHO_CMD) "${BLUE}๐Ÿ”จ Building $(SERVICE)...${NC}" @$(MAKE) -s build-$(SERVICE) @$(ECHO_CMD) "${GREEN}โœ… $(SERVICE) built.${NC}" build-all: ## [MID] Build all services (Docker images) @$(ECHO_CMD) "${BLUE}๐Ÿ”จ Building all services...${NC}" @$(MAKE) -s build-backend-api @$(MAKE) -s build-chat-server @$(MAKE) -s build-stream-server @$(MAKE) -s build-web @$(ECHO_CMD) "${GREEN}โœ… All services built.${NC}" build-all-native: ## [MID] Build all services natively (for Incus) @$(ECHO_CMD) "${BLUE}๐Ÿ”จ Building all services natively...${NC}" @$(shell pwd)/config/incus/build-native.sh all @$(ECHO_CMD) "${GREEN}โœ… All services built natively.${NC}" # ============================================================================== # LOW LEVEL / DEBUG COMMANDS # ============================================================================== .PHONY: check-tools install-tools install-deps check-ports check-tools: ## [LOW] Check required tools @$(ECHO_CMD) "${BLUE}Checking core requirements...${NC}" @for tool in docker go cargo npm; do \ command -v $$tool >/dev/null 2>&1 || { $(ECHO_CMD) "${RED}โŒ $$tool is missing!${NC}"; exit 1; }; \ done @$(ECHO_CMD) "${GREEN}โœ… All tools present.${NC}" check-tools-incus: ## [LOW] Check required tools for Incus deployment @$(ECHO_CMD) "${BLUE}Checking Incus deployment requirements...${NC}" @command -v incus >/dev/null 2>&1 || { $(ECHO_CMD) "${RED}โŒ incus is missing! Install with: sudo snap install incus${NC}"; exit 1; } @command -v go >/dev/null 2>&1 || { $(ECHO_CMD) "${RED}โŒ go is missing!${NC}"; exit 1; } @command -v cargo >/dev/null 2>&1 || { $(ECHO_CMD) "${RED}โŒ cargo is missing!${NC}"; exit 1; } @command -v npm >/dev/null 2>&1 || { $(ECHO_CMD) "${RED}โŒ npm is missing!${NC}"; exit 1; } @$(ECHO_CMD) "${GREEN}โœ… All Incus tools present.${NC}" install-tools: ## [LOW] Install Power User tools (Hot Reload, Linters) @$(ECHO_CMD) "${BLUE}๐Ÿ› ๏ธ Installing Dev Tools...${NC}" @command -v air >/dev/null 2>&1 || go install github.com/air-verse/air@latest @command -v cargo-watch >/dev/null 2>&1 || cargo install cargo-watch @command -v sqlx >/dev/null 2>&1 || cargo install sqlx-cli --no-default-features --features native-tls,postgres @$(ECHO_CMD) "${GREEN}โœ… Tools installed.${NC}" install-deps: ## [LOW] Install code dependencies @$(ECHO_CMD) "${BLUE}๐Ÿ“ฆ Installing dependencies...${NC}" @$(ECHO_CMD) " -> [Go] Downloading modules..." @(cd $(DIR_GO) && go mod download) @$(ECHO_CMD) " -> [Rust Chat] Fetching crates..." @(cd $(DIR_CHAT) && cargo fetch) @$(ECHO_CMD) " -> [Rust Stream] Fetching crates..." @(cd $(DIR_STREAM) && cargo fetch) @$(ECHO_CMD) " -> [Web] Installing npm packages..." @(cd $(DIR_WEB) && npm install --silent) check-ports: ## [LOW] Check if ports are available @$(ECHO_CMD) "${BLUE}๐Ÿ” Checking ports...${NC}" @for port in $(PORT_GO) $(PORT_CHAT) $(PORT_STREAM) $(PORT_WEB); do \ if lsof -i :$$port -t >/dev/null 2>&1; then \ $(ECHO_CMD) "${YELLOW}โš ๏ธ Port $$port is busy${NC}"; \ else \ $(ECHO_CMD) "${GREEN}โœ… Port $$port is free${NC}"; \ fi; \ done # ============================================================================== # INFRASTRUCTURE # ============================================================================== .PHONY: infra-up infra-down wait-for-infra db-shell redis-shell db-migrate infra-up: ## [MID] Start Docker Infra (with health checks) @$(ECHO_CMD) "${BLUE}๐Ÿณ Starting Infrastructure...${NC}" @docker compose -f $(COMPOSE_FILE) up -d @$(MAKE) -s wait-for-infra infra-down: ## [MID] Stop Docker Infra @$(ECHO_CMD) "${BLUE}๐Ÿ›‘ Stopping Infrastructure...${NC}" @docker compose -f $(COMPOSE_FILE) down wait-for-infra: ## [LOW] Wait for infrastructure to be ready @printf "${BLUE}โณ Waiting for services...${NC}" @until docker compose -f $(COMPOSE_FILE) exec -T postgres pg_isready -U $(DB_USER) > /dev/null 2>&1; do printf "."; sleep 1; done @until docker compose -f $(COMPOSE_FILE) exec -T redis redis-cli ping > /dev/null 2>&1; do printf "."; sleep 1; done @$(ECHO_CMD) " ${GREEN}OK${NC}" wait-for-services: ## [LOW] Wait for all application services @printf "${BLUE}โณ Waiting for services...${NC}" @for service in backend-api chat-server stream-server web; do \ until docker compose -f $(COMPOSE_PROD) exec -T $$service echo "ready" > /dev/null 2>&1; do \ printf "."; sleep 1; \ done; \ done @$(ECHO_CMD) " ${GREEN}OK${NC}" db-shell: ## [MID] Connect to Postgres shell @docker compose -f $(COMPOSE_FILE) exec postgres psql -U $(DB_USER) -d $(DB_NAME) redis-shell: ## [MID] Connect to Redis shell @docker compose -f $(COMPOSE_FILE) exec redis redis-cli db-migrate: infra-up ## [MID] Run all database migrations @$(ECHO_CMD) "${BLUE}๐Ÿ”„ Running Migrations...${NC}" @$(ECHO_CMD) " -> [Go] Migrating..." @(cd $(DIR_GO) && go run cmd/migrate_tool/main.go up || $(ECHO_CMD) "${YELLOW}Warning: Go migration failed${NC}") @$(ECHO_CMD) " -> [Chat] Migrating..." @(cd $(DIR_CHAT) && sqlx migrate run || $(ECHO_CMD) "${YELLOW}Warning: Chat migration failed${NC}") @$(ECHO_CMD) " -> [Stream] Migrating..." @(cd $(DIR_STREAM) && sqlx migrate run || $(ECHO_CMD) "${YELLOW}Warning: Stream migration failed${NC}") @$(ECHO_CMD) "${GREEN}โœ… Migrations done.${NC}" # ============================================================================== # DEVELOPMENT # ============================================================================== .PHONY: dev dev-backend stop-local-services start-local-service stop-local-service dev: check-ports infra-up ## [HIGH] Start Everything (Detects Hot Reload tools) @$(ECHO_CMD) "${BOLD}${PURPLE}๐Ÿš€ STARTING HYBRID DEV ENVIRONMENT${NC}" @$(ECHO_CMD) " Go: http://localhost:${PORT_GO}" @$(ECHO_CMD) " Chat: http://localhost:${PORT_CHAT}" @$(ECHO_CMD) " Web: http://localhost:${PORT_WEB}" @$(ECHO_CMD) "${YELLOW}Hit Ctrl+C to stop all.${NC}" @(trap 'kill 0' SIGINT; \ if command -v air >/dev/null; then \ $(ECHO_CMD) "${GREEN}[Go] Hot Reload Active (Air)${NC}" && cd $(DIR_GO) && air & \ else \ $(ECHO_CMD) "${YELLOW}[Go] Standard Run${NC}" && cd $(DIR_GO) && go run cmd/modern-server/main.go & \ fi; \ if command -v cargo-watch >/dev/null; then \ $(ECHO_CMD) "${GREEN}[Chat] Hot Reload Active${NC}" && cd $(DIR_CHAT) && cargo watch -x run -q & \ $(ECHO_CMD) "${GREEN}[Stream] Hot Reload Active${NC}" && cd $(DIR_STREAM) && cargo watch -x run -q & \ else \ $(ECHO_CMD) "${YELLOW}[Chat] Standard Run${NC}" && cd $(DIR_CHAT) && cargo run -q & \ $(ECHO_CMD) "${YELLOW}[Stream] Standard Run${NC}" && cd $(DIR_STREAM) && cargo run -q & \ fi; \ $(ECHO_CMD) "${GREEN}[Web] Starting Vite...${NC}" && cd $(DIR_WEB) && npm run dev & \ wait) dev-backend: check-ports infra-up ## [MID] Start Backends Only (Hot Reload supported) @$(ECHO_CMD) "${BOLD}${PURPLE}๐Ÿš€ STARTING BACKEND ONLY${NC}" @(trap 'kill 0' SIGINT; \ if command -v air >/dev/null; then cd $(DIR_GO) && air & else cd $(DIR_GO) && go run cmd/modern-server/main.go & fi; \ if command -v cargo-watch >/dev/null; then cd $(DIR_CHAT) && cargo watch -x run -q & else cd $(DIR_CHAT) && cargo run -q & fi; \ if command -v cargo-watch >/dev/null; then cd $(DIR_STREAM) && cargo watch -x run -q & else cd $(DIR_STREAM) && cargo run -q & fi; \ wait) stop-local-services: ## [LOW] Stop all local processes @pkill -f "air\|cargo watch\|npm run dev\|go run.*modern-server" 2>/dev/null || true start-local-service: ## [LOW] Start a service locally @case "$(SERVICE)" in \ backend-api) \ if command -v air >/dev/null; then cd $(DIR_GO) && air & else cd $(DIR_GO) && go run cmd/modern-server/main.go & fi ;; \ chat-server) \ if command -v cargo-watch >/dev/null; then cd $(DIR_CHAT) && cargo watch -x run -q & else cd $(DIR_CHAT) && cargo run -q & fi ;; \ stream-server) \ if command -v cargo-watch >/dev/null; then cd $(DIR_STREAM) && cargo watch -x run -q & else cd $(DIR_STREAM) && cargo run -q & fi ;; \ web) \ cd $(DIR_WEB) && npm run dev & ;; \ *) \ $(ECHO_CMD) "${RED}Unknown service: $(SERVICE)${NC}"; exit 1 ;; \ esac stop-local-service: ## [LOW] Stop a local service @case "$(SERVICE)" in \ backend-api) pkill -f "air\|go run.*modern-server" ;; \ chat-server|stream-server) pkill -f "cargo.*$(SERVICE)" ;; \ web) pkill -f "npm run dev\|vite" ;; \ *) $(ECHO_CMD) "${RED}Unknown service: $(SERVICE)${NC}" ;; \ esac # ============================================================================== # BUILD COMMANDS # ============================================================================== .PHONY: build-backend-api build-chat-server build-stream-server build-web build-backend-api: ## [LOW] Build Go backend @$(ECHO_CMD) "${BLUE}๐Ÿ”จ Building backend-api...${NC}" @docker build -t $(PROJECT_NAME)-backend-api:latest -f $(DIR_GO)/Dockerfile.production $(DIR_GO) || \ $(ECHO_CMD) "${YELLOW}Using local Dockerfile...${NC}" && \ docker build -t $(PROJECT_NAME)-backend-api:latest -f $(DIR_GO)/Dockerfile $(DIR_GO) build-chat-server: ## [LOW] Build Rust chat server @$(ECHO_CMD) "${BLUE}๐Ÿ”จ Building chat-server...${NC}" @docker build -t $(PROJECT_NAME)-chat-server:latest -f $(DIR_CHAT)/Dockerfile.production $(DIR_CHAT) || \ docker build -t $(PROJECT_NAME)-chat-server:latest -f $(DIR_CHAT)/Dockerfile $(DIR_CHAT) build-stream-server: ## [LOW] Build Rust stream server @$(ECHO_CMD) "${BLUE}๐Ÿ”จ Building stream-server...${NC}" @docker build -t $(PROJECT_NAME)-stream-server:latest -f $(DIR_STREAM)/Dockerfile.production $(DIR_STREAM) || \ docker build -t $(PROJECT_NAME)-stream-server:latest -f $(DIR_STREAM)/Dockerfile $(DIR_STREAM) build-web: ## [LOW] Build web frontend @$(ECHO_CMD) "${BLUE}๐Ÿ”จ Building web...${NC}" @docker build -t $(PROJECT_NAME)-web:latest -f $(DIR_WEB)/Dockerfile.production $(DIR_WEB) || \ docker build -t $(PROJECT_NAME)-web:latest -f $(DIR_WEB)/Dockerfile $(DIR_WEB) # ============================================================================== # INCUS / LXD DEPLOYMENT # ============================================================================== .PHONY: incus-setup-network incus-deploy-all incus-deploy-all-native incus-deploy-service incus-deploy-service-native incus-deploy-infra incus-start-all incus-stop-all incus-logs incus-setup-network: ## [LOW] Setup Incus network profile @$(ECHO_CMD) "${BLUE}๐Ÿ“ฆ Setting up Incus network...${NC}" @if ! incus network show $(INCUS_NETWORK) >/dev/null 2>&1; then \ $(ECHO_CMD) "Creating network $(INCUS_NETWORK)..."; \ incus network create $(INCUS_NETWORK) \ ipv4.address=10.10.10.1/24 \ ipv4.nat=true \ ipv4.dhcp=true \ dns.mode=managed \ dns.nameservers=8.8.8.8,1.1.1.1; \ else \ $(ECHO_CMD) "Updating network configuration..."; \ incus network set $(INCUS_NETWORK) ipv4.dhcp=true 2>/dev/null || true; \ incus network set $(INCUS_NETWORK) dns.mode=managed 2>/dev/null || true; \ incus network set $(INCUS_NETWORK) dns.nameservers=8.8.8.8,1.1.1.1 2>/dev/null || true; \ fi @if ! incus profile show $(INCUS_PROFILE) >/dev/null 2>&1; then \ $(ECHO_CMD) "Creating profile $(INCUS_PROFILE)..."; \ incus profile create $(INCUS_PROFILE); \ incus profile device add $(INCUS_PROFILE) root disk path=/ pool=default 2>/dev/null || \ incus profile device add $(INCUS_PROFILE) root disk path=/ 2>/dev/null || true; \ incus profile device add $(INCUS_PROFILE) eth0 nic network=$(INCUS_NETWORK) 2>/dev/null || true; \ else \ $(ECHO_CMD) "Ensuring profile devices..."; \ if ! incus profile show $(INCUS_PROFILE) | grep -q "root:"; then \ incus profile device add $(INCUS_PROFILE) root disk path=/ pool=default 2>/dev/null || \ incus profile device add $(INCUS_PROFILE) root disk path=/ 2>/dev/null || true; \ fi; \ if ! incus profile show $(INCUS_PROFILE) | grep -q "eth0:"; then \ incus profile device add $(INCUS_PROFILE) eth0 nic network=$(INCUS_NETWORK) 2>/dev/null || true; \ fi; \ fi @$(ECHO_CMD) "${GREEN}โœ… Incus network ready.${NC}" incus-deploy-all: incus-setup-network ## [MID] Deploy all services to Incus (legacy Docker method) @$(ECHO_CMD) "${BLUE}๐Ÿ“ฆ Deploying all services to Incus (Docker)...${NC}" @$(MAKE) -s incus-deploy-service SERVICE=backend-api @$(MAKE) -s incus-deploy-service SERVICE=chat-server @$(MAKE) -s incus-deploy-service SERVICE=stream-server @$(MAKE) -s incus-deploy-service SERVICE=web @$(MAKE) -s incus-deploy-service SERVICE=haproxy @$(ECHO_CMD) "${GREEN}โœ… All services deployed to Incus.${NC}" incus-deploy-all-native: incus-setup-network ## [MID] Deploy all services to Incus (native, no Docker) - excludes Rust services @$(ECHO_CMD) "${BLUE}๐Ÿ“ฆ Deploying all services to Incus (native, excluding Rust services)...${NC}" @$(ECHO_CMD) "${YELLOW}โš ๏ธ Note: chat-server and stream-server are excluded${NC}" @$(MAKE) -s incus-deploy-service-native SERVICE=backend-api @$(MAKE) -s incus-deploy-service-native SERVICE=web @$(MAKE) -s incus-deploy-service-native SERVICE=haproxy @$(ECHO_CMD) "${GREEN}โœ… All services deployed to Incus.${NC}" incus-deploy-service: ## [LOW] Deploy a service to Incus with Docker (usage: make incus-deploy-service SERVICE=backend-api) @if [ -z "$(SERVICE)" ]; then \ $(ECHO_CMD) "${RED}โŒ Please specify SERVICE=name${NC}"; \ exit 1; \ fi @$(ECHO_CMD) "${BLUE}๐Ÿ“ฆ Deploying $(SERVICE) to Incus (Docker)...${NC}" @if incus list -c n --format csv | grep -q "^veza-$(SERVICE)$$"; then \ $(ECHO_CMD) "${YELLOW}Container exists, removing...${NC}"; \ incus delete veza-$(SERVICE) --force; \ fi @incus init images:debian/13 veza-$(SERVICE) --profile $(INCUS_PROFILE) @incus start veza-$(SERVICE) @$(ECHO_CMD) "${BLUE}Installing Docker in container...${NC}" @incus exec veza-$(SERVICE) -- bash -c "apt-get update && apt-get install -y docker.io docker-compose && systemctl enable docker && systemctl start docker" || true @$(ECHO_CMD) "${GREEN}โœ… $(SERVICE) deployed.${NC}" incus-deploy-service-native: ## [LOW] Deploy a service to Incus natively (usage: make incus-deploy-service-native SERVICE=backend-api) @if [ -z "$(SERVICE)" ]; then \ $(ECHO_CMD) "${RED}โŒ Please specify SERVICE=name${NC}"; \ exit 1; \ fi @$(ECHO_CMD) "${BLUE}๐Ÿ“ฆ Deploying $(SERVICE) to Incus (native)...${NC}" @$(shell pwd)/config/incus/deploy-service-native.sh $(SERVICE) incus-deploy-infra: incus-setup-network ## [LOW] Deploy infrastructure services (PostgreSQL, Redis) @$(ECHO_CMD) "${BLUE}๐Ÿ“ฆ Deploying infrastructure services...${NC}" @$(MAKE) -s incus-deploy-service-native SERVICE=infra @$(ECHO_CMD) "${BLUE}Waiting for infrastructure to be ready...${NC}" @for i in $$(seq 1 30); do \ if incus exec veza-infra -- systemctl is-active postgresql >/dev/null 2>&1 && \ incus exec veza-infra -- systemctl is-active redis-server >/dev/null 2>&1; then \ $(ECHO_CMD) "${GREEN}โœ… Infrastructure services ready${NC}"; \ break; \ fi; \ sleep 1; \ done @$(ECHO_CMD) "${GREEN}โœ… Infrastructure deployed.${NC}" incus-start-all: ## [MID] Start all Incus services (excluding Rust services) @$(ECHO_CMD) "${BLUE}๐Ÿš€ Starting all Incus services (excluding Rust services)...${NC}" @for service in backend-api; do \ if incus list -c n --format csv | grep -q "^veza-$$service$$"; then \ $(ECHO_CMD) "Starting veza-$$service..."; \ if incus exec veza-$$service -- systemctl start veza-$$service 2>/dev/null; then \ $(ECHO_CMD) "${GREEN} โœ… veza-$$service started${NC}"; \ else \ $(ECHO_CMD) "${YELLOW} โš ๏ธ veza-$$service failed to start (check logs)${NC}"; \ fi; \ fi; \ done @if incus list -c n --format csv | grep -q "^veza-web$$"; then \ $(ECHO_CMD) "Starting veza-web..."; \ if incus exec veza-web -- systemctl start apache2 2>/dev/null; then \ $(ECHO_CMD) "${GREEN} โœ… Apache started${NC}"; \ else \ $(ECHO_CMD) "${YELLOW} โš ๏ธ Apache failed to start${NC}"; \ fi; \ fi @if incus list -c n --format csv | grep -q "^veza-haproxy$$"; then \ $(ECHO_CMD) "Starting veza-haproxy..."; \ if incus exec veza-haproxy -- systemctl start haproxy 2>/dev/null; then \ $(ECHO_CMD) "${GREEN} โœ… HAProxy started${NC}"; \ else \ $(ECHO_CMD) "${YELLOW} โš ๏ธ HAProxy failed to start${NC}"; \ fi; \ fi @if incus list -c n --format csv | grep -q "^veza-infra$$"; then \ $(ECHO_CMD) "Starting infrastructure services..."; \ if incus exec veza-infra -- systemctl start postgresql 2>/dev/null; then \ $(ECHO_CMD) "${GREEN} โœ… PostgreSQL started${NC}"; \ else \ $(ECHO_CMD) "${YELLOW} โš ๏ธ PostgreSQL failed to start${NC}"; \ fi; \ if incus exec veza-infra -- systemctl start redis-server 2>/dev/null; then \ $(ECHO_CMD) "${GREEN} โœ… Redis started${NC}"; \ else \ $(ECHO_CMD) "${YELLOW} โš ๏ธ Redis failed to start${NC}"; \ fi; \ fi @$(ECHO_CMD) "${GREEN}โœ… All services started.${NC}" @$(ECHO_CMD) "${BLUE}Run 'make incus-status' to check service status${NC}" incus-stop-all: ## [MID] Stop all Incus containers @$(ECHO_CMD) "${YELLOW}๐Ÿ›‘ Stopping all Incus containers...${NC}" @for container in $$(incus list -c n --format csv | grep veza-); do \ incus stop $$container 2>/dev/null || true; \ done @$(ECHO_CMD) "${GREEN}โœ… All Incus containers stopped.${NC}" incus-status: ## [MID] Show status of all Incus services @$(ECHO_CMD) "${BOLD}${CYAN}๐Ÿ“Š INCUS DEPLOYMENT STATUS${NC}" @$(ECHO_CMD) "" @$(ECHO_CMD) "${BOLD}Containers:${NC}" @incus list veza- --format table 2>/dev/null || echo " No containers found" @$(ECHO_CMD) "" @$(ECHO_CMD) "${BOLD}Service Status:${NC}" @for service in backend-api chat-server stream-server; do \ if incus list -c n --format csv 2>/dev/null | grep -q "^veza-$$service$$"; then \ STATUS=$$(incus exec veza-$$service -- systemctl is-active veza-$$service 2>/dev/null || echo "inactive"); \ if [ "$$STATUS" = "active" ]; then \ $(ECHO_CMD) " ${GREEN}โœ… veza-$$service: active${NC}"; \ else \ $(ECHO_CMD) " ${YELLOW}โš ๏ธ veza-$$service: $$STATUS${NC}"; \ fi; \ fi; \ done @if incus list -c n --format csv 2>/dev/null | grep -q "^veza-web$$"; then \ STATUS=$$(incus exec veza-web -- systemctl is-active apache2 2>/dev/null || echo "inactive"); \ if [ "$$STATUS" = "active" ]; then \ $(ECHO_CMD) " ${GREEN}โœ… veza-web (Apache): active${NC}"; \ else \ $(ECHO_CMD) " ${YELLOW}โš ๏ธ veza-web (Apache): $$STATUS${NC}"; \ fi; \ fi @if incus list -c n --format csv 2>/dev/null | grep -q "^veza-haproxy$$"; then \ STATUS=$$(incus exec veza-haproxy -- systemctl is-active haproxy 2>/dev/null || echo "inactive"); \ if [ "$$STATUS" = "active" ]; then \ $(ECHO_CMD) " ${GREEN}โœ… veza-haproxy: active${NC}"; \ else \ $(ECHO_CMD) " ${YELLOW}โš ๏ธ veza-haproxy: $$STATUS${NC}"; \ fi; \ fi @if incus list -c n --format csv 2>/dev/null | grep -q "^veza-infra$$"; then \ PG_STATUS=$$(incus exec veza-infra -- systemctl is-active postgresql 2>/dev/null || echo "inactive"); \ REDIS_STATUS=$$(incus exec veza-infra -- systemctl is-active redis-server 2>/dev/null || echo "inactive"); \ if [ "$$PG_STATUS" = "active" ]; then \ $(ECHO_CMD) " ${GREEN}โœ… PostgreSQL: active${NC}"; \ else \ $(ECHO_CMD) " ${YELLOW}โš ๏ธ PostgreSQL: $$PG_STATUS${NC}"; \ fi; \ if [ "$$REDIS_STATUS" = "active" ]; then \ $(ECHO_CMD) " ${GREEN}โœ… Redis: active${NC}"; \ else \ $(ECHO_CMD) " ${YELLOW}โš ๏ธ Redis: $$REDIS_STATUS${NC}"; \ fi; \ fi @$(ECHO_CMD) "" incus-logs: ## [LOW] Show logs from Incus container (usage: make incus-logs SERVICE=backend-api) @if [ -z "$(SERVICE)" ]; then \ $(ECHO_CMD) "${RED}โŒ Please specify SERVICE=name${NC}"; \ exit 1; \ fi @incus exec veza-$(SERVICE) -- journalctl -f # ============================================================================== # TEST & QUALITY # ============================================================================== .PHONY: test test-tmt lint fmt status test-tmt: ## [MID] Run Unified TMT Pipeline @$(ECHO_CMD) "${BLUE}๐Ÿงช Running TMT Pipeline...${NC}" @command -v tmt >/dev/null 2>&1 || { $(ECHO_CMD) "${RED}โŒ tmt is missing! Install with 'pip install tmt'${NC}"; exit 1; } @tmt run test: infra-up ## [MID] Run All Tests (Fastest strategy) @$(ECHO_CMD) "${BLUE}๐Ÿงช Running Tests...${NC}" @$(ECHO_CMD) " [Go] Unit Tests..." @(cd $(DIR_GO) && go test ./... -short) @$(ECHO_CMD) " [Rust] Unit Tests..." @(cd $(DIR_CHAT) && cargo test --lib -q) @(cd $(DIR_STREAM) && cargo test --lib -q) @$(ECHO_CMD) " [Web] Unit Tests..." @(cd $(DIR_WEB) && npm run test -- --run) @$(ECHO_CMD) "${GREEN}โœ… All tests passed.${NC}" lint: ## [MID] Lint everything @$(ECHO_CMD) "${BLUE}๐Ÿ” Linting Codebase...${NC}" @(cd $(DIR_CHAT) && cargo clippy -- -D warnings) || true @(cd $(DIR_STREAM) && cargo clippy -- -D warnings) || true @(cd $(DIR_GO) && golangci-lint run ./...) || true @(cd $(DIR_WEB) && npm run lint) || true fmt: ## [MID] Format everything @$(ECHO_CMD) "${BLUE}โœจ Formatting...${NC}" @(cd $(DIR_GO) && go fmt ./...) @(cd $(DIR_CHAT) && cargo fmt) @(cd $(DIR_STREAM) && cargo fmt) @(cd $(DIR_WEB) && npm run format) || true status: ## [MID] Show system health & stats @$(ECHO_CMD) "${BOLD}DOCKER STATS:${NC}" @docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}" 2>/dev/null | grep -E "NAME|veza" || echo "No containers running" @$(ECHO_CMD) "" @$(ECHO_CMD) "${BOLD}LOCAL PORTS:${NC}" @lsof -i :$(PORT_GO) -i :$(PORT_CHAT) -i :$(PORT_STREAM) -i :$(PORT_WEB) 2>/dev/null | grep LISTEN || echo "No apps listening."