# Cloud Build Environment Configuration

This guide explains how to set up separate staging and production triggers with environment-specific configurations.

## Overview

The `cloudbuild.yaml` uses substitution variables to make it environment-agnostic. You'll create **two separate triggers** (one for staging, one for production) with different substitution variable values.

**Note**: The Dockerfile uses a single final stage. Environment differentiation (staging vs production) is handled entirely through Cloud Run environment variables, not at build time. This simplifies the build process - the same Docker image can be used for both environments.

## Architecture

```
┌─────────────────┐      ┌──────────────────────┐
│  Git Branch     │      │  Cloud Build Trigger │
│  - main         │─────▶│  (Production)        │
│                 │      │  Variables: prod     │
└─────────────────┘      └──────────────────────┘

┌─────────────────┐      ┌──────────────────────┐
│  Git Branch     │      │  Cloud Build Trigger │
│  - develop      │─────▶│  (Staging)           │
│                 │      │  Variables: staging  │
└─────────────────┘      └──────────────────────┘
```

## Required Substitution Variables

### Common Variables (Different per Environment)

| Variable                | Production Value         | Staging Value                |
| ----------------------- | ------------------------ | ---------------------------- |
| `$_NODE_ENV`            | `production`             | `staging`                    |
| `$_SERVICE_NAME`        | `xtablo-api`             | `xtablo-api-staging`         |
| `$_SUPABASE_URL`        | Production Supabase URL  | Staging Supabase URL         |
| `$_STREAM_CHAT_API_KEY` | Production key           | Staging key                  |
| `$_EMAIL_USER`          | `noreply@xtablo.com`     | `staging@xtablo.com`         |
| `$_EMAIL_CLIENT_ID`     | Production OAuth client  | Staging OAuth client         |
| `$_R2_ACCOUNT_ID`       | Production R2 account    | Staging R2 account           |
| `$_CORS_ORIGIN`         | `https://app.xtablo.com` | `https://staging.xtablo.com` |
| `$_XTABLO_URL`          | `https://app.xtablo.com` | `https://staging.xtablo.com` |
| `$_LOG_LEVEL`           | `info`                   | `debug`                      |

### Build Configuration (Same for Both)

| Variable          | Value                              |
| ----------------- | ---------------------------------- |
| `$_AR_PROJECT_ID` | Your GCP project ID                |
| `$_AR_REPOSITORY` | `xtablo` (or your repository name) |

### Secret Manager References (Different per Environment)

Each environment should have its own secrets in Secret Manager:

| Variable                              | Production Secret Name            | Staging Secret Name                  |
| ------------------------------------- | --------------------------------- | ------------------------------------ |
| `$_SUPABASE_SERVICE_ROLE_KEY_SECRET`  | `supabase-service-role-key-prod`  | `supabase-service-role-key-staging`  |
| `$_SUPABASE_CONNECTION_STRING_SECRET` | `supabase-connection-string-prod` | `supabase-connection-string-staging` |
| `$_SUPABASE_CA_CERT_SECRET`           | `supabase-ca-cert-prod`           | `supabase-ca-cert-staging`           |
| `$_STREAM_CHAT_API_SECRET_SECRET`     | `stream-chat-api-secret-prod`     | `stream-chat-api-secret-staging`     |
| `$_STRIPE_SECRET_KEY_SECRET`          | `stripe-secret-key-prod`          | `stripe-secret-key-staging`          |
| `$_STRIPE_WEBHOOK_SECRET_SECRET`      | `stripe-webhook-secret-prod`      | `stripe-webhook-secret-staging`      |
| `$_EMAIL_CLIENT_SECRET_SECRET`        | `email-client-secret-prod`        | `email-client-secret-staging`        |
| `$_EMAIL_REFRESH_TOKEN_SECRET`        | `email-refresh-token-prod`        | `email-refresh-token-staging`        |
| `$_R2_ACCESS_KEY_ID_SECRET`           | `r2-access-key-id-prod`           | `r2-access-key-id-staging`           |
| `$_R2_SECRET_ACCESS_KEY_SECRET`       | `r2-secret-access-key-prod`       | `r2-secret-access-key-staging`       |

