Northstar Deployment plan · 1 September 2026
Recommended first production shape

Use Cloud Run. Do not start with GKE.

Northstar has twelve deployable backend processes, but most of them will sit idle during the internal pilot. Cloud Run keeps the service boundaries without paying for twelve servers all day.

1region to start
12Cloud Run services
2public API entry points plus one webhook
0GKE clusters needed now
Target architecture

One regional control plane

Start in asia-south1. Keep the control data in that region. Route database reads and migration work through small, capped worker pools. Add regional workers only when customer database locations make the extra latency worth it.

Callers
BrowserNorthstar operators and reviewers
Codex, Cursor, ClaudeMCP clients with scoped tokens
GitHubSigned pull request and merge events
Report readersPublic, sanitized HTML only
HTTPS ↓
Edge
Cloudflare PagesStatic UI after auth is ready
API gatewayHuman API and browser session checks
Agent gatewayMCP endpoint and client token checks
GitHub webhookSignature check and fast acceptance
authenticated internal calls ↓
Control
Identity and accessUsers, clients, grants, decisions
Connections and brokerEncrypted targets and short leases
Metadata and auditCatalog cache and durable events
Migration servicePR state, approvals, run ledger
queued and rate-limited work ↓
Execution
Cloud TasksWebhook work and migration execution
Query runnerShort SQL work with hard limits
Liquibase runnerOne migration per container request
Connector agent laterOutbound path from private customer networks
private network or fixed egress ↓
Data
Cloud SQLNorthstar control records
Cloud StorageExact migration source bundles
Customer databasesQueries and Liquibase changes
Cloud LoggingService logs, alerts, traces
Service placement

Keep the code split, cap the runtime

Each Go command can remain a separate Cloud Run service. Only three routes need public traffic. Everything else should reject calls that do not carry a valid service identity.

ProcessExposureInitial sizeInitial scalingReason
api-gatewayPublic through one hostname1 vCPU, 512 MiBMin 1 in production, max 5, concurrency 40Browser entry point. One warm instance avoids a slow first screen.
agent-gatewayPublic MCP hostname1 vCPU, 512 MiBMin 0, max 5, concurrency 20MCP requests are bursty. Keep a lower concurrency until query limits are proven.
github-servicePublic webhook route only1 vCPU, 512 MiBMin 0, max 3, concurrency 40Verify the signature, store the event, enqueue work, and return fast.
identity-service, access-servicePrivate1 vCPU, 512 MiB eachMin 0, max 3, concurrency 40Small control-plane requests.
connection-service, credential-brokerPrivate1 vCPU, 512 MiB eachMin 0, max 3, concurrency 20These touch encrypted credentials. Keep the caller list narrow.
metadata-service, audit-servicePrivate1 vCPU, 512 MiB eachMin 0, max 3, concurrency 40Control database reads and writes.
migration-servicePrivate worker API1 vCPU, 1 GiBMin 0, max 3, concurrency 5Builds source manifests and records run state.
query-runnerPrivate1 vCPU, 1 GiBMin 0, max 5, concurrency 4Every request can hold a connection to a customer database.
liquibase-runnerPrivate2 vCPU, 2 GiBMin 0, max 2, concurrency 1Liquibase uses Java and runs external processes. Isolate each run.
connector-agentDo not deploy centrally yetCustomer dependentDisabledUse it later for databases that have no public route.
These are starting controls, not Cloud Run limits. Load tests should set the next values. Database capacity and target database safety matter more than raw HTTP throughput.
Required GCP services

Small set, clear jobs

The control plane needs managed compute, a durable database, private networking, task delivery, container storage, secrets, and logs. Redis and Kubernetes add cost without solving a current problem.

Compute

Cloud Run

Twelve services. Most use a zero minimum. Query and migration runners get low concurrency and strict maximums.

Database

Cloud SQL for PostgreSQL

One control database per environment. Start staging as single-zone. Use regional HA, backups, and point-in-time recovery in production.

Delivery

Cloud Tasks

Move webhook and migration work off the request path. Use OIDC service identity and database-backed idempotency.

Build

Artifact Registry and Cloud Build

Build one image per process from a commit SHA. Promote the exact digest from staging to production.

Source

Cloud Storage

Store short-lived, checksum-addressed migration bundles. Lifecycle rules should delete old bundles after the audit window.

Security

Secret Manager and Cloud KMS

Hold runtime secrets in Secret Manager. Replace the single AES environment key with KMS envelope encryption before customer use.

Network

VPC, private service access, NAT

Give Cloud SQL a private address. Route database workers through a fixed egress IP when a target database requires allowlisting.

Operations

Cloud Logging and Monitoring

Alert on failed tasks, failed migrations, high database connections, repeated authorization failures, and old in-progress runs.

Edge

Cloudflare Pages

Publish sanitized reports now. Publish the product UI only after production authentication is in place.

