# KROW Workforce Project Makefile # ------------------------------- # This Makefile provides a central place for common project commands. # It is designed to be the main entry point for developers. # Use .PHONY to declare targets that are not files, to avoid conflicts. .PHONY: help install dev build integrate-export prepare-export deploy-launchpad deploy-launchpad-full deploy-app admin-install admin-dev admin-build deploy-admin deploy-admin-full configure-iap-launchpad configure-iap-admin list-iap-users remove-iap-user setup-labels export-issues create-issues-from-file install-git-hooks mobile-client-install mobile-client-dev mobile-client-build mobile-staff-install mobile-staff-dev mobile-staff-build # The default command to run if no target is specified (e.g., just 'make'). .DEFAULT_GOAL := help # --- Flutter check --- FLUTTER := $(shell which flutter) ifeq ($(FLUTTER),) $(error "flutter not found in PATH. Please install Flutter and add it to your PATH.") endif # --- Firebase & GCP Configuration --- GCP_DEV_PROJECT_ID := krow-workforce-dev GCP_STAGING_PROJECT_ID := krow-workforce-staging IAP_SERVICE_ACCOUNT := service-933560802882@gcp-sa-iap.iam.gserviceaccount.com # --- Cloud Run Configuration --- CR_LAUNCHPAD_SERVICE_NAME := internal-launchpad CR_LAUNCHPAD_REGION := us-central1 CR_LAUNCHPAD_IMAGE_URI := us-docker.pkg.dev/$(GCP_DEV_PROJECT_ID)/gcr-io/$(CR_LAUNCHPAD_SERVICE_NAME) CR_ADMIN_SERVICE_NAME := admin-console CR_ADMIN_REGION := us-central1 CR_ADMIN_IMAGE_URI = us-docker.pkg.dev/$(GCP_PROJECT_ID)/gcr-io/$(CR_ADMIN_SERVICE_NAME) # --- Environment Detection --- ENV ?= dev SERVICE ?= launchpad # Default service for IAP commands: 'launchpad' or 'admin' # --- Conditional Variables by Environment --- ifeq ($(ENV),staging) GCP_PROJECT_ID := $(GCP_STAGING_PROJECT_ID) FIREBASE_ALIAS := staging HOSTING_TARGET := app-staging else GCP_PROJECT_ID := $(GCP_DEV_PROJECT_ID) FIREBASE_ALIAS := dev HOSTING_TARGET := app-dev endif # --- Conditional Variables by Service for IAP commands --- ifeq ($(SERVICE),admin) IAP_SERVICE_NAME := $(CR_ADMIN_SERVICE_NAME) IAP_SERVICE_REGION := $(CR_ADMIN_REGION) IAP_PROJECT_ID := $(GCP_PROJECT_ID) # Admin console is env-specific else IAP_SERVICE_NAME := $(CR_LAUNCHPAD_SERVICE_NAME) IAP_SERVICE_REGION := $(CR_LAUNCHPAD_REGION) IAP_PROJECT_ID := $(GCP_DEV_PROJECT_ID) # Launchpad is dev-only endif # Shows this help message. help: @echo "--------------------------------------------------" @echo " KROW Workforce - Available Makefile Commands" @echo "--------------------------------------------------" @echo "" @echo " --- CORE DEVELOPMENT ---" @echo " make install - Installs web frontend dependencies." @echo " make dev - Starts the local web frontend server." @echo " make build - Builds the web frontend for production." @echo "" @echo " --- MOBILE APP DEVELOPMENT ---" @echo " make mobile-client-install - Install dependencies for client app" @echo " make mobile-client-dev - Run client app in development mode" @echo " make mobile-client-build - Build client app (requires ENV & PLATFORM)" @echo "" @echo " make mobile-staff-install - Install dependencies for staff app" @echo " make mobile-staff-dev - Run staff app in development mode" @echo " make mobile-staff-build - Build staff app (requires ENV & PLATFORM)" @echo "" @echo " --- DEPLOYMENT ---" @echo " make deploy-launchpad-full - Deploys internal launchpad to Cloud Run (dev only) with IAP." @echo " make deploy-admin-full [ENV=staging] - Deploys Admin Console to Cloud Run with IAP (default: dev)." @echo " make deploy-app [ENV=staging] - Builds and deploys the main web app via Firebase Hosting (default: dev)." @echo "" @echo " --- CLOUD IAP MANAGEMENT ---" @echo " make list-iap-users [SERVICE=admin] - Lists IAP users for a service (default: launchpad)." @echo " make remove-iap-user USER=... [SERVICE=admin] - Removes an IAP user from a service." @echo "" @echo " --- PROJECT MANAGEMENT & TOOLS ---" @echo " make setup-labels - Creates/updates GitHub labels from labels.yml." @echo " make export-issues [ARGS=\"--state=all --label=bug\"] - Exports GitHub issues to a markdown file. See scripts/export_issues.sh for options." @echo " make create-issues-from-file - Bulk creates GitHub issues from a markdown file." @echo " make install-git-hooks - Installs git pre-push hook to protect main/dev branches." @echo "" @echo " --- DATA CONNECT MANAGEMENT ---" @echo " make dataconnect-enable-apis - Enables required GCP APIs for Data Connect." @echo " make dataconnect-init - Initializes Firebase Data Connect (interactive wizard)." @echo " make dataconnect-deploy - Deploys Data Connect schemas (GraphQL -> Cloud SQL)." @echo "" @echo " --- BASE44 EXPORT WORKFLOW ---" @echo " make integrate-export - Integrates a new Base44 export from '../krow-workforce-export-latest'." @echo " make prepare-export - Prepares a fresh Base44 export for local use." @echo "" @echo " make help - Shows this help message." @echo "--------------------------------------------------" # --- Core Development --- install: @echo "--> Installing web frontend dependencies..." @cd frontend-web && npm install dev: @echo "--> Ensuring web frontend dependencies are installed..." @cd frontend-web && npm install @echo "--> Starting web frontend development server on http://localhost:5173 ..." @cd frontend-web && npm run dev build: @echo "--> Building web frontend for production..." @cd frontend-web && VITE_APP_ENV=$(ENV) npm run build # --- Deployment --- deploy-launchpad: @echo "--> Building and deploying Internal Launchpad to Cloud Run..." @echo " - Step 1: Building container image..." @cd firebase/internal-launchpad && gcloud builds submit \ --tag $(CR_LAUNCHPAD_IMAGE_URI) \ --project=$(GCP_DEV_PROJECT_ID) @echo " - Step 2: Deploying to Cloud Run..." @gcloud run deploy $(CR_LAUNCHPAD_SERVICE_NAME) \ --image $(CR_LAUNCHPAD_IMAGE_URI) \ --platform managed \ --region $(CR_LAUNCHPAD_REGION) \ --no-allow-unauthenticated \ --project=$(GCP_DEV_PROJECT_ID) @echo " - Step 3: Enabling IAP on the service..." @gcloud beta run services update $(CR_LAUNCHPAD_SERVICE_NAME) \ --region=$(CR_LAUNCHPAD_REGION) \ --project=$(GCP_DEV_PROJECT_ID) \ --iap @echo "--> ✅ Deployment to Cloud Run successful." deploy-launchpad-full: deploy-launchpad configure-iap-launchpad @echo "✅ Launchpad deployed and IAP configured successfully!" deploy-app: build @echo "--> Deploying Frontend Web App to [$(ENV)] environment..." @firebase deploy --only hosting:$(HOSTING_TARGET) --project=$(FIREBASE_ALIAS) # --- Admin Console --- admin-install: @echo "--> Installing admin console dependencies..." @cd admin-web && npm install admin-dev: @echo "--> Starting admin console development server on http://localhost:5174 ..." @cd admin-web && npm run dev -- --port 5174 admin-build: @echo "--> Building admin console for production..." @node scripts/patch-admin-layout-for-env-label.js @cd admin-web && VITE_APP_ENV=$(ENV) npm run build deploy-admin: admin-build @echo "--> Building and deploying Admin Console to Cloud Run [$(ENV)]..." @echo " - Step 1: Building container image..." @cd admin-web && gcloud builds submit \ --tag $(CR_ADMIN_IMAGE_URI) \ --project=$(GCP_PROJECT_ID) @echo " - Step 2: Deploying to Cloud Run..." @gcloud run deploy $(CR_ADMIN_SERVICE_NAME) \ --image $(CR_ADMIN_IMAGE_URI) \ --platform managed \ --region $(CR_ADMIN_REGION) \ --no-allow-unauthenticated \ --project=$(GCP_PROJECT_ID) @echo " - Step 3: Enabling IAP on the service..." @gcloud beta run services update $(CR_ADMIN_SERVICE_NAME) \ --region=$(CR_ADMIN_REGION) \ --project=$(GCP_PROJECT_ID) \ --iap @echo "--> ✅ Admin Console deployment to Cloud Run successful." deploy-admin-full: deploy-admin configure-iap-admin @echo "✅ Admin Console deployed and IAP configured successfully!" # --- Cloud IAP Configuration --- configure-iap-launchpad: @echo "--> Configuring IAP for Cloud Run service [$(CR_LAUNCHPAD_SERVICE_NAME)]..." @echo " - Granting Cloud Run Invoker role to IAP Service Account..." @gcloud run services add-iam-policy-binding $(CR_LAUNCHPAD_SERVICE_NAME) \ --region=$(CR_LAUNCHPAD_REGION) \ --project=$(GCP_DEV_PROJECT_ID) \ --member=\"serviceAccount:$(IAP_SERVICE_ACCOUNT)\" \ --role='roles/run.invoker' \ --quiet @echo " - Adding users from iap-users.txt..." @cd firebase/internal-launchpad && \ grep -v '^#' iap-users.txt | grep -v '^$$' | while read -r member; do \ echo " Adding $$member as IAP-secured Web App User..."; \ gcloud beta iap web add-iam-policy-binding \ --project=$(GCP_DEV_PROJECT_ID) \ --resource-type=cloud-run \ --service=$(CR_LAUNCHPAD_SERVICE_NAME) \ --region=$(CR_LAUNCHPAD_REGION) \ --member=\"$$member\" \ --role='roles/iap.httpsResourceAccessor' \ --quiet; \ done @echo "✅ IAP configuration for Launchpad complete." configure-iap-admin: @echo "--> Configuring IAP for Cloud Run service [$(CR_ADMIN_SERVICE_NAME)] in [$(ENV)]..." @echo " - Granting Cloud Run Invoker role to IAP Service Account..." @gcloud run services add-iam-policy-binding $(CR_ADMIN_SERVICE_NAME) \ --region=$(CR_ADMIN_REGION) \ --project=$(GCP_PROJECT_ID) \ --member=\"serviceAccount:$(IAP_SERVICE_ACCOUNT)\" \ --role='roles/run.invoker' \ --quiet @echo " - Adding users from iap-users.txt..." @cd admin-web && \ grep -v '^#' iap-users.txt | grep -v '^$$' | while read -r member; do \ echo " Adding $$member as IAP-secured Web App User..."; \ gcloud beta iap web add-iam-policy-binding \ --project=$(GCP_PROJECT_ID) \ --resource-type=cloud-run \ --service=$(CR_ADMIN_SERVICE_NAME) \ --region=$(CR_ADMIN_REGION) \ --member=\"$$member\" \ --role='roles/iap.httpsResourceAccessor' \ --quiet; \ done @echo "✅ IAP configuration for Admin Console complete." list-iap-users: @echo "--> Current IAP users for Cloud Run service [$(IAP_SERVICE_NAME)]:" @gcloud beta iap web get-iam-policy \ --project=$(IAP_PROJECT_ID) \ --resource-type=cloud-run \ --service=$(IAP_SERVICE_NAME) \ --region=$(IAP_SERVICE_REGION) remove-iap-user: @if [ -z "$(USER)" ]; then \ echo "❌ Error: Please specify USER=user:email@example.com"; \ exit 1; \ fi @echo "--> Removing IAP access for $(USER) from Cloud Run service [$(IAP_SERVICE_NAME)]..." @gcloud beta iap web remove-iam-policy-binding \ --project=$(IAP_PROJECT_ID) \ --resource-type=cloud-run \ --service=$(IAP_SERVICE_NAME) \ --region=$(IAP_SERVICE_REGION) \ --member=\"$(USER)\" \ --role='roles/iap.httpsResourceAccessor' \ --quiet @echo "✅ User removed from IAP." # --- Project Management --- setup-labels: @echo "--> Setting up GitHub labels..." @./scripts/setup-github-labels.sh export-issues: @echo "--> Exporting GitHub issues to documentation..." @./scripts/export_issues.sh $(ARGS) create-issues-from-file: @echo "--> Creating GitHub issues from file..." @./scripts/create_issues.py # --- Development Tools --- install-git-hooks: @echo "--> Installing Git hooks..." @ln -sf ../../scripts/git-hooks/pre-push .git/hooks/pre-push @echo "✅ pre-push hook installed successfully. Direct pushes to 'main' and 'dev' are now blocked." # --- Base44 Export Workflow --- integrate-export: @echo "--> Integrating new Base44 export into frontend-web/..." @if [ ! -d "../krow-workforce-export-latest" ]; then \ echo "❌ Error: Export directory '../krow-workforce-export-latest' not found."; \ exit 1; \ fi @echo " - Removing old src directory..." @rm -rf frontend-web/src @echo " - Copying new src directory..." @cp -R ../krow-workforce-export-latest/src ./frontend-web/src @echo " - Copying new index.html..." @cp ../krow-workforce-export-latest/index.html ./frontend-web/index.html @echo " - Patching base44Client.js for local development..." @node scripts/patch-base44-client.js @echo " - Patching queryKey in Layout.jsx for local development..." @node scripts/patch-layout-query-key.js @echo " - Patching Dashboard.jsx for environment label..." @node scripts/patch-dashboard-for-env-label.js @echo " - Patching index.html for title..." @node scripts/patch-index-html.js @echo "--> Integration complete. Next step: 'make prepare-export'." prepare-export: @echo "--> Preparing fresh Base44 export for local development..." @node scripts/prepare-export.js @echo "--> Preparation complete. You can now run 'make dev'." # --- Data Connect / Backend --- # Enable all required APIs for Firebase Data Connect + Cloud SQL dataconnect-enable-apis: @echo "--> Enabling Firebase & Data Connect APIs on project [$(GCP_PROJECT_ID)]..." @gcloud services enable firebase.googleapis.com --project=$(GCP_PROJECT_ID) @gcloud services enable firebasedataconnect.googleapis.com --project=$(GCP_PROJECT_ID) @gcloud services enable sqladmin.googleapis.com --project=$(GCP_PROJECT_ID) @gcloud services enable iam.googleapis.com --project=$(GCP_PROJECT_ID) @gcloud services enable cloudresourcemanager.googleapis.com --project=$(GCP_PROJECT_ID) @echo "✅ APIs enabled for project [$(GCP_PROJECT_ID)]." # Initialize Firebase Data Connect (interactive wizard). # This wraps the command so we remember how to run it for dev/staging/prod. dataconnect-init: @echo "--> Initializing Firebase Data Connect for alias [$(FIREBASE_ALIAS)] (project: $(GCP_PROJECT_ID))..." @firebase init dataconnect --project $(FIREBASE_ALIAS) @echo "✅ Data Connect initialization command executed. Follow the interactive steps in the CLI." # Deploy Data Connect schemas (GraphQL → Cloud SQL) dataconnect-deploy: @echo "--> Deploying Firebase Data Connect schemas to [$(ENV)] (project: $(FIREBASE_ALIAS))..." @firebase deploy --only dataconnect --project=$(FIREBASE_ALIAS) @echo "✅ Data Connect deployment completed for [$(ENV)]." # --- Mobile App Development --- FLAVOR := ifeq ($(ENV),dev) FLAVOR := development else ifeq ($(ENV),staging) FLAVOR := staging else ifeq ($(ENV),prod) FLAVOR := production endif mobile-client-install: @echo "--> Installing Flutter dependencies for client app..." @cd mobile-apps/client-app && \ $(FLUTTER) pub get && \ $(FLUTTER) pub run build_runner build --delete-conflicting-outputs mobile-client-dev: @echo "--> Running client app in development mode..." @echo "--> If using VS code, use the debug configurations" @cd mobile-apps/client-app && $(FLUTTER) run --flavor development -t lib/main_dev.dart mobile-client-build: @if [ "$(ENV)" != "dev" ] && [ "$(ENV)" != "staging" ] && [ "$(ENV)" != "prod" ]; then \ echo "ERROR: ENV must be one of dev, staging, or prod."; exit 1; \ fi @if [ "$(PLATFORM)" != "android" ] && [ "$(PLATFORM)" != "ios" ]; then \ echo "ERROR: PLATFORM must be either android or ios."; exit 1; \ fi @echo "--> Building client app for $(PLATFORM) with flavor $(FLAVOR)..." @cd mobile-apps/client-app && \ $(FLUTTER) pub get && \ $(FLUTTER) pub run build_runner build --delete-conflicting-outputs && \ if [ "$(PLATFORM)" = "android" ]; then \ $(FLUTTER) build appbundle --flavor $(FLAVOR); \ elif [ "$(PLATFORM)" = "ios" ]; then \ $(FLUTTER) build ipa --flavor $(FLAVOR); \ fi mobile-staff-install: @echo "--> Installing Flutter dependencies for staff app..." @cd mobile-apps/staff-app && \ $(FLUTTER) pub get && \ $(FLUTTER) pub run build_runner build --delete-conflicting-outputs mobile-staff-dev: @echo "--> Running staff app in development mode..." @echo "--> If using VS code, use the debug configurations" @cd mobile-apps/staff-app && $(FLUTTER) run --flavor development -t lib/main_dev.dart mobile-staff-build: @if [ "$(ENV)" != "dev" ] && [ "$(ENV)" != "staging" ] && [ "$(ENV)" != "prod" ]; then \ echo "ERROR: ENV must be one of dev, staging, or prod."; exit 1; \ fi @if [ "$(PLATFORM)" != "android" ] && [ "$(PLATFORM)" != "ios" ]; then \ echo "ERROR: PLATFORM must be either android or ios."; exit 1; \ fi @echo "--> Building staff app for $(PLATFORM) with flavor $(FLAVOR)..." @cd mobile-apps/staff-app && \ $(FLUTTER) pub get && \ $(FLUTTER) pub run build_runner build --delete-conflicting-outputs && \ if [ "$(PLATFORM)" = "android" ]; then \ $(FLUTTER) build appbundle --flavor $(FLAVOR); \ elif [ "$(PLATFORM)" = "ios" ]; then \ $(FLUTTER) build ipa --flavor $(FLAVOR); \ fi