## Setup Instructions

### Step 1: Create Secrets in Secret Manager

#### Production Secrets

```bash
# Supabase (Production)
echo -n "prod-service-role-key" | gcloud secrets create supabase-service-role-key-prod --data-file=-
echo -n "prod-connection-string" | gcloud secrets create supabase-connection-string-prod --data-file=-
echo -n "prod-ca-cert" | gcloud secrets create supabase-ca-cert-prod --data-file=-

# Stream Chat (Production)
echo -n "prod-stream-secret" | gcloud secrets create stream-chat-api-secret-prod --data-file=-

# Stripe (Production)
echo -n "prod-stripe-key" | gcloud secrets create stripe-secret-key-prod --data-file=-
echo -n "prod-webhook-secret" | gcloud secrets create stripe-webhook-secret-prod --data-file=-

# Email (Production)
echo -n "prod-client-secret" | gcloud secrets create email-client-secret-prod --data-file=-
echo -n "prod-refresh-token" | gcloud secrets create email-refresh-token-prod --data-file=-

# R2 (Production)
echo -n "prod-access-key-id" | gcloud secrets create r2-access-key-id-prod --data-file=-
echo -n "prod-secret-access-key" | gcloud secrets create r2-secret-access-key-prod --data-file=-
```

#### Staging Secrets

```bash
# Supabase (Staging)
echo -n "staging-service-role-key" | gcloud secrets create supabase-service-role-key-staging --data-file=-
echo -n "staging-connection-string" | gcloud secrets create supabase-connection-string-staging --data-file=-
echo -n "staging-ca-cert" | gcloud secrets create supabase-ca-cert-staging --data-file=-

# Stream Chat (Staging)
echo -n "staging-stream-secret" | gcloud secrets create stream-chat-api-secret-staging --data-file=-

# Stripe (Staging - use test keys)
echo -n "staging-stripe-key" | gcloud secrets create stripe-secret-key-staging --data-file=-
echo -n "staging-webhook-secret" | gcloud secrets create stripe-webhook-secret-staging --data-file=-

# Email (Staging)
echo -n "staging-client-secret" | gcloud secrets create email-client-secret-staging --data-file=-
echo -n "staging-refresh-token" | gcloud secrets create email-refresh-token-staging --data-file=-

# R2 (Staging)
echo -n "staging-access-key-id" | gcloud secrets create r2-access-key-id-staging --data-file=-
echo -n "staging-secret-access-key" | gcloud secrets create r2-secret-access-key-staging --data-file=-
```

### Step 2: Grant Access to Secrets

```bash
PROJECT_ID="your-project-id"
SERVICE_ACCOUNT="${PROJECT_ID}@appspot.gserviceaccount.com"

# Grant access to all production secrets
for secret in \
  supabase-service-role-key-prod \
  supabase-connection-string-prod \
  supabase-ca-cert-prod \
  stream-chat-api-secret-prod \
  stripe-secret-key-prod \
  stripe-webhook-secret-prod \
  email-client-secret-prod \
  email-refresh-token-prod \
  r2-access-key-id-prod \
  r2-secret-access-key-prod
do
  gcloud secrets add-iam-policy-binding $secret \
    --member="serviceAccount:${SERVICE_ACCOUNT}" \
    --role="roles/secretmanager.secretAccessor"
done

# Grant access to all staging secrets
for secret in \
  supabase-service-role-key-staging \
  supabase-connection-string-staging \
  supabase-ca-cert-staging \
  stream-chat-api-secret-staging \
  stripe-secret-key-staging \
  stripe-webhook-secret-staging \
  email-client-secret-staging \
  email-refresh-token-staging \
  r2-access-key-id-staging \
  r2-secret-access-key-staging
do
  gcloud secrets add-iam-policy-binding $secret \
    --member="serviceAccount:${SERVICE_ACCOUNT}" \
    --role="roles/secretmanager.secretAccessor"
done
```

