← Ambasdr Platform Docs
Reference · Environments

Every URL, domain and config, grouped by environment

Two lookup tables — one for production, one for development — covering the public hostnames, the backend API base URL, the Auth0 tenant, the operator tools, the data stores and the environment-specific settings. Both tables use the same row keys in the same order, so you can read one row across the two to see exactly what differs. Every row names where the value is actually defined, so you can change it at the source rather than guessing.

01

How to read these tables

The third column is the point of the page. A value that is wrong in one place is usually wrong because it was changed in the app but not in the infrastructure, or vice versa.

Source A

GitHub Environments

Runtime and build values live as GitHub Actions variables and secrets on the dev and prod Environments in the ambasdr repo. The deploy workflows read them and render /opt/ambasdr/.env.backend on the Droplet. Inspect with gh variable list --env prod.

Source B

Terraform tfvars

Infrastructure shape — Droplet size, DNS records, Cloudflare Access applications, whether Postgres and object storage are managed or in-box — lives in the separate ambasdr-infra repo under environments/<env>.tfvars. Both environments share one set of Terraform modules and differ only by these toggles.

Source C

Hardcoded in the workflow

A few values are literals inside .github/workflows/deploy-dev.yml and deploy-prod.yml rather than variables — the Spaces bucket names, the Stripe redirect URLs, and the admin-panel Cloudflare Access identifiers. Changing those means editing the workflow.

No secret values appear on this page

Passwords, API keys and signing secrets are stored as GitHub Actions secrets and are never printed here. Where a secret governs a row, the row names the secret (for example PROD_PG_HOST) instead of its value. Client IDs, Auth0 tenant domains, Stripe price IDs and Cloudflare Access audience tags are public identifiers, not secrets, so they are shown in full.

02

Production

Deployed by the deploy-prod GitHub Actions workflow (manual workflow_dispatch only) onto the ambasdr-prod Droplet. Stateful data lives in DigitalOcean managed services rather than in the box.

