feat(attendance): add notification delivery and NFC security foundation
This commit is contained in:
@@ -41,6 +41,7 @@ BACKEND_V2_CORE_SERVICE_NAME ?= krow-core-api-v2
|
||||
BACKEND_V2_COMMAND_SERVICE_NAME ?= krow-command-api-v2
|
||||
BACKEND_V2_QUERY_SERVICE_NAME ?= krow-query-api-v2
|
||||
BACKEND_V2_UNIFIED_SERVICE_NAME ?= krow-api-v2
|
||||
BACKEND_V2_NOTIFICATION_JOB_NAME ?= krow-notification-dispatcher-v2
|
||||
BACKEND_V2_RUNTIME_SA_NAME ?= krow-backend-v2-runtime
|
||||
BACKEND_V2_RUNTIME_SA_EMAIL := $(BACKEND_V2_RUNTIME_SA_NAME)@$(GCP_PROJECT_ID).iam.gserviceaccount.com
|
||||
|
||||
@@ -76,8 +77,17 @@ BACKEND_V2_COMMAND_IMAGE ?= $(BACKEND_REGION)-docker.pkg.dev/$(GCP_PROJECT_ID)/$
|
||||
BACKEND_V2_QUERY_IMAGE ?= $(BACKEND_REGION)-docker.pkg.dev/$(GCP_PROJECT_ID)/$(BACKEND_V2_ARTIFACT_REPO)/query-api-v2:latest
|
||||
BACKEND_V2_UNIFIED_IMAGE ?= $(BACKEND_REGION)-docker.pkg.dev/$(GCP_PROJECT_ID)/$(BACKEND_V2_ARTIFACT_REPO)/unified-api-v2:latest
|
||||
BACKEND_V2_FIREBASE_WEB_API_KEY_SECRET ?= firebase-web-api-key
|
||||
BACKEND_V2_NOTIFICATION_BATCH_LIMIT ?= 50
|
||||
BACKEND_V2_PUSH_DELIVERY_MODE ?= live
|
||||
BACKEND_V2_SHIFT_REMINDERS_ENABLED ?= true
|
||||
BACKEND_V2_SHIFT_REMINDER_LEAD_MINUTES ?= 60,15
|
||||
BACKEND_V2_SHIFT_REMINDER_WINDOW_MINUTES ?= 5
|
||||
BACKEND_V2_NFC_ENFORCE_PROOF_NONCE ?= false
|
||||
BACKEND_V2_NFC_ENFORCE_DEVICE_ID ?= false
|
||||
BACKEND_V2_NFC_ENFORCE_ATTESTATION ?= false
|
||||
BACKEND_V2_NFC_PROOF_MAX_AGE_SECONDS ?= 120
|
||||
|
||||
.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-deploy-unified-v2 backend-smoke-core-v2 backend-smoke-commands-v2 backend-smoke-query-v2 backend-smoke-unified-v2 backend-logs-core-v2 backend-v2-migrate-idempotency backend-v2-migrate-schema
|
||||
.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-deploy-unified-v2 backend-deploy-notification-job-v2 backend-run-notification-job-v2 backend-smoke-core-v2 backend-smoke-commands-v2 backend-smoke-query-v2 backend-smoke-unified-v2 backend-logs-core-v2 backend-v2-migrate-idempotency backend-v2-migrate-schema
|
||||
|
||||
backend-help:
|
||||
@echo "--> Backend Foundation Commands"
|
||||
@@ -97,6 +107,8 @@ backend-help:
|
||||
@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 service"
|
||||
@echo " make backend-deploy-unified-v2 [ENV=dev] Build + deploy unified API v2 gateway"
|
||||
@echo " make backend-deploy-notification-job-v2 Deploy notification dispatcher v2 job"
|
||||
@echo " make backend-run-notification-job-v2 Run notification dispatcher v2 job once"
|
||||
@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"
|
||||
@@ -283,6 +295,10 @@ backend-bootstrap-v2-dev: backend-enable-apis
|
||||
--member="serviceAccount:$(BACKEND_V2_RUNTIME_SA_EMAIL)" \
|
||||
--role="roles/secretmanager.secretAccessor" \
|
||||
--quiet >/dev/null
|
||||
@gcloud projects add-iam-policy-binding $(GCP_PROJECT_ID) \
|
||||
--member="serviceAccount:$(BACKEND_V2_RUNTIME_SA_EMAIL)" \
|
||||
--role="roles/firebasecloudmessaging.admin" \
|
||||
--quiet >/dev/null
|
||||
@gcloud iam service-accounts add-iam-policy-binding $(BACKEND_V2_RUNTIME_SA_EMAIL) \
|
||||
--member="serviceAccount:$(BACKEND_V2_RUNTIME_SA_EMAIL)" \
|
||||
--role="roles/iam.serviceAccountTokenCreator" \
|
||||
@@ -357,7 +373,7 @@ backend-deploy-core-v2:
|
||||
--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) \
|
||||
--set-cloudsql-instances=$(BACKEND_V2_SQL_CONNECTION_NAME) \
|
||||
$(BACKEND_V2_RUN_AUTH_FLAG)
|
||||
@echo "✅ Core backend v2 service deployed."
|
||||
|
||||
@@ -366,7 +382,7 @@ 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=sql,INSTANCE_CONNECTION_NAME=$(BACKEND_V2_SQL_CONNECTION_NAME),DB_NAME=$(BACKEND_V2_SQL_DATABASE),DB_USER=$(BACKEND_V2_SQL_APP_USER)"; \
|
||||
@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),NOTIFICATION_BATCH_LIMIT=$(BACKEND_V2_NOTIFICATION_BATCH_LIMIT),PUSH_DELIVERY_MODE=$(BACKEND_V2_PUSH_DELIVERY_MODE),SHIFT_REMINDERS_ENABLED=$(BACKEND_V2_SHIFT_REMINDERS_ENABLED),SHIFT_REMINDER_WINDOW_MINUTES=$(BACKEND_V2_SHIFT_REMINDER_WINDOW_MINUTES),NFC_ENFORCE_PROOF_NONCE=$(BACKEND_V2_NFC_ENFORCE_PROOF_NONCE),NFC_ENFORCE_DEVICE_ID=$(BACKEND_V2_NFC_ENFORCE_DEVICE_ID),NFC_ENFORCE_ATTESTATION=$(BACKEND_V2_NFC_ENFORCE_ATTESTATION),NFC_PROOF_MAX_AGE_SECONDS=$(BACKEND_V2_NFC_PROOF_MAX_AGE_SECONDS)"; \
|
||||
gcloud run deploy $(BACKEND_V2_COMMAND_SERVICE_NAME) \
|
||||
--image=$(BACKEND_V2_COMMAND_IMAGE) \
|
||||
--region=$(BACKEND_REGION) \
|
||||
@@ -374,10 +390,39 @@ backend-deploy-commands-v2:
|
||||
--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) \
|
||||
--set-cloudsql-instances=$(BACKEND_V2_SQL_CONNECTION_NAME) \
|
||||
$(BACKEND_V2_RUN_AUTH_FLAG)
|
||||
@echo "✅ Command backend v2 service deployed."
|
||||
|
||||
backend-deploy-notification-job-v2:
|
||||
@echo "--> Deploying notification dispatcher v2 job [$(BACKEND_V2_NOTIFICATION_JOB_NAME)]..."
|
||||
@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)
|
||||
@gcloud run jobs deploy $(BACKEND_V2_NOTIFICATION_JOB_NAME) \
|
||||
--image=$(BACKEND_V2_COMMAND_IMAGE) \
|
||||
--region=$(BACKEND_REGION) \
|
||||
--project=$(GCP_PROJECT_ID) \
|
||||
--service-account=$(BACKEND_V2_RUNTIME_SA_EMAIL) \
|
||||
--command=node \
|
||||
--args=scripts/dispatch-notifications.mjs \
|
||||
--set-env-vars=APP_ENV=$(ENV),APP_STACK=v2,GCP_PROJECT_ID=$(GCP_PROJECT_ID),PUBLIC_BUCKET=$(BACKEND_V2_PUBLIC_BUCKET),PRIVATE_BUCKET=$(BACKEND_V2_PRIVATE_BUCKET),INSTANCE_CONNECTION_NAME=$(BACKEND_V2_SQL_CONNECTION_NAME),DB_NAME=$(BACKEND_V2_SQL_DATABASE),DB_USER=$(BACKEND_V2_SQL_APP_USER),NOTIFICATION_BATCH_LIMIT=$(BACKEND_V2_NOTIFICATION_BATCH_LIMIT),PUSH_DELIVERY_MODE=$(BACKEND_V2_PUSH_DELIVERY_MODE),SHIFT_REMINDERS_ENABLED=$(BACKEND_V2_SHIFT_REMINDERS_ENABLED),SHIFT_REMINDER_WINDOW_MINUTES=$(BACKEND_V2_SHIFT_REMINDER_WINDOW_MINUTES),NFC_ENFORCE_PROOF_NONCE=$(BACKEND_V2_NFC_ENFORCE_PROOF_NONCE),NFC_ENFORCE_DEVICE_ID=$(BACKEND_V2_NFC_ENFORCE_DEVICE_ID),NFC_ENFORCE_ATTESTATION=$(BACKEND_V2_NFC_ENFORCE_ATTESTATION),NFC_PROOF_MAX_AGE_SECONDS=$(BACKEND_V2_NFC_PROOF_MAX_AGE_SECONDS) \
|
||||
--set-secrets=DB_PASSWORD=$(BACKEND_V2_SQL_PASSWORD_SECRET):latest \
|
||||
--set-cloudsql-instances=$(BACKEND_V2_SQL_CONNECTION_NAME) \
|
||||
--tasks=1 \
|
||||
--parallelism=1 \
|
||||
--max-retries=1 \
|
||||
--task-timeout=10m
|
||||
@echo "✅ Notification dispatcher v2 job deployed."
|
||||
|
||||
backend-run-notification-job-v2:
|
||||
@echo "--> Running notification dispatcher v2 job [$(BACKEND_V2_NOTIFICATION_JOB_NAME)]..."
|
||||
@gcloud run jobs execute $(BACKEND_V2_NOTIFICATION_JOB_NAME) \
|
||||
--region=$(BACKEND_REGION) \
|
||||
--project=$(GCP_PROJECT_ID) \
|
||||
--wait
|
||||
@echo "✅ Notification dispatcher v2 job completed."
|
||||
|
||||
backend-deploy-query-v2:
|
||||
@echo "--> Deploying query backend v2 service [$(BACKEND_V2_QUERY_SERVICE_NAME)] to [$(ENV)]..."
|
||||
@test -d $(BACKEND_V2_QUERY_DIR) || (echo "❌ Missing directory: $(BACKEND_V2_QUERY_DIR)" && exit 1)
|
||||
|
||||
Reference in New Issue
Block a user