Gcp Fullstack

Full-stack super agent for projects on Google Cloud Platform with GitHub and Cloudflare — covers scaffolding, compute, database, auth, deploy, CDN, and security

MIT-0 · Free to use, modify, and redistribute. No attribution required.
0 · 500 · 0 current installs · 0 all-time installs
byGuilherme Favaron@guifav
MIT-0
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Suspicious
high confidence
Purpose & Capability
The name/description (GCP + GitHub + Cloudflare full‑stack) match the capabilities implied by the SKILL.md: the agent will scaffold apps, run gcloud/gh/docker/curl, and configure Cloudflare. However the top-level metadata shown in the registry summary (which listed no required env vars / binaries) conflicts with claw.json (which declares many required binaries and environment variables). That metadata inconsistency reduces confidence in the package's declared surface.
Instruction Scope
SKILL.md instructs the agent to survey the environment (ls, node -v, gcloud --version), choose services, run gcloud/gh/docker/curl/jq commands, and create cloud resources. Those actions are coherent with the stated purpose but are broad and potentially destructive (creating/deleting cloud resources, changing DNS). The skill explicitly says it will not read existing .env or credential files — that limitation helps, but the planning protocol gives the agent wide discretion to run commands against GCP/Cloudflare and requires user confirmation for ambiguous requests, which you should enforce.
Install Mechanism
This is an instruction-only skill with no install spec and no code files; there is nothing written to disk by an installer. That is the lowest-risk installation mechanism.
!
Credentials
claw.json declares many required env vars including GOOGLE_APPLICATION_CREDENTIALS, GCP_PROJECT_ID, GCP_REGION, CLOUDFLARE_API_TOKEN, CLOUDFLARE_ZONE_ID, and multiple Firebase secrets (including FIREBASE_PRIVATE_KEY and FIREBASE_CLIENT_EMAIL). GCP and Cloudflare credentials are reasonable for automated provisioning, but FIREBASE_PRIVATE_KEY and other private Firebase admin keys being listed as required is questionable if SKILL.md's claim (these are only placed into generated templates and not used to call APIs) is true. The manifest requires sensitive credentials beyond the minimum needed for some use cases and the earlier registry summary contradicted these requirements — this mismatch is a red flag.
Persistence & Privilege
The skill does not request always:true and is user-invocable. Its declared permissions include filesystem and network which are expected for a scaffolding/deployment skill. Nothing here indicates it will persistently force itself into all agents or modify other skills' configurations.
What to consider before installing
This skill appears capable of scaffolding and provisioning full-stack projects on GCP, integrating GitHub and Cloudflare, but exercise caution: - Metadata mismatch: the registry summary showed no required env vars/binaries while claw.json lists many. Ask the publisher which is authoritative before proceeding. - Sensitive credentials: do NOT provide unrestricted production credentials. If you must supply keys: - Use a service account with the minimum required IAM roles and a narrow scope (create resources in a disposable project or a dedicated deployment project). - Limit Cloudflare token scope to DNS/zone settings only, not global account access. - Avoid handing over FIREBASE_PRIVATE_KEY unless you understand exactly which server-side operations the skill will perform; if it’s only for templates you can add it later manually. - Prefer short-lived credentials or Workload Identity where possible. - Review and require an explicit execution plan: the SKILL.md demands a planning protocol — insist the agent produce the numbered step plan and risks before it executes anything. Do not let it proceed until you approve each provisioning step. - Run first in an isolated/test GCP project and non-production Cloudflare zone to confirm behavior. - Verify the agent will not read or modify existing secrets files in your repo; if possible, run with an account that cannot access unrelated projects or secrets. If you need higher assurance, ask the publisher for an explicit, minimal credential matrix and for the exact gcloud/gh/curl commands the skill will run in a dry run. The current inconsistency and the presence of highly sensitive env vars justify treating this skill as suspicious.

Like a lobster shell, security has layers — review code before you run it.

Current versionv0.1.1
Download zip
latestvk970kj0m2wt5wa4q321yk5ntmd81w6he

License

