REPO_OWNER := celesrenata REPO_NAME := stonks-oracle GHCR := ghcr.io/$(REPO_OWNER)/$(REPO_NAME) SHA := $(shell git rev-parse --short HEAD 2>/dev/null || echo "dev") SERVICES := scheduler symbol-registry ingestion parser extractor aggregation recommendation risk broker-adapter lake-publisher query-api .PHONY: help lint test build push deploy clean help: @echo "Targets:" @echo " lint - Run ruff linter" @echo " test - Run pytest" @echo " build - Build all service images locally" @echo " push - Push all images to GHCR" @echo " deploy - Apply K8s manifests" @echo " clean - Remove local images" lint: ruff check services/ test: pytest tests/ -x --tb=short -q build: @for svc in $(SERVICES); do \ case $$svc in \ scheduler) cmd="python -m services.scheduler.app" ;; \ symbol-registry) cmd="uvicorn services.symbol_registry.app:app --host 0.0.0.0 --port 8000" ;; \ ingestion) cmd="python -m services.ingestion.worker" ;; \ parser) cmd="python -m services.parser.worker" ;; \ extractor) cmd="python -m services.extractor.main" ;; \ aggregation) cmd="python -m services.aggregation.main" ;; \ recommendation) cmd="python -m services.recommendation.main" ;; \ risk) cmd="uvicorn services.risk.app:app --host 0.0.0.0 --port 8000" ;; \ broker-adapter) cmd="python -m services.adapters.broker_service" ;; \ lake-publisher) cmd="python -m services.lake_publisher.jobs" ;; \ query-api) cmd="uvicorn services.api.app:app --host 0.0.0.0 --port 8000" ;; \ esac; \ echo "Building $$svc ($$cmd)..."; \ docker build \ --build-arg "SERVICE_CMD=$$cmd" \ -t $(GHCR)/$$svc:$(SHA) \ -t $(GHCR)/$$svc:latest \ -f docker/Dockerfile . || exit 1; \ done push: @for svc in $(SERVICES); do \ echo "Pushing $$svc..."; \ docker push $(GHCR)/$$svc:$(SHA); \ docker push $(GHCR)/$$svc:latest; \ done deploy: kubectl apply -f infra/k8s/namespace.yaml kubectl apply -f infra/k8s/configmap.yaml kubectl apply -f infra/k8s/secrets.yaml kubectl apply -f infra/k8s/ clean: @for svc in $(SERVICES); do \ docker rmi $(GHCR)/$$svc:$(SHA) $(GHCR)/$$svc:latest 2>/dev/null || true; \ done