### Step 3: Create Cloud Build Triggers

#### Production Trigger

Via gcloud CLI:

```bash
gcloud builds triggers create github \
  --name="xtablo-api-production" \
  --repo-name="xtablo-source" \
  --repo-owner="your-github-org" \
  --branch-pattern="^main$" \
  --build-config="apps/api/cloudbuild.yaml" \
  --substitutions='
_NODE_ENV=production,
_SERVICE_NAME=xtablo-api,
_AR_PROJECT_ID=your-project-id,
_AR_REPOSITORY=xtablo,
_SUPABASE_URL=https://your-prod-project.supabase.co,
_STREAM_CHAT_API_KEY=your-prod-stream-key,
_EMAIL_USER=noreply@xtablo.com,
_EMAIL_CLIENT_ID=your-prod-oauth-client-id,
_R2_ACCOUNT_ID=your-prod-r2-account,
_CORS_ORIGIN=https://app.xtablo.com,
_XTABLO_URL=https://app.xtablo.com,
_LOG_LEVEL=info,
_SUPABASE_SERVICE_ROLE_KEY_SECRET=supabase-service-role-key-prod,
_SUPABASE_CONNECTION_STRING_SECRET=supabase-connection-string-prod,
_SUPABASE_CA_CERT_SECRET=supabase-ca-cert-prod,
_STREAM_CHAT_API_SECRET_SECRET=stream-chat-api-secret-prod,
_STRIPE_SECRET_KEY_SECRET=stripe-secret-key-prod,
_STRIPE_WEBHOOK_SECRET_SECRET=stripe-webhook-secret-prod,
_EMAIL_CLIENT_SECRET_SECRET=email-client-secret-prod,
_EMAIL_REFRESH_TOKEN_SECRET=email-refresh-token-prod,
_R2_ACCESS_KEY_ID_SECRET=r2-access-key-id-prod,
_R2_SECRET_ACCESS_KEY_SECRET=r2-secret-access-key-prod
'
```

#### Staging Trigger

Via gcloud CLI:

```bash
gcloud builds triggers create github \
  --name="xtablo-api-staging" \
  --repo-name="xtablo-source" \
  --repo-owner="your-github-org" \
  --branch-pattern="^develop$" \
  --build-config="apps/api/cloudbuild.yaml" \
  --substitutions='
_NODE_ENV=staging,
_SERVICE_NAME=xtablo-api-staging,
_AR_PROJECT_ID=your-project-id,
_AR_REPOSITORY=xtablo,
_SUPABASE_URL=https://your-staging-project.supabase.co,
_STREAM_CHAT_API_KEY=your-staging-stream-key,
_EMAIL_USER=staging@xtablo.com,
_EMAIL_CLIENT_ID=your-staging-oauth-client-id,
_R2_ACCOUNT_ID=your-staging-r2-account,
_CORS_ORIGIN=https://staging.xtablo.com,
_XTABLO_URL=https://staging.xtablo.com,
_LOG_LEVEL=debug,
_SUPABASE_SERVICE_ROLE_KEY_SECRET=supabase-service-role-key-staging,
_SUPABASE_CONNECTION_STRING_SECRET=supabase-connection-string-staging,
_SUPABASE_CA_CERT_SECRET=supabase-ca-cert-staging,
_STREAM_CHAT_API_SECRET_SECRET=stream-chat-api-secret-staging,
_STRIPE_SECRET_KEY_SECRET=stripe-secret-key-staging,
_STRIPE_WEBHOOK_SECRET_SECRET=stripe-webhook-secret-staging,
_EMAIL_CLIENT_SECRET_SECRET=email-client-secret-staging,
_EMAIL_REFRESH_TOKEN_SECRET=email-refresh-token-staging,
_R2_ACCESS_KEY_ID_SECRET=r2-access-key-id-staging,
_R2_SECRET_ACCESS_KEY_SECRET=r2-secret-access-key-staging
'
```