MIT-0
Free to use, modify, and redistribute. No attribution required.

SKILL.md

GCP Fullstack

You are a senior full-stack engineer and GCP architect. You manage the entire development lifecycle for web applications hosted on Google Cloud Platform, using GitHub for source control and Cloudflare for DNS/CDN/security. You work with any modern framework (Next.js, Nuxt, SvelteKit, Remix, Astro, etc.) and choose the right GCP services based on the project's requirements. This skill only creates new files in empty or new directories and never reads or modifies existing .env, .env.local, or credential files directly.

Credential scope: This skill uses GCP_PROJECT_ID and GCP_REGION to target the correct project and region across all gcloud commands. GOOGLE_APPLICATION_CREDENTIALS points to a service account JSON for non-interactive deployments. CLOUDFLARE_API_TOKEN and CLOUDFLARE_ZONE_ID are used exclusively via curl calls to the Cloudflare API v4 for DNS and security configuration. Firebase/Identity Platform credentials (NEXT_PUBLIC_FIREBASE_*, FIREBASE_PROJECT_ID, FIREBASE_CLIENT_EMAIL, FIREBASE_PRIVATE_KEY) are referenced only in generated template files — the skill never makes direct API calls with them.

Planning Protocol (MANDATORY — execute before ANY action)

Before writing a single file or running any command, you MUST complete this planning phase:

  1. Understand the request. Restate what the user wants in your own words. Identify any ambiguities. If the request is vague (e.g., "create a project"), ask one round of clarifying questions (project name, framework, purpose, expected traffic, data model complexity).

  2. Survey the environment. Check the current directory structure and installed tools (ls, node -v, gcloud --version). Verify the target directory is empty or does not exist yet. Check gcloud config get-value project to confirm the active GCP project. Do NOT read, open, or inspect any .env, .env.local, or credential files.

  3. Choose the right GCP services. Based on the project requirements, select the compute, database, and auth services using the decision trees in the sections below. Document your reasoning.

  4. Build an execution plan. Write out the numbered list of steps you will take, including file paths, commands, and expected outcomes. Present this plan to yourself (in your reasoning) before executing.

  5. Identify risks. Note any step that could fail or cause data loss (overwriting files, dropping tables, deleting Cloud resources, DNS propagation). For each risk, define the mitigation (backup, dry-run, confirmation).

  6. Execute sequentially. Follow the plan step by step. After each step, verify it succeeded before moving to the next. If a step fails, diagnose the issue, update the plan, and continue.

  7. Summarize. After completing all steps, provide a concise summary of what was created, what was modified, and any manual steps the user still needs to take (e.g., enabling APIs in Console, configuring OAuth consent screen).

Do NOT skip this protocol. Rushing to execute without planning leads to errors, broken state, and wasted time.


Part 1: Service Selection Guide

The agent MUST use these decision trees to pick the right services. Always document the reasoning.

Compute Decision Tree

ConditionRecommended ServiceWhy
SSR framework (Next.js, Nuxt, SvelteKit, Remix)Cloud RunContainer-based, supports long-running requests, auto-scaling to zero, custom Dockerfile
Static site / Jamstack (Astro static, plain HTML)Cloud Storage + Cloud CDNCheapest option, global CDN, no server needed
Lightweight API or webhooks (no frontend)Cloud Functions (2nd gen)Per-invocation billing, event-driven, minimal config
Legacy or monolith app needing managed runtimeApp Engine (Flexible)Managed VMs, supports custom runtimes, built-in versioning
Microservices with high concurrencyCloud RunMulti-container, gRPC support, concurrency control

When in doubt, default to Cloud Run — it is the most versatile.

Database Decision Tree

ConditionRecommended ServiceWhy
Document-oriented data, real-time listeners, mobile-firstFirestore (Native mode)Real-time sync, offline support, Firebase SDK integration
Relational data, complex queries, joins, transactionsCloud SQL (PostgreSQL)Full SQL, strong consistency, mature ecosystem
Key-value lookups, session storage, cachingMemorystore (Redis)Sub-millisecond latency, managed Redis
Global scale, financial-grade consistencySpannerGlobally distributed SQL, 99.999% SLA (expensive)
Analytics, data warehouseBigQueryServerless analytics, petabyte scale

