Derive *_BASE_URL env vars from the manifest domains cast already parses — hand-writing them into the env template drifts from the domains it creates #66

Closed
opened 2026-07-15 10:32:18 +00:00 by dan-claude-bot · 0 comments
dan-claude-bot commented 2026-07-15 10:32:18 +00:00 (Migrated from github.com)

Problem

The env templates carry base-URL vars that are already fully determined by the domain fields in manifest.yaml — the same fields cast reads to create Coolify domains. Because cast doesn't derive them, they're hand-transcribed a second time into env/*.env.template, and the two copies drift.

Concretely, incubator's prod env template was missing three vars staging had, and one of them (LANDING_BASE_URL) still pointed at the old pre-apex host even after the manifest's domains/service_domains were renamed to the apex scheme. The manifest was right; the env template was stale — exactly the class of drift cast exists to kill.

The app reads (via apps/core/src/platform/config.ts):

Env var Should derive from (manifest)
LANDING_BASE_URL applications.landing.domains[0]
ADMIN_WEB_BASE_URL applications.core.service_domains.admin[0]

LANDING_BASE_URL drives branded-email header images + footer links; ADMIN_WEB_BASE_URL is required at startup once REPORTING_ENABLED flips (loadConfig throws without it). So a stale value is not cosmetic — it's a boot-time failure or broken outbound links at cutover.

Why this is the same shape as #60 / #63

  • #60 derives DATABASE_URL/REDIS_URL from the database resource cast created.
  • #63 derives landing static fields from manifest data.

This is the identical pattern applied to the domain fields: cast already parses domains and service_domains to reconcile Coolify domains, so the base-URL env values are known at plan time. Writing them into the template by hand is the duplication (and the drift vector).

Proposal

Let the env template reference derived domain values instead of literals — e.g. a ${domain:...}-style interpolation resolved from the manifest, symmetric with how generated_secrets are resolved post-create:

LANDING_BASE_URL=${domain:landing}
ADMIN_WEB_BASE_URL=${domain:core.admin}

(exact syntax TBD — mirror whatever generated_secrets interpolation settles on.)

Out of scope / notes

  • REPORTING_TZ is not derivable — it's an operator policy choice (Europe/Madrid), not topology. It stays a literal in the template. This issue is only for values that are pure functions of the manifest's domains.
  • API_BASE_URL is intentionally the internal compose address (http://api:3000), not a public domain — don't derive that one from service_domains.api.

Bridge until then

incubator's .infra/env/core.prod.env.template now hard-codes the three literals as a temporary bridge. When this lands, those *_BASE_URL lines become derived and the manual copies retire.

Filed from the incubator repo — pattern precedent: cast#60 (D-268), cast#63 (D-267).

## Problem The env templates carry base-URL vars that are **already fully determined by the domain fields in `manifest.yaml`** — the same fields cast reads to create Coolify domains. Because cast doesn't derive them, they're hand-transcribed a second time into `env/*.env.template`, and the two copies drift. Concretely, `incubator`'s prod env template was missing three vars staging had, and one of them (`LANDING_BASE_URL`) still pointed at the **old pre-apex host** even after the manifest's `domains`/`service_domains` were renamed to the apex scheme. The manifest was right; the env template was stale — exactly the class of drift cast exists to kill. The app reads (via `apps/core/src/platform/config.ts`): | Env var | Should derive from (manifest) | | --- | --- | | `LANDING_BASE_URL` | `applications.landing.domains[0]` | | `ADMIN_WEB_BASE_URL` | `applications.core.service_domains.admin[0]` | `LANDING_BASE_URL` drives branded-email header images + footer links; `ADMIN_WEB_BASE_URL` is **required at startup** once `REPORTING_ENABLED` flips (`loadConfig` throws without it). So a stale value is not cosmetic — it's a boot-time failure or broken outbound links at cutover. ## Why this is the same shape as #60 / #63 - **#60** derives `DATABASE_URL`/`REDIS_URL` from the database resource cast created. - **#63** derives landing static fields from manifest data. This is the identical pattern applied to the **domain** fields: cast already parses `domains` and `service_domains` to reconcile Coolify domains, so the base-URL env values are known at plan time. Writing them into the template by hand is the duplication (and the drift vector). ## Proposal Let the env template reference derived domain values instead of literals — e.g. a `${domain:...}`-style interpolation resolved from the manifest, symmetric with how `generated_secrets` are resolved post-create: ``` LANDING_BASE_URL=${domain:landing} ADMIN_WEB_BASE_URL=${domain:core.admin} ``` (exact syntax TBD — mirror whatever `generated_secrets` interpolation settles on.) ## Out of scope / notes - `REPORTING_TZ` is **not** derivable — it's an operator policy choice (`Europe/Madrid`), not topology. It stays a literal in the template. This issue is only for values that are pure functions of the manifest's domains. - `API_BASE_URL` is intentionally the internal compose address (`http://api:3000`), not a public domain — don't derive that one from `service_domains.api`. ## Bridge until then `incubator`'s `.infra/env/core.prod.env.template` now hard-codes the three literals as a temporary bridge. When this lands, those `*_BASE_URL` lines become derived and the manual copies retire. _Filed from the `incubator` repo — pattern precedent: cast#60 (D-268), cast#63 (D-267)._
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: heavy-duty/cast#66
No description provided.