Deployment Guide
Bilko Deployment Guide
Last Updated: 2026-04-16
Current State: Stable Cloud Run deployment with custom domain provisioning
GCP Project Configuration
- Project ID:
tribal-sign-487920-k0 - Region:
europe-north1(Stockholm) - Services:
bilko-api→ https://bilko-api-dh4m46blja-lz.a.run.app (revision 00037)bilko-web→ https://bilko-web-dh4m46blja-lz.a.run.app
Secret Manager
| Secret Name | Version | Purpose |
|---|---|---|
bilko-cors-origins | v2 | Comma-separated list of allowed CORS origins |
bilko-database-url | latest | Cloud SQL connection string (password reset 2026-04-16) |
bilko-jwt-refresh-secret | latest | JWT refresh token secret |
CORS Parsing: Secret bilko-cors-origins is parsed by comma in apps/api/src/app.ts:61
Environment Variables
bilko-web
NEXT_PUBLIC_API_URL=https://bilko-api-dh4m46blja-lz.a.run.app
bilko-api
CORS_ORIGINS→ pulled frombilko-cors-origins:latestSESSION_COOKIE_SECURE=trueNODE_ENV=productionDATABASE_URL→ pulled frombilko-database-url:latest
Custom Domain Setup
Current Domain
- Host:
bilko-demo.alai.no - Mapped to:
bilko-webCloud Run service - DNS Provider: one.com
- DNS Record:
CNAME bilko-demo.alai.no → ghs.googlehosted.com. - TLS Cert: Let's Encrypt (managed by GCP, auto-renews)
- Provisioning Time: 15-30 minutes after DNS propagation
Domain Verification Constraint
Critical: Only alai.no is verified in GCP Search Console (via [email protected]).
basicconsulting.no is NOT verified. All custom domains MUST use *.alai.no subdomains until basicconsulting.no is verified.
Custom Domain Runbook
Prerequisites
- Domain must be verified in Google Search Console by the GCP account owner
- DNS provider access (one.com for
alai.no, Vercel forbasicconsulting.no) gcloudCLI authenticated:gcloud auth login
Step-by-Step
1. Create Domain Mapping
gcloud beta run domain-mappings create \
--service=bilko-web \
--domain=bilko-demo.alai.no \
--region=europe-north1 \
--project=tribal-sign-487920-k0
2. Configure DNS
Add CNAME record at DNS provider:
Type: CNAME
Host: bilko-demo
Value: ghs.googlehosted.com.
TTL: 3600
3. Wait for Certificate Provisioning
gcloud beta run domain-mappings describe bilko-demo.alai.no \
--region=europe-north1 \
--project=tribal-sign-487920-k0
Look for status.conditions → CertificateProvisioned: True
4. Update CORS Allowed Origins
# Get current value
gcloud secrets versions access latest --secret=bilko-cors-origins
# Add new domain
echo "https://bilko-demo.alai.no,https://bilko-web-dh4m46blja-lz.a.run.app" | \
gcloud secrets versions add bilko-cors-origins --data-file=-
5. Deploy New Revision
gcloud run services update-traffic bilko-api \
--to-latest \
--region=europe-north1 \
--project=tribal-sign-487920-k0
6. Verify CORS Preflight
curl -sSI -X OPTIONS \
https://bilko-api-dh4m46blja-lz.a.run.app/api/v1/auth/login \
-H "Origin: https://bilko-demo.alai.no" \
-H "Access-Control-Request-Method: POST"
Expected: HTTP 204 with Access-Control-Allow-Origin: https://bilko-demo.alai.no
GitHub Actions CI/CD
- Workflow:
.github/workflows/deploy-production.yml - Auth: Workload Identity Federation (WIF)
- Service Account:
[email protected] - IAM Roles:
roles/run.admin,roles/iam.serviceAccountUser
Deployment Steps
- Authenticate via WIF
- Build Docker images (api + web)
- Push to Google Container Registry
- Deploy to Cloud Run (europe-north1)
- Run smoke tests (Playwright E2E)
Testing
Backend Tests
- Framework: Vitest
- Location:
apps/api/src/**/*.test.ts - Command:
pnpm test(fromapps/api/)
End-to-End Tests
- Framework: Playwright
- Location:
apps/e2e/tests/ - Command:
pnpm test(fromapps/e2e/) - Runs in CI: Yes (on every deploy)
Recent Fixes (2026-04-16)
Commits
a62b7f6— Cloud Run service names align:bilko-staging-*→bilko-*9b1ced1— Backend: addedcurrencyfield to invoice list, added/api/v1/settings/profileendpoint73693d4— Frontend: avatar initials fallback, invoice step indicator, chat widget ARIA labels
Key Changes
- Service Naming: Production services now named
bilko-apiandbilko-web(no-stagingsuffix) - API Enhancements: Invoice list now includes currency, new profile settings endpoint
- Frontend Fixes: Accessibility improvements (ARIA), avatar initials when no image, visual polish
Rollback Procedure
Rollback to Previous Revision
# List revisions
gcloud run revisions list --service=bilko-api --region=europe-north1
# Rollback
gcloud run services update-traffic bilko-api \
--to-revisions=bilko-api-00036=100 \
--region=europe-north1
Rollback via GitHub Actions
git revert HEAD
git push origin main # Triggers deploy workflow
Troubleshooting
Issue: CORS errors in browser
Cause: Custom domain not in bilko-cors-origins secret
Fix: Update secret (see step 4 in Custom Domain Runbook), deploy new revision
Issue: 502 Bad Gateway
Cause: Service unhealthy or startup timeout
Fix: Check Cloud Run logs: gcloud run services logs read bilko-api --region=europe-north1 --limit=50
Issue: Database connection timeout
Cause: Cloud SQL Proxy misconfiguration or secret outdated
Fix: Verify bilko-database-url secret, check Cloud SQL instance status
Issue: Custom domain SSL pending
Cause: DNS not propagated or domain not verified in Search Console
Fix: Wait 15-30 min after DNS change, verify domain ownership in Search Console
Architecture Diagram
┌─────────────────┐
│ one.com DNS │
│ bilko-demo. │
│ alai.no │
└────────┬────────┘
│ CNAME
▼
┌─────────────────────────────┐
│ ghs.googlehosted.com │
│ (Google Cloud Load Balancer)│
└────────┬────────────────────┘
│
▼
┌─────────────────────────────┐ ┌──────────────────┐
│ bilko-web (Cloud Run) │──────▶│ bilko-api │
│ Next.js 15 + React 19 │ HTTP │ Express + TS │
│ europe-north1 │ │ europe-north1 │
└─────────────────────────────┘ └────────┬─────────┘
│
▼
┌─────────────────┐
│ Cloud SQL │
│ PostgreSQL 16 │
│ europe-north1 │
└─────────────────┘
No comments to display
No comments to display