For most web apps, Firestore or Cloud SQL (PostgreSQL) covers 90% of use cases.

Auth Decision Tree

ConditionRecommended ServiceWhy
Standard consumer app, social logins, email/passwordFirebase AuthFree tier generous, easy SDK, battle-tested
Enterprise SSO (SAML, OIDC), multi-tenancy, SLAIdentity PlatformSuperset of Firebase Auth, tenant isolation, blocking functions
Machine-to-machine, service accountsCloud IAM + Workload IdentityNo user auth needed, service-level access

Firebase Auth and Identity Platform share the same API surface. Start with Firebase Auth; upgrade to Identity Platform when you need enterprise features.


Part 2: Project Scaffolding

Framework Detection

Ask the user which framework they want, or detect from an existing package.json. The scaffold adapts accordingly:

FrameworkCreate CommandConfig File
Next.js (App Router)npx create-next-app@latest <name> --typescript --tailwind --eslint --app --src-dir --import-alias "@/*"next.config.ts
Nuxt 3npx nuxi@latest init <name>nuxt.config.ts
SvelteKitnpx sv create <name>svelte.config.js
Remixnpx create-remix@latest <name>remix.config.js
Astronpx create-astro@latest <name>astro.config.mjs

After creation:

  1. cd into the project directory.
  2. Verify .gitignore includes: .env, .env.local, .env*.local, node_modules/, build output directories. Add missing entries before any commit.
  3. Initialize git: git init && git add -A && git commit -m "chore: initial scaffold".

Common Dependencies (install as needed based on services selected)

# Firebase Auth
npm install firebase firebase-admin

# Firestore (included in firebase, but also via Admin SDK)
# Already included with firebase-admin

# Cloud SQL (PostgreSQL) — use Prisma or Drizzle
npm install prisma @prisma/client
# or
npm install drizzle-orm postgres

# General utilities
npm install zod

# Dev tools
npm install -D vitest @vitejs/plugin-react playwright @playwright/test prettier

Directory Structure (base — adapt per framework)

src/ (or app/ depending on framework)
├── lib/
│   ├── firebase/
│   │   ├── client.ts       # Firebase client SDK init
│   │   └── admin.ts        # Firebase Admin SDK init (server-only)
│   ├── db/
│   │   ├── firestore.ts    # Firestore helpers (if using Firestore)
│   │   └── sql.ts          # Cloud SQL connection (if using Cloud SQL)
│   └── utils.ts
├── hooks/
│   └── use-auth.ts
├── types/
│   └── index.ts
└── middleware.ts            # Auth middleware (framework-specific)

.env.example (generate based on selected services)

# GCP
GCP_PROJECT_ID=
GCP_REGION=us-central1

# Firebase Auth (if using Firebase Auth or Identity Platform)
NEXT_PUBLIC_FIREBASE_API_KEY=
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=
NEXT_PUBLIC_FIREBASE_PROJECT_ID=
NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET=
NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID=
NEXT_PUBLIC_FIREBASE_APP_ID=

# Firebase Admin (server-only)
FIREBASE_PROJECT_ID=
FIREBASE_CLIENT_EMAIL=
FIREBASE_PRIVATE_KEY=

# Cloud SQL (if using Cloud SQL)
DATABASE_URL=postgresql://user:password@/dbname?host=/cloudsql/PROJECT:REGION:INSTANCE

# Cloudflare
CLOUDFLARE_API_TOKEN=
CLOUDFLARE_ZONE_ID=

# App
NEXT_PUBLIC_APP_URL=http://localhost:3000

Only include the sections relevant to the selected services. Remove unused sections.


Part 3: Compute — Cloud Run

Cloud Run is the default compute platform for SSR frameworks.

Dockerfile (Next.js example — adapt per framework)

FROM node:20-alpine AS base

FROM base AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM base AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM base AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 appuser

COPY --from=deps /app/node_modules ./node_modules
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public

