Deployment Guide: New GCP Project & Firebase Project
This guide walks you through deploying the Gamuda Technology Jira Tracker to a brand new GCP project with a new Firebase project.
📋 Prerequisites
Before starting, ensure you have:
- Google Cloud Platform account with billing enabled
- gcloud CLI installed (
brew install google-cloud-sdkon macOS) - Terraform installed (
brew install terraformon macOS) - Node.js >= 18.0.0 and npm >= 9.0.0
- Firebase CLI installed (
npm install -g firebase-tools) - Jira account with API access
- Bitbucket account with API access
🚀 Step-by-Step Deployment
Step 1: Configure Environment Variables
First, create your .env file from the example:
# Copy the example configuration
cp env.example .env
# Edit with your values
nano .env
Update the following values in .env:
# ============================================================================
# GCP Infrastructure Configuration (for deployment scripts)
# ============================================================================
PROJECT_ID=your-company-jira-tracker # Must be globally unique
PROJECT_NAME=Jira Tracker Production
REGION=asia-southeast1
BILLING_ACCOUNT_ID=YOUR-BILLING-ACCOUNT-ID
# Cloud Run Configuration
SERVICE_NAME=gamuda-jira-tracker
CLOUD_RUN_MEMORY=512Mi
CLOUD_RUN_CPU=1
CLOUD_RUN_TIMEOUT=300
CLOUD_RUN_MAX_INSTANCES=10
# Cloud Scheduler Configuration
SYNC_SCHEDULE=0 1 * * * # 1:00 AM daily
TIME_ZONE=Asia/Kuala_Lumpur
Also configure your Firebase, Jira, and Bitbucket credentials in the same .env file (see env.example for all options).
Share dev Firestore in prod (optional): To have dev and prod use the same Firestore (the dev one), set in .env:
- All
NEXT_PUBLIC_FIREBASE_*and Firebase secrets to your dev Firebase project values. FIRESTORE_PROJECT_ID=your-dev-firebase-project-id(e.g.gtc-chikeen-tan8f5-prj). Then deploy; the build will use dev Firebase for the client, and the server will use dev Firestore viaFIRESTORE_PROJECT_ID. Store the dev service account JSON in GCP Secret Manager asfirebase-service-accountfor the prod Cloud Run service.
Important: The .env file is in .gitignore and will not be committed to version control.
Step 2: Create New GCP Project
# Load your configuration
set -a
source .env
set +a
# Login to GCP (if not already logged in)
gcloud auth login
gcloud auth application-default login
# Create the project
gcloud projects create $PROJECT_ID --name="$PROJECT_NAME"
# Set as default project
gcloud config set project $PROJECT_ID
# Link billing account (REQUIRED for all subsequent steps)
gcloud billing projects link $PROJECT_ID --billing-account=$BILLING_ACCOUNT_ID
# Verify billing is linked
gcloud billing projects describe $PROJECT_ID
Step 2: Enable Required GCP APIs
# Enable all necessary APIs
gcloud services enable \
cloudbuild.googleapis.com \
run.googleapis.com \
secretmanager.googleapis.com \
firestore.googleapis.com \
cloudscheduler.googleapis.com \
firebase.googleapis.com \
--project=$PROJECT_ID
# Verify APIs are enabled
gcloud services list --enabled --project=$PROJECT_ID
Step 3: Create and Configure Firebase Project
3.1 Create Firebase Project (Web Console)
- Go to https://console.firebase.google.com
- Click "Add project"
- Select your existing GCP project:
$PROJECT_ID - Confirm Firebase billing plan
- Enable Google Analytics (optional)
- Click "Continue" to finish setup
3.2 Enable Firebase Authentication
- In Firebase Console, go to Authentication → Get Started
- Enable Email/Password sign-in method
- For Google SSO: enable the Google sign-in method (Authentication → Sign-in method → Google → Enable). The Velocity app shows "Sign in with Google" when
NEXT_PUBLIC_GOOGLE_SSO_ENABLEDis not set tofalse. - (Optional) Enable other providers (e.g. SAML/OIDC for company SSO — see SSO setup)
3.3 Create Firestore Database
- In Firebase Console, go to Firestore Database
- Click "Create database"
- Select Production mode
- Choose location:
asia-southeast1(or your preferred region) - Click "Enable"
3.4 Register Web App
- In Firebase Console, go to Project Settings (gear icon)
- Scroll down to "Your apps" section
- Click the Web icon (
</>) - Register app with nickname:
"Jira Tracker Web" - Copy the Firebase config - you'll need this later
- Click "Continue to console"
3.5 Generate Service Account Key
- In Firebase Console, go to Project Settings → Service accounts
- Click "Generate new private key"
- Click "Generate key" in the dialog
- Save the JSON file as
firebase-service-account.jsonin your project root - IMPORTANT: Never commit this file to Git
Step 4: Configure Firestore Rules and Indexes
# Deploy Firestore rules
firebase deploy --only firestore:rules --project=$PROJECT_ID
# Deploy Firestore indexes
firebase deploy --only firestore:indexes --project=$PROJECT_ID
Step 5: Set Up Secrets in Secret Manager
The setup script will automatically use your .env configuration. Run the setup script:
./setup-secrets.sh
The script will guide you through creating the following secrets:
Firebase Configuration:
firebase-api-key- From Firebase config (step 3.4)firebase-auth-domain- e.g.,your-project.firebaseapp.comfirebase-project-id- Your Firebase project IDfirebase-storage-bucket- e.g.,your-project.appspot.comfirebase-messaging-sender-id- From Firebase configfirebase-app-id- From Firebase configfirebase-service-account- Contents of service account JSON (step 3.5)
Jira Configuration:
jira-base-url- e.g.,https://your-company.atlassian.net/jira-username- Your Jira emailjira-api-token- Generate from: https://id.atlassian.com/manage-profile/security/api-tokens
Bitbucket Configuration:
bitbucket-username- Your Bitbucket emailbitbucket-api-token- Generate from: https://bitbucket.org/account/settings/app-passwords/bitbucket-workspace- Your Bitbucket workspace slug
Step 6: Build and Deploy Application to Cloud Run
The deployment scripts will automatically use your .env configuration:
# Make deployment scripts executable
chmod +x deploy-to-gcp.sh
chmod +x deploy-all.sh
# Deploy the application
./deploy-to-gcp.sh
This will:
- Build the Docker container
- Push to Google Container Registry
- Deploy to Cloud Run
- Configure secrets
- Output the service URL
Save the service URL - you'll need it for the next steps.
Step 7: Configure Firebase Authorized Domains
Firebase only allows sign-in from domains listed here. If you use a custom URL (e.g. velocity.internal.gamuda.app), add it or you'll get auth/unauthorized-domain.
- Go to Firebase Console → Authentication → Settings
- Scroll to Authorized domains
- Click "Add domain"
- Add each domain (without
https://), for example:- Cloud Run:
your-service-xxxxx-as.a.run.app - Custom/internal:
velocity.internal.gamuda.app
- Cloud Run:
- Click "Add" for each
Step 8: Deploy Cloud Scheduler (Auto-Sync)
9.1 Configure Terraform Variables
cd terraform
# Copy the example file
cp terraform.tfvars.example terraform.tfvars
# Edit with your values
nano terraform.tfvars
Update terraform.tfvars:
project_id = "your-new-project-id"
region = "asia-southeast1"
cloud_run_service_name = "gamuda-jira-tracker"
app_url = "https://your-service-xxxxx-as.a.run.app" # From Step 7
sync_schedule = "0 1 * * *" # 1 AM daily
time_zone = "Asia/Kuala_Lumpur"
9.2 Deploy with Terraform
# Initialize Terraform
terraform init
# Preview changes
terraform plan
# Apply configuration
terraform apply
Type yes when prompted.
This will create:
- Cloud Scheduler job (daily sync)
- Service account for scheduler
- IAM permissions
Step 9: Initial Setup and Testing
10.1 Access Your Application
Open your Cloud Run URL in a browser:
https://your-service-xxxxx-as.a.run.app
10.2 Create Admin User
- Click "Register"
- Create your admin account
- Login with your credentials
10.3 Configure Team Settings
-
Upload team configuration:
- Go to
/settings - Upload
configs/team-config.json
- Go to
-
Upload project mappings:
- Go to
/settings - Upload
configs/project-mappings.json
- Go to
10.4 Run Initial Sync
- Go to Sync Manager page
- Click "Sync All Data"
- Monitor the sync progress
- Initial sync may take 10-30 minutes depending on data volume
10.5 Test Cloud Scheduler
Manually trigger the scheduled job:
gcloud scheduler jobs run daily-jira-bitbucket-sync \
--location=$REGION \
--project=$PROJECT_ID
Check logs:
gcloud logging read "resource.type=cloud_scheduler_job" \
--limit=10 \
--project=$PROJECT_ID
Step 10: Configure Auto-Sync (Optional)
- Go to your app → Settings
- Toggle "Enable Auto-Sync" to ON
- Set sync time (e.g., 01:00)
- Click "Save Settings"
🔍 Verification Checklist
After deployment, verify:
- Application accessible via Cloud Run URL
- Firebase Authentication working
- Can register and login
- Firestore data persisting
- Manual sync completes successfully
- Dashboard displays data correctly
- Cloud Scheduler job created
- Scheduled sync triggers automatically
- Secrets properly configured
- All required APIs enabled
📊 Monitoring and Logs
View Cloud Run Logs
gcloud run services logs read $SERVICE_NAME \
--region=$REGION \
--project=$PROJECT_ID \
--limit=100
View Scheduler Logs
gcloud scheduler jobs logs $SERVICE_NAME \
--location=$REGION \
--project=$PROJECT_ID
Monitor in Console
- Cloud Run: https://console.cloud.google.com/run?project=$PROJECT_ID
- Cloud Scheduler: https://console.cloud.google.com/cloudscheduler?project=$PROJECT_ID
- Secret Manager: https://console.cloud.google.com/security/secret-manager?project=$PROJECT_ID
- Firestore: https://console.firebase.google.com/project/$PROJECT_ID/firestore
🛠️ Troubleshooting
Issue: Build fails
# Check if Cloud Build API is enabled
gcloud services list --enabled | grep cloudbuild
# View build logs
gcloud builds list --project=$PROJECT_ID
Issue: Deployment fails with permission error
# Ensure you have necessary permissions
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="user:your-email@company.com" \
--role="roles/owner"
Issue: Secrets not accessible
# Grant Cloud Run access to secrets
PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
SERVICE_ACCOUNT="${PROJECT_NUMBER}-compute@developer.gserviceaccount.com"
gcloud secrets add-iam-policy-binding SECRET_NAME \
--member="serviceAccount:${SERVICE_ACCOUNT}" \
--role="roles/secretmanager.secretAccessor" \
--project=$PROJECT_ID
Issue: Firestore permission denied
- Check Firestore rules in Firebase Console
- Ensure rules allow authenticated users to read/write
- Verify service account has Firestore permissions
Issue: Scheduler not triggering
# Check if Cloud Scheduler API is enabled
gcloud services enable cloudscheduler.googleapis.com --project=$PROJECT_ID
# Verify job exists
gcloud scheduler jobs list --location=$REGION --project=$PROJECT_ID
# Check job configuration
gcloud scheduler jobs describe daily-jira-bitbucket-sync \
--location=$REGION \
--project=$PROJECT_ID
🔐 Security Best Practices
-
Never commit secrets:
- Add
*.tfvarsto.gitignore - Add
firebase-service-account.jsonto.gitignore - Add
.env.localto.gitignore
- Add
-
Rotate credentials regularly:
- Rotate Jira API tokens every 90 days
- Rotate Bitbucket API tokens every 90 days
- Rotate Firebase service accounts annually
-
Use principle of least privilege:
- Create separate service accounts for different functions
- Grant only necessary IAM roles
- Regularly audit IAM permissions
-
Enable security features:
- Enable Cloud Armor for DDoS protection
- Set up Cloud Monitoring alerts
- Enable audit logging
-
Backup data:
- Enable Firestore backups
- Export data regularly
- Test restore procedures
📝 Post-Deployment Tasks
-
Set up monitoring:
# Create uptime check
gcloud monitoring uptime create $SERVICE_NAME-uptime \
--display-name="Jira Tracker Uptime" \
--http-check="$SERVICE_URL" \
--project=$PROJECT_ID -
Configure alerting:
- Set up alerts for failed syncs
- Monitor Cloud Run errors
- Track Firestore quota usage
-
Document your setup:
- Save project ID, region, and URLs
- Document custom configuration
- Share access with team members
-
Schedule maintenance:
- Plan for regular updates
- Test disaster recovery
- Review and optimize costs
💰 Cost Optimization
-
Cloud Run:
- Use minimum instances: 0
- Set max instances: 10
- Adjust memory based on usage
-
Firestore:
- Monitor read/write operations
- Optimize queries
- Use composite indexes
-
Cloud Scheduler:
- Free tier: 3 jobs/month
- Current setup: 1 job (within free tier)
-
Secret Manager:
- Free tier: 6 active secrets
- Current setup:
13 secrets ($0.36/month)
🎯 Next Steps
- Set up custom domain (optional)
- Configure SSL certificate (optional)
- Enable Cloud CDN (optional)
- Set up staging environment
- Configure CI/CD pipeline
- Add more team members
- Customize reports
- Integrate with other tools
📞 Support
For issues or questions:
- Check logs in GCP Console
- Review Firestore rules
- Verify Secret Manager configuration
- Contact your infrastructure team
Deployment Date: _________________
Deployed By: _________________
Project ID: _________________
Cloud Run URL: _________________
Firebase Project: _________________