Capacity

Start for an internal pilot

The first deployment should protect databases, not chase a large request number. The following tiers are operating targets. They are not promises about provider limits.

TierWorking assumptionDatabase workControl databaseChange that unlocks it
Internal pilotUp to 25 people, 50 saved targets, 100 migration runs per day10 active queries and 2 Liquibase runs at once2 vCPU, about 8 GiB RAM, single-zone stagingCurrent recommendation
Early customersUp to 500 people, 1,000 saved targets, 1,000 migration runs per day100 active queries and 10 Liquibase runs across targets4 vCPU, about 16 GiB RAM, regional HAConnection pooler, per-tenant limits, queue partitions
Regional productSeveral thousand people and databases in more than one geographyWorkers placed near target databasesControl data remains regional, reporting reads may use replicasRegional runner pools and customer connector agents
Do not raise migration concurrency to make a queue disappear. A database migration is an exclusive operation for a target. Queue it, show its position, and keep one active migration per database.
Code gaps

Do not deploy the current local shape as production

The service boundaries are usable. Five local assumptions still block a safe cloud deployment.

Blocker 1

Authentication is still a development flow

DEV_MODE creates a local browser session. Keep staging private behind an identity proxy, then add real SSO or product login before any customer can reach the API.

Blocker 2

Repositories are local mounts

The migration service reads exact commits from /repos. Cloud Run will not have those folders. Fetch the approved GitHub commit with a GitHub App and store a checksum-addressed bundle.

Blocker 3

Webhook work is synchronous

A webhook must verify, persist, enqueue, and return. Cloud Tasks should run previews and applies. Existing idempotency keys and Liquibase history already provide a good base for retries.

Blocker 4

Internal trust uses one shared token

Use one service account per process and Cloud Run identity tokens. Keep the internal token only as a temporary staging control.

Blocker 5

Control schema changes only run on a new Docker volume

The SQL files under backend/deploy/postgres/init need a real migration job. Convert them into a versioned changelog and run it before each service release.

Before external use

Make pool and timeout settings configurable

Eight control services each open up to eight PostgreSQL connections per instance. Set small per-service pools, cap Cloud Run instances, and give long migrations an asynchronous job timeout.

Release order

Build staging before production

Each phase has a pass condition. A successful container deployment is not enough.

01

Prepare the code

  • Add remote GitHub commit fetch.
  • Add Cloud Tasks handlers.
  • Add service identity tokens.
  • Make database pools configurable.
  • Package control schema migrations.
  • Disable DEV_MODE by default.
02

Create isolated staging

  • Create a new GCP project.
  • Use asia-south1.
  • Create VPC, private Cloud SQL, NAT, queues, bucket, registry, KMS, and secrets.
  • Create service accounts with narrow IAM roles.
  • Create a dedicated test database target.
  • Never use an existing production database for migration tests.
03

Deploy and prove the workflow

  • Deploy private services first.
  • Deploy API, MCP, and webhook entry points last.
  • Run preview, approve, apply, duplicate delivery, and rollback tests.
  • Kill a worker during a run and prove the retry is safe.
  • Confirm logs do not contain database passwords.
  • Confirm a denied MCP token cannot read a table.
04

Run the internal pilot

  • Use a small set of non-production databases first.
  • Add allowlists and per-target query limits.
  • Measure cold starts, queue delay, query duration, and control DB connections.
  • Keep Liquibase concurrency at one per target.
  • Review audit events daily during the pilot.
05

Create production

  • Create a second GCP project.
  • Use regional HA Cloud SQL with backups and point-in-time recovery.
  • Promote tested image digests.
  • Require real user authentication.
  • Run restore and rollback drills before onboarding a customer.
Cloudflare reports

A safe terminal publishing path

The repository now has a dedicated public-reports directory. Only files in that directory are uploaded. Internal docs, credentials, and source files stay out of the Pages deployment.

Local command

Publish all approved reports

./scripts/deploy-public-reports.sh
One report

Add a sanitized page

cp report.html public-reports/
./scripts/deploy-public-reports.sh
Every file under public-reports becomes public. Remove credentials, customer names, internal hostnames, database data, account numbers, and private screenshots before publishing.

The local Wrangler OAuth login is suitable for manual publishing. CI should use a separate API token limited to Cloudflare Pages. Do not copy the local OAuth credential into GitHub Actions.

Final decision

What I would approve

Approve an isolated staging build on Cloud Run. Reject a production launch until authentication, remote repository fetch, asynchronous execution, service identity, and control database migrations are fixed.

Approve now

Staging foundation

New project, one region, Cloud Run, private Cloud SQL, Cloud Tasks, fixed egress, KMS, logs, and a test-only PostgreSQL target.

Reject now

Production traffic

The current local login and mounted repository model are not safe or workable in a serverless production deployment.