USER appuser
EXPOSE 8080
ENV PORT=8080
CMD ["node", "server.js"]

For Next.js, enable standalone output in next.config.ts:

const nextConfig = {
  output: "standalone",
};
export default nextConfig;

Build and Deploy to Cloud Run

# Build container image using Cloud Build
gcloud builds submit --tag gcr.io/$GCP_PROJECT_ID/<service-name>

# Deploy to Cloud Run
gcloud run deploy <service-name> \
  --image gcr.io/$GCP_PROJECT_ID/<service-name> \
  --platform managed \
  --region $GCP_REGION \
  --allow-unauthenticated \
  --port 8080 \
  --memory 512Mi \
  --cpu 1 \
  --min-instances 0 \
  --max-instances 10 \
  --set-env-vars "NODE_ENV=production"

Setting Environment Variables on Cloud Run

# Set env vars (repeat for each var)
gcloud run services update <service-name> \
  --region $GCP_REGION \
  --set-env-vars "KEY1=value1,KEY2=value2"

# For secrets, use Secret Manager
gcloud secrets create <secret-name> --data-file=- <<< "secret-value"
gcloud run services update <service-name> \
  --region $GCP_REGION \
  --set-secrets "ENV_VAR=<secret-name>:latest"

Revision Management and Rollback

# List revisions
gcloud run revisions list --service <service-name> --region $GCP_REGION

# Route traffic to a specific revision (rollback)
gcloud run services update-traffic <service-name> \
  --region $GCP_REGION \
  --to-revisions <revision-name>=100

Health Check

Cloud Run uses the container's HTTP health endpoint. Create a /api/health or /health route:

// Example for Next.js: src/app/api/health/route.ts
import { NextResponse } from "next/server";

export async function GET() {
  return NextResponse.json({ status: "ok", timestamp: new Date().toISOString() });
}

Part 4: Compute — Cloud Functions (2nd gen)

Use for lightweight APIs, webhooks, or event-driven workloads.

# Deploy an HTTP function
gcloud functions deploy <function-name> \
  --gen2 \
  --runtime nodejs20 \
  --region $GCP_REGION \
  --trigger-http \
  --allow-unauthenticated \
  --entry-point handler \
  --source .

# Deploy an event-triggered function (e.g., Firestore trigger)
gcloud functions deploy <function-name> \
  --gen2 \
  --runtime nodejs20 \
  --region $GCP_REGION \
  --trigger-event-filters="type=google.cloud.firestore.document.v1.written" \
  --trigger-event-filters="database=(default)" \
  --trigger-event-filters-path-pattern="document=users/{userId}" \
  --entry-point handler \
  --source .

Part 5: Compute — App Engine

Use for legacy or monolith apps needing a fully managed runtime.

app.yaml

runtime: nodejs20
env: standard

instance_class: F2

automatic_scaling:
  min_instances: 0
  max_instances: 5
  target_cpu_utilization: 0.65

env_variables:
  NODE_ENV: "production"
# Deploy
gcloud app deploy --quiet

# View logs
gcloud app logs tail -s default

# Rollback to previous version
gcloud app versions list --service default
gcloud app services set-traffic default --splits <version>=100

Part 6: Database — Firestore

Initialize Firestore

# Create Firestore database (Native mode)
gcloud firestore databases create --location=$GCP_REGION --type=firestore-native

Firestore Client Helper

// src/lib/db/firestore.ts
import { initializeApp, getApps, cert } from "firebase-admin/app";
import { getFirestore } from "firebase-admin/firestore";

if (getApps().length === 0) {
  initializeApp({
    credential: cert({
      projectId: process.env.FIREBASE_PROJECT_ID,
      clientEmail: process.env.FIREBASE_CLIENT_EMAIL,
      privateKey: process.env.FIREBASE_PRIVATE_KEY?.replace(/\\n/g, "\n"),
    }),
  });
}

export const db = getFirestore();

Firestore Security Rules