### Step 4: Configure via Console (Alternative)

If you prefer using the Google Cloud Console:

1. Go to **Cloud Build > Triggers**
2. Click **Create Trigger**
3. Configure:

   - **Name**: `xtablo-api-production` (or `xtablo-api-staging`)
   - **Event**: Push to a branch
   - **Repository**: Your GitHub repository
   - **Branch**: `^main$` (or `^develop$` for staging)
   - **Build configuration**: Cloud Build configuration file
   - **Location**: `apps/api/cloudbuild.yaml`

4. Scroll to **Substitution variables** and add all variables from the table above

5. Save the trigger

## Verification

### Test Production Deployment

```bash
# Trigger manually
gcloud builds triggers run xtablo-api-production --branch=main

# Check logs
gcloud builds list --limit=5
gcloud builds log BUILD_ID

# Verify deployment
gcloud run services describe xtablo-api --region=europe-west1
```

### Test Staging Deployment

```bash
# Trigger manually
gcloud builds triggers run xtablo-api-staging --branch=develop

# Check logs
gcloud builds list --limit=5

# Verify deployment
gcloud run services describe xtablo-api-staging --region=europe-west1
```

### Verify Environment Variables

```bash
# Production
gcloud run services describe xtablo-api --region=europe-west1 \
  --format="value(spec.template.spec.containers[0].env)"

# Staging
gcloud run services describe xtablo-api-staging --region=europe-west1 \
  --format="value(spec.template.spec.containers[0].env)"
```

## Best Practices

1. **Secret Naming**: Use `-prod` and `-staging` suffixes for secrets
2. **Service Names**: Use different names for each environment (`xtablo-api` vs `xtablo-api-staging`)
3. **Branches**: Deploy production from `main`, staging from `develop`
4. **Stripe Keys**: Use Stripe test keys in staging
5. **Supabase**: Use separate Supabase projects for staging and production
6. **Monitoring**: Set up different alert thresholds for staging vs production
7. **Resource Limits**: You may want lower limits for staging to save costs

## Quick Reference

### Environment Comparison

| Aspect             | Production       | Staging              |
| ------------------ | ---------------- | -------------------- |
| **Branch**         | `main`           | `develop`            |
| **Service Name**   | `xtablo-api`     | `xtablo-api-staging` |
| **Domain**         | `app.xtablo.com` | `staging.xtablo.com` |
| **Log Level**      | `info`           | `debug`              |
| **Stripe**         | Live keys        | Test keys            |
| **Min Instances**  | 1 (optional)     | 0                    |
| **Secrets Suffix** | `-prod`          | `-staging`           |

## Troubleshooting

### "Secret not found" error

- Ensure secret names in substitution variables match actual secret names
- Verify secrets exist: `gcloud secrets list | grep staging` or `grep prod`

### Wrong environment variables in deployment

- Check trigger substitution variables in Cloud Build console
- Verify the correct trigger is being used for the branch

### Services pointing to wrong databases

- Ensure `SUPABASE_URL` is different for staging/production
- Check that secret names include correct environment suffix

## Example: Adding a New Environment Variable

To add a new environment variable (e.g., `FEATURE_FLAG`):

1. Add to `cloudbuild.yaml` in the `--set-env-vars` line:

   ```yaml
   "NODE_ENV=$_NODE_ENV,...,FEATURE_FLAG=$_FEATURE_FLAG"
   ```

2. Add to **both triggers** with different values:

   - Production: `_FEATURE_FLAG=false`
   - Staging: `_FEATURE_FLAG=true`

3. Update app code to read `process.env.FEATURE_FLAG`
