feat(backend): implement v2 domain slice and live smoke

This commit is contained in:
zouantchaw
2026-03-11 18:23:55 +01:00
parent bc068373e9
commit fe43ff23cf
40 changed files with 5191 additions and 99 deletions

View File

@@ -49,6 +49,9 @@ BACKEND_V2_QUERY_DIR ?= backend/query-api
BACKEND_V2_SQL_INSTANCE ?= krow-sql-v2
BACKEND_V2_SQL_DATABASE ?= krow_v2_db
BACKEND_V2_SQL_APP_USER ?= krow_v2_app
BACKEND_V2_SQL_PASSWORD_SECRET ?= krow-v2-sql-app-password
BACKEND_V2_SQL_CONNECTION_NAME ?= $(GCP_PROJECT_ID):$(BACKEND_REGION):$(BACKEND_V2_SQL_INSTANCE)
BACKEND_V2_SQL_TIER ?= $(SQL_TIER)
BACKEND_V2_DEV_PUBLIC_BUCKET ?= krow-workforce-dev-v2-public
@@ -70,7 +73,7 @@ BACKEND_V2_CORE_IMAGE ?= $(BACKEND_REGION)-docker.pkg.dev/$(GCP_PROJECT_ID)/$(BA
BACKEND_V2_COMMAND_IMAGE ?= $(BACKEND_REGION)-docker.pkg.dev/$(GCP_PROJECT_ID)/$(BACKEND_V2_ARTIFACT_REPO)/command-api-v2:latest
BACKEND_V2_QUERY_IMAGE ?= $(BACKEND_REGION)-docker.pkg.dev/$(GCP_PROJECT_ID)/$(BACKEND_V2_ARTIFACT_REPO)/query-api-v2:latest
.PHONY: backend-help backend-enable-apis backend-bootstrap-dev backend-migrate-idempotency backend-deploy-core backend-deploy-commands backend-deploy-workers backend-smoke-core backend-smoke-commands backend-logs-core backend-bootstrap-v2-dev backend-deploy-core-v2 backend-deploy-commands-v2 backend-deploy-query-v2 backend-smoke-core-v2 backend-smoke-commands-v2 backend-smoke-query-v2 backend-logs-core-v2 backend-v2-migrate-idempotency
.PHONY: backend-help backend-enable-apis backend-bootstrap-dev backend-migrate-idempotency backend-deploy-core backend-deploy-commands backend-deploy-workers backend-smoke-core backend-smoke-commands backend-logs-core backend-bootstrap-v2-dev backend-deploy-core-v2 backend-deploy-commands-v2 backend-deploy-query-v2 backend-smoke-core-v2 backend-smoke-commands-v2 backend-smoke-query-v2 backend-logs-core-v2 backend-v2-migrate-idempotency backend-v2-migrate-schema
backend-help:
@echo "--> Backend Foundation Commands"
@@ -88,7 +91,8 @@ backend-help:
@echo " make backend-bootstrap-v2-dev [ENV=dev] Bootstrap isolated v2 resources and SQL instance"
@echo " make backend-deploy-core-v2 [ENV=dev] Build + deploy core API v2 service"
@echo " make backend-deploy-commands-v2 [ENV=dev] Build + deploy command API v2 service"
@echo " make backend-deploy-query-v2 [ENV=dev] Build + deploy query API v2 scaffold service"
@echo " make backend-deploy-query-v2 [ENV=dev] Build + deploy query API v2 service"
@echo " make backend-v2-migrate-schema Apply v2 domain schema against krow-sql-v2"
@echo " make backend-v2-migrate-idempotency Apply command idempotency migration against v2 DB"
@echo " make backend-smoke-core-v2 [ENV=dev] Smoke test core API v2 /health"
@echo " make backend-smoke-commands-v2 [ENV=dev] Smoke test command API v2 /health"
@@ -309,6 +313,29 @@ backend-bootstrap-v2-dev: backend-enable-apis
else \
echo " - Cloud SQL database already exists: $(BACKEND_V2_SQL_DATABASE)"; \
fi
@echo "--> Ensuring v2 SQL application password secret [$(BACKEND_V2_SQL_PASSWORD_SECRET)] exists..."
@if ! gcloud secrets describe $(BACKEND_V2_SQL_PASSWORD_SECRET) --project=$(GCP_PROJECT_ID) >/dev/null 2>&1; then \
PASSWORD=$$(openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 32); \
printf "%s" "$$PASSWORD" | gcloud secrets create $(BACKEND_V2_SQL_PASSWORD_SECRET) \
--replication-policy=automatic \
--data-file=- \
--project=$(GCP_PROJECT_ID); \
else \
echo " - Secret already exists: $(BACKEND_V2_SQL_PASSWORD_SECRET)"; \
fi
@echo "--> Ensuring v2 SQL application user [$(BACKEND_V2_SQL_APP_USER)] exists and matches the current secret..."
@DB_PASSWORD=$$(gcloud secrets versions access latest --secret=$(BACKEND_V2_SQL_PASSWORD_SECRET) --project=$(GCP_PROJECT_ID)); \
if gcloud sql users list --instance=$(BACKEND_V2_SQL_INSTANCE) --project=$(GCP_PROJECT_ID) --format='value(name)' | grep -qx "$(BACKEND_V2_SQL_APP_USER)"; then \
gcloud sql users set-password $(BACKEND_V2_SQL_APP_USER) \
--instance=$(BACKEND_V2_SQL_INSTANCE) \
--password="$$DB_PASSWORD" \
--project=$(GCP_PROJECT_ID) >/dev/null; \
else \
gcloud sql users create $(BACKEND_V2_SQL_APP_USER) \
--instance=$(BACKEND_V2_SQL_INSTANCE) \
--password="$$DB_PASSWORD" \
--project=$(GCP_PROJECT_ID) >/dev/null; \
fi
@echo "✅ Backend v2 foundation bootstrap complete for [$(ENV)]."
backend-deploy-core-v2:
@@ -330,16 +357,15 @@ backend-deploy-commands-v2:
@test -d $(BACKEND_V2_COMMAND_DIR) || (echo "❌ Missing directory: $(BACKEND_V2_COMMAND_DIR)" && exit 1)
@test -f $(BACKEND_V2_COMMAND_DIR)/Dockerfile || (echo "❌ Missing Dockerfile: $(BACKEND_V2_COMMAND_DIR)/Dockerfile" && exit 1)
@gcloud builds submit $(BACKEND_V2_COMMAND_DIR) --tag $(BACKEND_V2_COMMAND_IMAGE) --project=$(GCP_PROJECT_ID)
@EXTRA_ENV="APP_ENV=$(ENV),APP_STACK=v2,GCP_PROJECT_ID=$(GCP_PROJECT_ID),PUBLIC_BUCKET=$(BACKEND_V2_PUBLIC_BUCKET),PRIVATE_BUCKET=$(BACKEND_V2_PRIVATE_BUCKET),IDEMPOTENCY_STORE=memory"; \
if [ -n "$(IDEMPOTENCY_DATABASE_URL)" ]; then \
EXTRA_ENV="APP_ENV=$(ENV),APP_STACK=v2,GCP_PROJECT_ID=$(GCP_PROJECT_ID),PUBLIC_BUCKET=$(BACKEND_V2_PUBLIC_BUCKET),PRIVATE_BUCKET=$(BACKEND_V2_PRIVATE_BUCKET),IDEMPOTENCY_STORE=sql,IDEMPOTENCY_DATABASE_URL=$(IDEMPOTENCY_DATABASE_URL)"; \
fi; \
@EXTRA_ENV="APP_ENV=$(ENV),APP_STACK=v2,GCP_PROJECT_ID=$(GCP_PROJECT_ID),PUBLIC_BUCKET=$(BACKEND_V2_PUBLIC_BUCKET),PRIVATE_BUCKET=$(BACKEND_V2_PRIVATE_BUCKET),IDEMPOTENCY_STORE=sql,INSTANCE_CONNECTION_NAME=$(BACKEND_V2_SQL_CONNECTION_NAME),DB_NAME=$(BACKEND_V2_SQL_DATABASE),DB_USER=$(BACKEND_V2_SQL_APP_USER)"; \
gcloud run deploy $(BACKEND_V2_COMMAND_SERVICE_NAME) \
--image=$(BACKEND_V2_COMMAND_IMAGE) \
--region=$(BACKEND_REGION) \
--project=$(GCP_PROJECT_ID) \
--service-account=$(BACKEND_V2_RUNTIME_SA_EMAIL) \
--set-env-vars=$$EXTRA_ENV \
--set-secrets=DB_PASSWORD=$(BACKEND_V2_SQL_PASSWORD_SECRET):latest \
--add-cloudsql-instances=$(BACKEND_V2_SQL_CONNECTION_NAME) \
$(BACKEND_V2_RUN_AUTH_FLAG)
@echo "✅ Command backend v2 service deployed."
@@ -353,16 +379,24 @@ backend-deploy-query-v2:
--region=$(BACKEND_REGION) \
--project=$(GCP_PROJECT_ID) \
--service-account=$(BACKEND_V2_RUNTIME_SA_EMAIL) \
--set-env-vars=APP_ENV=$(ENV),APP_STACK=v2,GCP_PROJECT_ID=$(GCP_PROJECT_ID) \
--set-env-vars=APP_ENV=$(ENV),APP_STACK=v2,GCP_PROJECT_ID=$(GCP_PROJECT_ID),INSTANCE_CONNECTION_NAME=$(BACKEND_V2_SQL_CONNECTION_NAME),DB_NAME=$(BACKEND_V2_SQL_DATABASE),DB_USER=$(BACKEND_V2_SQL_APP_USER) \
--set-secrets=DB_PASSWORD=$(BACKEND_V2_SQL_PASSWORD_SECRET):latest \
--add-cloudsql-instances=$(BACKEND_V2_SQL_CONNECTION_NAME) \
$(BACKEND_V2_RUN_AUTH_FLAG)
@echo "✅ Query backend v2 service deployed."
backend-v2-migrate-idempotency:
@echo "--> Applying idempotency table migration for command API v2..."
@test -n "$(IDEMPOTENCY_DATABASE_URL)" || (echo "❌ IDEMPOTENCY_DATABASE_URL is required" && exit 1)
@cd $(BACKEND_V2_COMMAND_DIR) && IDEMPOTENCY_DATABASE_URL="$(IDEMPOTENCY_DATABASE_URL)" npm run migrate:idempotency
@test -n "$(IDEMPOTENCY_DATABASE_URL)$(DATABASE_URL)" || (echo "❌ IDEMPOTENCY_DATABASE_URL or DATABASE_URL is required" && exit 1)
@cd $(BACKEND_V2_COMMAND_DIR) && IDEMPOTENCY_DATABASE_URL="$(IDEMPOTENCY_DATABASE_URL)" DATABASE_URL="$(DATABASE_URL)" npm run migrate:idempotency
@echo "✅ Idempotency migration applied for command API v2."
backend-v2-migrate-schema:
@echo "--> Applying v2 domain schema migration..."
@test -n "$(DATABASE_URL)" || (echo "❌ DATABASE_URL is required" && exit 1)
@cd $(BACKEND_V2_COMMAND_DIR) && DATABASE_URL="$(DATABASE_URL)" npm run migrate:v2-schema
@echo "✅ V2 domain schema migration applied."
backend-smoke-core-v2:
@echo "--> Running core v2 smoke check..."
@URL=$$(gcloud run services describe $(BACKEND_V2_CORE_SERVICE_NAME) --region=$(BACKEND_REGION) --project=$(GCP_PROJECT_ID) --format='value(status.url)'); \
@@ -381,7 +415,7 @@ backend-smoke-commands-v2:
exit 1; \
fi; \
TOKEN=$$(gcloud auth print-identity-token); \
curl -fsS -H "Authorization: Bearer $$TOKEN" "$$URL/health" >/dev/null && echo "✅ Command v2 smoke check passed: $$URL/health"
curl -fsS -H "Authorization: Bearer $$TOKEN" "$$URL/readyz" >/dev/null && echo "✅ Command v2 smoke check passed: $$URL/readyz"
backend-smoke-query-v2:
@echo "--> Running query v2 smoke check..."
@@ -391,7 +425,7 @@ backend-smoke-query-v2:
exit 1; \
fi; \
TOKEN=$$(gcloud auth print-identity-token); \
curl -fsS -H "Authorization: Bearer $$TOKEN" "$$URL/health" >/dev/null && echo "✅ Query v2 smoke check passed: $$URL/health"
curl -fsS -H "Authorization: Bearer $$TOKEN" "$$URL/readyz" >/dev/null && echo "✅ Query v2 smoke check passed: $$URL/readyz"
backend-logs-core-v2:
@echo "--> Reading logs for core backend v2 service [$(BACKEND_V2_CORE_SERVICE_NAME)]..."