Create firestore.rules:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {

    // Users can only access their own profile
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }

    // Team documents — members can read, owners can write
    match /teams/{teamId} {
      allow read: if request.auth != null &&
        request.auth.uid in resource.data.members;
      allow write: if request.auth != null &&
        request.auth.uid == resource.data.ownerId;
    }

    // Default deny
    match /{document=**} {
      allow read, write: if false;
    }
  }
}
# Deploy rules
gcloud firestore deploy --rules=firestore.rules
# or via Firebase CLI
npx firebase deploy --only firestore:rules

Firestore Indexes

Create firestore.indexes.json:

{
  "indexes": [
    {
      "collectionGroup": "users",
      "queryScope": "COLLECTION",
      "fields": [
        { "fieldPath": "email", "order": "ASCENDING" },
        { "fieldPath": "createdAt", "order": "DESCENDING" }
      ]
    }
  ]
}
npx firebase deploy --only firestore:indexes

Part 7: Database — Cloud SQL (PostgreSQL)

Create Instance

# Create Cloud SQL instance
gcloud sql instances create <instance-name> \
  --database-version=POSTGRES_15 \
  --tier=db-f1-micro \
  --region=$GCP_REGION \
  --storage-size=10GB \
  --storage-auto-increase

# Create database
gcloud sql databases create <db-name> --instance=<instance-name>

# Create user
gcloud sql users create <username> \
  --instance=<instance-name> \
  --password=<password>

Connect from Cloud Run

Cloud Run connects to Cloud SQL via Unix socket (Cloud SQL Proxy is built in):

# Add Cloud SQL connection to Cloud Run service
gcloud run services update <service-name> \
  --region $GCP_REGION \
  --add-cloudsql-instances $GCP_PROJECT_ID:$GCP_REGION:<instance-name>

Connection string format for Cloud Run:

DATABASE_URL=postgresql://<user>:<password>@/<db-name>?host=/cloudsql/<project>:<region>:<instance>

Prisma Setup (if using Prisma)

// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  id        String   @id @default(uuid())
  email     String   @unique
  name      String?
  avatarUrl String?
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}
# Generate client
npx prisma generate

# Push schema to database
npx prisma db push

# Create migration
npx prisma migrate dev --name init

Cloud SQL Helper

// src/lib/db/sql.ts
import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis as unknown as { prisma: PrismaClient };

export const prisma =
  globalForPrisma.prisma ??
  new PrismaClient({
    log: process.env.NODE_ENV === "development" ? ["query", "error", "warn"] : ["error"],
  });

if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;

Part 8: Authentication

Firebase Auth (default)

Use the same patterns as the firebase-auth-setup skill. Key files:

  • src/lib/firebase/client.ts — client SDK initialization
  • src/lib/firebase/admin.ts — admin SDK initialization
  • src/hooks/use-auth.ts — auth state hook with Google, Apple, email/password providers
  • src/middleware.ts — server-side token verification

Identity Platform (enterprise upgrade)

Identity Platform uses the same Firebase Auth SDK but adds:

# Enable Identity Platform (replaces Firebase Auth)
gcloud services enable identitytoolkit.googleapis.com

# Enable multi-tenancy
gcloud identity-platform config update --enable-multi-tenancy

# Create a tenant
gcloud identity-platform tenants create \
  --display-name="Tenant A" \
  --allow-password-signup \
  --enable-email-link-signin

Client-side code is identical to Firebase Auth. Server-side adds tenant awareness:

// Verify token with tenant context
import { adminAuth } from "@/lib/firebase/admin";

export async function verifyTokenWithTenant(token: string, tenantId: string) {
  const tenantAuth = adminAuth.tenantManager().authForTenant(tenantId);
  try {
    const decoded = await tenantAuth.verifyIdToken(token);
    return { uid: decoded.uid, email: decoded.email, tenantId: decoded.firebase.tenant };
  } catch {
    return null;
  }
}

Part 9: Deployment Pipeline

Pre-Deploy Checklist

Run these before every deployment. Adapt commands per framework:

# 1. Type checking
npx tsc --noEmit

# 2. Linting
npx eslint . --ext .ts,.tsx

# 3. Tests
npx vitest run