ConcernValueDefined in
Primary domain (web app) https://ambasdr.com — the bare apex, no subdomain ambasdr-infra/environments/prod.tfvars: domain = "ambasdr.com", subdomain = ""
Backend API base URL https://api.ambasdr.com Cloudflare A record → the prod reserved IP; Caddy on the box reverse-proxies to backend:9080
API URL baked into the web bundle https://api.ambasdr.com GitHub prod Environment variable VITE_API_URL, passed as a Docker build arg. Vite inlines it at build time, so a dev image can never be promoted to prod.
CORS allowed origins https://ambasdr.com GitHub prod variable PROD_ALLOWED_ORIGINSALLOWED_ORIGINS in /opt/ambasdr/.env.backend
Auth0 tenant ambasdr-prod.us.auth0.com GitHub prod variable VITE_AUTH0_DOMAIN. The same value is handed to the backend as AUTH0_DOMAIN (deploy-prod.yml:208), so the SPA and the JWT validator always agree.
Auth0 SPA client ID chegHzcSAPP6nASMx8UPRIGg7VynoUtH GitHub prod variable VITE_AUTH0_CLIENT_ID
Auth0 API audience https://api.ambasdr.com — a logical identifier string, not a URL that is called GitHub prod variable VITE_AUTH0_AUDIENCE. Deliberately identical in both environments; the tenant is what separates them.
Admin control panel https://panel.ambasdr.com/panel Published by the prod Cloudflare Tunnel (panel → backend:9080) behind the "Panel (prod)" Access application. App and policy IDs in prod.tfvars; the tunnel ingress and the proxied CNAME are managed through the Cloudflare API, outside Terraform.
Panel Access audience tag 1097f2d195388abe4c160bdde7c24930608f73adadd5c43735e46b947b85e174 Literal CF_ACCESS_AUD in deploy-prod.yml. The backend checks the aud claim of the Cloudflare Access JWT against it. It is per-application, so it must differ from dev and changes if the Access app is recreated.
Grafana (logs + metrics) https://grafana.ambasdr.com Cloudflare Tunnel + Access, email one-time PIN to any @juelz.ai address. App/policy IDs in prod.tfvars.
Portainer (container admin) https://portainer.ambasdr.com Cloudflare Tunnel + Access, same PIN gate. App/policy IDs in prod.tfvars.
Droplet ambasdr-prods-4vcpu-8gb, region nyc3, backups on prod.tfvars: droplet_size, enable_droplet_backups = true
Public IP 209.38.50.179 (reserved IP) DigitalOcean reserved IP attached to the Droplet; the Cloudflare A records for the apex and api. point here.
Postgres DigitalOcean Managed Postgres cluster, reached over the private VPC prod.tfvars: managed_postgres_enabled = true. Connection details come from the GitHub secrets PROD_PG_HOST, PROD_PG_USER, PROD_PG_PASSWORD.
Object storage Spaces bucket ambasdr-prod-documents, region nyc3, endpoint https://nyc3.digitaloceanspaces.com Literals in deploy-prod.yml (DO_SPACES_BUCKET / _REGION / _ENDPOINT); bucket created by spaces_enabled = true in prod.tfvars.
Public URL base for stored files https://api.ambasdr.com/v1 GitHub prod variable PROD_DO_SPACES_PUBLIC_URL_BASE. Documents are served back through the API, not straight off the bucket.
Backend ENVIRONMENT value production Literal in deploy-prod.yml. It selects production behaviour throughout the Go service and keeps the admin panel's development-only bypass path unreachable.
Stripe mode Live mode GitHub secrets PROD_STRIPE_SECRET_KEY and PROD_STRIPE_WEBHOOK_SECRET
Stripe webhook endpoint https://api.ambasdr.com/webhooks/stripe Route registered at backend/internal/handler/router.go:415 (signature-verified, no JWT). The endpoint itself is registered in the Stripe dashboard / CLI, not in this repo.
Stripe redirect URLs success https://ambasdr.com/dashboard?checkout=success&session_id={CHECKOUT_SESSION_ID}
cancel https://ambasdr.com/dashboard?checkout=canceled
billing portal return https://ambasdr.com/dashboard
Literals in deploy-prod.yml:198-200
Stripe price IDs Pro price_1TOtBvBrSVDg8X2uxCIOYUx0
Premium price_1Tjfx2BrSVDg8X2uBitJXSUc
GitHub prod variables PROD_STRIPE_PRICE_ID_PRO / _PREMIUM
Stripe payment link https://buy.stripe.com/bJe5kCfE2026fWh3oOb3q01 GitHub prod variable VITE_STRIPE_PAYMENT_LINK. Set on prod only.
Terraform state Spaces bucket ambasdr-tfstate, key prod/terraform.tfstate ambasdr-infra/environments/prod.s3.tfbackend
Deploy trigger Manual only — workflow_dispatch on deploy-prod .github/workflows/deploy-prod.yml
03

Development

Deployed by the deploy-dev workflow onto the ambasdr-dev Droplet. Same rows, same order as the production table above. The defining difference: every data store runs as a container inside the box, so there are no managed-service endpoints.

