Screver Market Access IQ · docs
Engineering

Deployment

Cloud Run, Cloud SQL, Secret Manager, and the hard-won learnings baked in from day one.

Targets

  • GCP project screver-market-access, region europe-west6.
  • Cloud Run services per repo, each with a -staging and a production variant.
  • Cloud SQL Postgres 17 (screver-ma-db-staging / -prod), reached via the Cloud SQL Proxy for migrations.
  • Secret Manager (-staging / -prod pairs): database URLs, payload-secret, service-secret, anthropic-api-key, gcs-bucket.
  • Domains: ma.screver.com (prod) · ma-staging.screver.com (staging) · docs.ma.screver.com. The AI service is internal (run.app) only.

Pipeline shape (per repo)

Each .github/workflows/ci-deploy.yml: lint / typecheck / build → Payload migrations via the Cloud SQL Proxy → staging auto-deployproduction manual approval gate. Auth via Workload Identity Federation (no JSON keys).

Learnings baked in (non-negotiable)

These come from prior incidents on sibling projects. They are wired into the build, not left to memory.

  • Blank admin panel = the GCS storage plugin missing from the import map. The build runs GCS_BUCKET=dummy payload generate:importmap. If the admin renders blank, check the Cloud Run server logs first for a getFromImportMap error — not the browser CSS.
  • Never db.push() in CI. It uses interactive prompts that hang forever in a non-TTY Cloud Run Job. Always run pre-generated migrations.
  • Migrations are additive only. Never drop a column; never change a field type in place. A new collection also needs its payload_locked_documents_rels relation column (the generated migration handles this — never hand-trim it). A missing one 500s all of /admin.
  • "Deploy is green but new code isn't live" = Cloud Run traffic pinned to an old revision. Deploy by immutable digest and run gcloud run services update-traffic --to-latest after every deploy.
  • Redirects resolving to 0.0.0.0:8080 = read x-forwarded-host / x-forwarded-proto, never request.url, in any redirect route.
  • CSRF / CORS 403 on admin mutations = the allowlists must include both ma.screver.com and ma-staging.screver.com.
  • Stop on warnings; verify before reporting success. After a deploy, curl -sLI the URL and confirm the new behaviour is live (not cached). Production deploys always ask first.

The Fumadocs Dockerfile ordering

fumadocs-mdx's postinstall detects Next vs Vite from the config files present at install time. The docs Dockerfile copies the full source before npm ci, so detection sees next.config.mjs. Reordering to a deps-cache-first pattern breaks the build.