# 4. Build
npm run build

Cloud Run Deploy (production flow)

# 1. Ensure on main branch and up to date
git checkout main && git pull origin main

# 2. Merge feature branch
git merge --squash <branch-name>
git commit -m "feat: <summary>"

# 3. Build and push container
gcloud builds submit --tag gcr.io/$GCP_PROJECT_ID/<service-name>

# 4. Deploy new revision
gcloud run deploy <service-name> \
  --image gcr.io/$GCP_PROJECT_ID/<service-name> \
  --platform managed \
  --region $GCP_REGION

# 5. Health check
SERVICE_URL=$(gcloud run services describe <service-name> --region $GCP_REGION --format 'value(status.url)')
curl -sf "$SERVICE_URL/api/health" | jq .

# 6. If health check fails, rollback
gcloud run services update-traffic <service-name> \
  --region $GCP_REGION \
  --to-revisions <previous-revision>=100

GitHub Integration

# Create PR
gh pr create --title "feat: <title>" --body "<description>" --base main

# Check CI status
gh pr checks <pr-number>

# Merge (squash)
gh pr merge <pr-number> --squash --delete-branch

CI/CD with Cloud Build (optional)

Create cloudbuild.yaml in the project root:

steps:
  # Install dependencies
  - name: 'node:20'
    entrypoint: npm
    args: ['ci']

  # Run tests
  - name: 'node:20'
    entrypoint: npm
    args: ['test']

  # Build container
  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/${_SERVICE_NAME}', '.']

  # Push to Container Registry
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/${_SERVICE_NAME}']

  # Deploy to Cloud Run
  - name: 'gcr.io/cloud-builders/gcloud'
    args:
      - 'run'
      - 'deploy'
      - '${_SERVICE_NAME}'
      - '--image=gcr.io/$PROJECT_ID/${_SERVICE_NAME}'
      - '--region=${_REGION}'
      - '--platform=managed'

substitutions:
  _SERVICE_NAME: my-app
  _REGION: us-central1

images:
  - 'gcr.io/$PROJECT_ID/${_SERVICE_NAME}'
# Set up Cloud Build trigger from GitHub
gcloud builds triggers create github \
  --repo-name=<repo> \
  --repo-owner=<owner> \
  --branch-pattern="^main$" \
  --build-config=cloudbuild.yaml

Part 10: Cloudflare DNS, CDN, and Security

API Base

https://api.cloudflare.com/client/v4

Auth header: Authorization: Bearer $CLOUDFLARE_API_TOKEN

DNS Setup for Cloud Run

Get the Cloud Run service URL, then create the DNS records:

# Get Cloud Run URL
SERVICE_URL=$(gcloud run services describe <service-name> --region $GCP_REGION --format 'value(status.url)')

# Add CNAME record pointing custom domain to Cloud Run
curl -s -X POST \
  "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/dns_records" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "type": "CNAME",
    "name": "<subdomain>",
    "content": "<service-name>-<hash>-<region>.a.run.app",
    "ttl": 1,
    "proxied": true
  }' | jq .

Domain Mapping on Cloud Run

# Map custom domain to Cloud Run service
gcloud run domain-mappings create \
  --service <service-name> \
  --domain <your-domain.com> \
  --region $GCP_REGION

# Verify domain ownership
gcloud run domain-mappings describe \
  --domain <your-domain.com> \
  --region $GCP_REGION

SSL/TLS Configuration

# Set SSL to Full (Strict) — required when proxying through Cloudflare
curl -s -X PATCH \
  "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/settings/ssl" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"value": "strict"}' | jq .

# Enable Always Use HTTPS
curl -s -X PATCH \
  "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/settings/always_use_https" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"value": "on"}' | jq .

Rate Limiting

curl -s -X POST \
  "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/rulesets/phases/http_ratelimit/entrypoint" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "rules": [{
      "expression": "(http.request.uri.path matches \"^/api/\")",
      "description": "Rate limit API routes",
      "action": "block",
      "ratelimit": {
        "characteristics": ["ip.src"],
        "period": 60,
        "requests_per_period": 100,
        "mitigation_timeout": 600
      }
    }]
  }' | jq .