ConcernValueDefined in
Primary domain (web app) https://dev.ambasdr.com ambasdr-infra/environments/dev.tfvars: domain = "ambasdr.com", subdomain = "dev"
Backend API base URL https://api.dev.ambasdr.com Cloudflare A record → the dev reserved IP; Caddy reverse-proxies to backend:9080
API URL baked into the web bundle https://api.dev.ambasdr.com GitHub dev Environment variable VITE_API_URL
CORS allowed origins https://dev.ambasdr.com GitHub dev variable DEV_ALLOWED_ORIGINSALLOWED_ORIGINS in /opt/ambasdr/.env.backend
Auth0 tenant dev-p63lq2om24unmpa2.us.auth0.com Repository-level variable VITE_AUTH0_DOMAIN. The dev Environment defines no override, so it inherits the repo value — unlike prod, which overrides it. A separate Auth0 tenant from prod, so dev logins and prod logins are entirely independent user pools.
Auth0 SPA client ID SUxT7E56NlA9iarQEvryB8ZBANaAW3HT Repository-level variable VITE_AUTH0_CLIENT_ID (inherited, as above)
Auth0 API audience https://api.ambasdr.com — same identifier string as prod, by design Repository-level variable VITE_AUTH0_AUDIENCE
Admin control panel https://panel-dev.ambasdr.com/panel Dev Cloudflare Tunnel (panel-dev → backend:9080) behind the "Panel (dev)" Access application. App and policy IDs in dev.tfvars; tunnel ingress and CNAME managed via the Cloudflare API.
Panel Access audience tag 6910108429833c4b211a1b633c2992683ce14c80929cbb9745f1e903dbd591f5 Literal CF_ACCESS_AUD in deploy-dev.yml. Different from prod's because it identifies a different Access application — never copy one environment's value to the other.
Grafana (logs + metrics) https://grafana-dev.ambasdr.com Cloudflare Tunnel + Access. Dev additionally owns the account-global one-time-PIN login method (manage_grafana_idp = true in dev.tfvars; prod sets it false so the two do not fight over the same object).
Portainer (container admin) https://portainer-dev.ambasdr.com Cloudflare Tunnel + Access. App/policy IDs in dev.tfvars.
Droplet ambasdr-devs-2vcpu-4gb, region nyc3, backups off dev.tfvars: droplet_size, enable_droplet_backups = false
Public IP 152.42.153.142 (reserved IP). The Droplet also carries its original public address 45.55.86.15; DNS points at the reserved IP. DigitalOcean reserved IP attached to the Droplet
Postgres In-box postgres:16-alpine container, data under /data/ambasdr/postgres dev.tfvars: managed_postgres_enabled = false. The backend reaches it at DB_HOST=postgres over the Docker network.
Object storage In-box MinIO container. Bucket ambasdr-documents, region us-east-1, endpoint http://minio:9000 Literals in deploy-dev.yml; spaces_enabled = false in dev.tfvars means no Spaces bucket is created. The region string is a MinIO placeholder, not a DigitalOcean region.
Public URL base for stored files https://api.dev.ambasdr.com/v1 GitHub dev variable DEV_DO_SPACES_PUBLIC_URL_BASE
Backend ENVIRONMENT value dev Literal in deploy-dev.yml. Note it is dev, not development — the admin panel's local bypass is gated on the exact string development, so on the dev box that path stays unreachable and Cloudflare Access is the only way in.
Stripe mode Test mode GitHub secrets DEV_STRIPE_SECRET_KEY and DEV_STRIPE_WEBHOOK_SECRET. Test and live are separate Stripe endpoints with separate signing secrets.
Stripe webhook endpoint https://api.dev.ambasdr.com/webhooks/stripe Same route as prod (router.go:415); registered against the test-mode Stripe account.
Stripe redirect URLs success https://dev.ambasdr.com/dashboard?checkout=success&session_id={CHECKOUT_SESSION_ID}
cancel https://dev.ambasdr.com/dashboard?checkout=canceled
billing portal return https://dev.ambasdr.com/dashboard
Literals in deploy-dev.yml:250-252
Stripe price IDs Pro price_1TyPvRBrSVDg8X2uut2JtYbM
Premium price_1TyPvRBrSVDg8X2uCLri8xxI
GitHub dev variables DEV_STRIPE_PRICE_ID_PRO / _PREMIUM
Stripe payment link Not set on dev No VITE_STRIPE_PAYMENT_LINK variable exists on the dev Environment.
Terraform state Spaces bucket ambasdr-tfstate, key dev/terraform.tfstate ambasdr-infra/environments/dev.s3.tfbackend
Deploy trigger deploy-dev workflow .github/workflows/deploy-dev.yml
Dev-only frontend flags VITE_PRELAUNCH_MODE=false, plus a VITE_BETA_ACCESS_CODE_HASH gate GitHub dev Environment variables. Neither variable is defined on prod.
04

Identical in both environments

These are deliberately not split per environment. Knowing which values are shared is as useful as knowing which differ — changing one of these affects dev and prod at the same time.

The prod web app sits on the apex, which constrains the marketing site

Because subdomain = "", the production React app is served from ambasdr.com itself rather than a subdomain such as app.ambasdr.com. That means the apex record cannot simultaneously point at a separate marketing host. If the marketing site ever needs the apex back, the app has to move to a subdomain first, and changing subdomain in prod.tfvars is only the first step. Four other places hardcode https://ambasdr.com and would each have to change too: PROD_ALLOWED_ORIGINS, the Auth0 callback / logout / web-origin URLs on the prod SPA application, the three Stripe redirect URLs in deploy-prod.yml, and the Cloudflare A record. The API hostname (api.ambasdr.com) is already a subdomain and would be unaffected.