AccountingKitDocs

Deployment

Run the cost-first MVP on Cloud Run with Cloud SQL.

Cloud Run MVP

The MVP target is one Cloud Run API service and one Cloud SQL PostgreSQL instance in the same region. The API runs the durable accounting worker in-process. PostgreSQL owns queue state, leases, retries, dead letters, and the outbox, so the MVP does not need a separate worker or queue service.

Use scripts/deploy/cloud-run.sh. It builds and pushes the server image, runs the migration Cloud Run job, deploys the service, and checks /ready. The complete non-secret environment is deploy/cloudrun/env.yaml; Secret Manager mappings are declared in deploy/cloudrun/config.env. Cloud SQL is reached through Cloud Run's Unix socket mount; do not expose PostgreSQL publicly.

Use ACCOUNTING_QUEUE_BACKEND=postgres, ACCOUNTING_EMBEDDED_WORKER_ENABLED=true, one minimum instance, and the declared maximum of three instances. Wrap production data keys with the regional Cloud KMS key declared by ACCOUNTING_KMS_KEY_NAME. The console and documentation are static Cloudflare assets.

Required accounting configuration

Set XERO_CLIENT_ID, XERO_CLIENT_SECRET, XERO_REDIRECT_URI, XERO_WEBHOOK_KEY, ACCOUNTING_API_KEY_PEPPER, ACCOUNTING_KMS_KEY_NAME, and CONNECT_ALLOWED_REDIRECT_ORIGINS. Production startup rejects incomplete security-critical configuration.

For the PostgreSQL-backed MVP, the worker URL and Cloud Tasks service account are not required. They become relevant only when the Cloud Tasks backend is selected. KMS remains part of both production topologies because it protects provider credentials independently of queue delivery.

Later GCP migration

When scale justifies it, the existing GCP infrastructure can provision separate Cloud Run API and worker services, Cloud SQL, Cloud Tasks, KMS, Artifact Registry, Secret Manager, and controlled egress. Set ACCOUNTING_QUEUE_BACKEND=cloud-tasks and disable the embedded worker. The operation ledger and worker execution path remain unchanged.

Terraform creates Secret Manager containers but deliberately does not place secret values in state. For a new environment, apply the secret containers first, add at least one version for every ID in the runtime_secret_ids output, and then apply the Cloud Run services. An empty secret cannot be mounted as latest by Cloud Run.

GCP service identity

The API may enqueue Cloud Tasks but should not invoke arbitrary services. Cloud Tasks signs requests for the worker audience, and each task also carries a separately generated ACCOUNTING_WORKER_AUTH_TOKEN. The worker rejects requests without both credentials; never reuse an API key pepper, user credential, or provider secret for this token. The worker may decrypt with the accounting KMS key. Database identities should be distinct where practical.

Release verification

Apply migrations up, down, and up in an isolated database. Run formatting, lint, type checking, tests, unused-code analysis, infrastructure validation, and production builds. Smoke-test readiness, API-key rejection, hosted connect creation, a test Xero authorization, one cached list read, one idempotent write replay, one automation, and one signed webhook delivery before routing production traffic.

On this page