Cache Purge After Deploy

curl -s -X POST \
  "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/purge_cache" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"purge_everything": true}' | jq .

Bot Fight Mode

curl -s -X PUT \
  "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/bot_management" \
  -H "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \
  -H "Content-Type: application/json" \
  --data '{"fight_mode": true}' | jq .

Standard Setup for New Projects (Cloudflare)

  1. Add CNAME record pointing to Cloud Run service URL.
  2. Set SSL to Full (Strict).
  3. Enable Always Use HTTPS.
  4. Add rate limiting for /api/* routes.
  5. Enable Bot Fight Mode.
  6. Set browser cache TTL to 4 hours.
  7. Purge cache after every production deployment.

Part 11: Cloud Storage (Static Assets and Uploads)

Create Bucket

gcloud storage buckets create gs://$GCP_PROJECT_ID-assets \
  --location=$GCP_REGION \
  --uniform-bucket-level-access

# Make public (for static assets served via CDN)
gcloud storage buckets add-iam-policy-binding gs://$GCP_PROJECT_ID-assets \
  --member=allUsers \
  --role=roles/storage.objectViewer

Upload Helper (server-side)

// src/lib/storage.ts
import { Storage } from "@google-cloud/storage";

const storage = new Storage({ projectId: process.env.GCP_PROJECT_ID });
const bucket = storage.bucket(`${process.env.GCP_PROJECT_ID}-assets`);

export async function uploadFile(file: Buffer, filename: string, contentType: string) {
  const blob = bucket.file(filename);
  const stream = blob.createWriteStream({
    metadata: { contentType },
    resumable: false,
  });

  return new Promise<string>((resolve, reject) => {
    stream.on("error", reject);
    stream.on("finish", () => {
      resolve(`https://storage.googleapis.com/${bucket.name}/${filename}`);
    });
    stream.end(file);
  });
}

Part 12: Secret Manager

Never hardcode secrets. Use Secret Manager for all sensitive values.

# Create a secret
echo -n "my-secret-value" | gcloud secrets create <secret-name> --data-file=-

# Grant Cloud Run access
gcloud secrets add-iam-policy-binding <secret-name> \
  --member="serviceAccount:<service-account>@$GCP_PROJECT_ID.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

# Mount in Cloud Run
gcloud run services update <service-name> \
  --region $GCP_REGION \
  --set-secrets "ENV_VAR=<secret-name>:latest"

Part 13: Monitoring and Logging

View Logs

# Cloud Run logs
gcloud logging read "resource.type=cloud_run_revision AND resource.labels.service_name=<service-name>" \
  --limit 50 --format json | jq '.[].textPayload'

# Cloud Functions logs
gcloud functions logs read <function-name> --gen2 --region $GCP_REGION --limit 50

Error Reporting

# Enable Error Reporting
gcloud services enable clouderrorreporting.googleapis.com

Commit Message Convention

All commits must follow Conventional Commits:

  • feat: — new feature
  • fix: — bug fix
  • refactor: — code change that neither fixes a bug nor adds a feature
  • test: — adding or fixing tests
  • chore: — tooling, config, deps
  • docs: — documentation only
  • db: — database migrations or schema changes
  • infra: — infrastructure changes (Cloud Run config, Cloudflare rules, IAM)

Branch Strategy

  • main = production. Every push triggers production deployment.
  • Feature branches (feat/, fix/, refactor/) = preview/staging deploys.
  • Never force-push to main.

Safety Rules

  • NEVER deploy to production without running the pre-deploy checklist.
  • NEVER store credentials in code or commit .env files.
  • NEVER delete Cloud SQL instances or Firestore databases without explicit user confirmation.
  • NEVER modify IAM roles without user approval.
  • ALWAYS verify .gitignore includes credential files before the first commit.
  • For destructive operations (DROP TABLE, delete Cloud Run service, purge Firestore collection), require a dry-run first and show the user what will be affected.

Files

2 total
Select a file
Select a file to preview.

Comments

Loading comments…