# Helix / Odenza Deployment Setup (Lumen & Gescan)

**Date**: 2026-10-16
**Scope**: CI/CD pipelines, Dockerfiles, Helm charts, SSL and ECR base images
for the new Helix-based sites **Lumen** and **Gescan**.

---

## Services

| Service | Role | Public ingress | Base image (`FROM`) |
|---------|------|----------------|---------------------|
| tbi-hlx-dynamic-path | Reservation / dynamic path (per site) | yes | `tbi-php-85` |
| tbi-hlx-booking-path | Booking / revenue path (per site) | yes | `tbi-php-73` |
| tbi-hlx-whitelabel-frontend | Whitelabel travel frontend (per site) | yes | `tbi-php-85` |
| tbi-rlv-helix-bridge | Internal Helix member connectivity service | no | `tbi-php-85` |
| tbi-legacy-hotels-service | Shared hotels backend service | no | `tbi-php-81` |

Each service has config generated under `dev/`, `uat/`, and `prod/`.
Total: **5 services × 3 environments = 15 pipeline directories.**

> The brief specified dev and prod with no UAT. A `uat/` tree is included as
> well (same shape as dev, branch `uat`) so a dedicated UAT environment can be
> stood up if required; it can be deleted if UAT is never used.

---

## Deployment targets (hostnames)

Dev hosts carry a `dev-` prefix; prod drops it. Both Lumen and Gescan hosts are
served by the same service deployment and resolved per environment from
`tbi-environments/<env>/values/<service>.yaml` (`hosts:` list).

### Lumen

| Service | dev | prod |
|---------|-----|------|
| tbi-hlx-dynamic-path | dev-res-recompenses.lumen.ca | res-recompenses.lumen.ca |
| tbi-hlx-booking-path | dev-rev-recompenses.lumen.ca | rev-recompenses.lumen.ca |
| tbi-hlx-whitelabel-frontend | dev-travel-recompenses.lumen.ca | travel-recompenses.lumen.ca |

### Gescan

| Service | dev | prod |
|---------|-----|------|
| tbi-hlx-dynamic-path | dev-res-rewards.gescan.com | res-rewards.gescan.com |
| tbi-hlx-booking-path | dev-rev-rewards.gescan.com | rev-rewards.gescan.com |
| tbi-hlx-whitelabel-frontend | dev-travel-rewards.gescan.com | travel-rewards.gescan.com |

### TD, ATB MyRewards, ATB MyBusinessRewards

`develop` is staging. `master` is production. These names are the sites already served from the web servers.

| Service | staging (`develop`) | prod (`master`) |
|---------|---------------------|-----------------|
| tbi-hlx-whitelabel-frontend | td-odenza.stg.travelco.com, atb-odenza.stg.travelco.com, atbbusiness-odenza.stg.travelco.com | travel.tdreferralrewards.com, td-odenza.redtag.ca, travel.atbmyrewards.com, atb-odenza.redtag.ca, travel.atbmybusinessrewards.com, atbbusiness-odenza.redtag.ca |
| tbi-hlx-dynamic-path | hotels-td-odenza.stg.travelco.com, hotels-atb-odenza.stg.travelco.com, hotels-atbbusiness-odenza.stg.travelco.com | dyn-path-td-odenza.redtag.ca, dyn-path-atb-odenza.redtag.ca, dyn-path-atbbusiness-odenza.redtag.ca |
| tbi-hlx-booking-path | flights-td-odenza.stg.travelco.com, flights-atb-odenza.stg.travelco.com, flights-atbbusiness-odenza.stg.travelco.com | book-path-td-odenza.redtag.ca, book-path-atb-odenza.redtag.ca, book-path-atbbusiness-odenza.redtag.ca |

---

## Environment matrix

| Setting | dev | uat | prod |
|---------|-----|-----|------|
| Branch | `develop` | `uat` | `master` |
| CircleCI context | `devops-mgt` | `devops-mgt` | `devops-mgt-prod` |
| Helm S3 bucket | `tbi-charts` | `tbi-charts` | `tbi-charts-prod` |
| Deploy runner | `tbi-local-runner/loadtest` | `tbi-local-runner/loadtest` | `tbi-local-runner/prod-win` |
| ECR tag mutability | MUTABLE | MUTABLE | IMMUTABLE |
| Image tag | `VERSION-branch-build` | `VERSION-branch-build` | clean `VERSION` |
| Approval gates | none | none | 2-stage (build + deploy) |
| SNS topic | — | — | `arn:aws:sns:ca-central-1:489176460030:DevOps-alert` |
| Namespace | `helix` | `helix` | `helix` |

The Dockerfile and deployment scripts are staged from THIS repo at build time
(the app repo's CircleCI project points its config at
`<env>/<service>/.circleci/config.yml`).

---

## SSL / TLS

Certificates are pre-provisioned (ACM). The ALB ingress consumes the ACM
certificate ARN via the `acm_cert_arn` value and listens on HTTP(80)+HTTPS(443)
with `ssl-redirect` to 443. Supply per environment in
`tbi-environments/<env>/values/<service>.yaml`:

```yaml
ingress_enabled: true
acm_cert_arn: arn:aws:acm:ca-central-1:<account>:certificate/<id>
hosts:
  - res-recompenses.lumen.ca
  - res-rewards.gescan.com
```

> If Lumen and Gescan use separate ACM certs that cannot share one ALB listener,
> split the service into two value sets / listeners accordingly. A single ALB
> listener supports multiple certs (SNI), which the current template assumes.

---

## ECR base images (REQUIRED before app builds)

App Dockerfiles pull their PHP base image from the **per-environment ECR
account**, matching the AWS profile used for that environment:

| Environment | AWS profile | ECR account |
|-------------|-------------|-------------|
| dev | `tbi-dev` | 594765360358 |
| uat / prod | `tbi-prod` | 489176460030 |

The generated `dev/*/docker/Dockerfile` reference `594765360358`; `uat/*` and
`prod/*` reference `489176460030`.

Required base images (verified against live ECR, 2026-10-16):

| Base image | Needed by | tbi-dev (594…) | tbi-prod (489…) | Action |
|------------|-----------|----------------|-----------------|--------|
| `tbi-php-85` | dynamic-path, whitelabel-frontend, helix-bridge | missing | missing | **publish to both** |
| `tbi-php-81` | legacy-hotels-service | missing | missing | **publish to both** |
| `tbi-php-73` | booking-path | present | present | none |

Source: `redlabelvacations/tbi-base-images` @ branch `helix-upgrades`.

Publish with `scripts/build-helix-base-images.sh` (needs Docker + an active SSO
session for the relevant profile). It builds each image once and pushes to the
selected environment's account using `--profile`:

```bash
# log in to the SSO profiles first
aws sso login --profile tbi-dev
aws sso login --profile tbi-prod

# publish tbi-php-85 and tbi-php-81 to BOTH dev and prod ECR (default):
bash scripts/build-helix-base-images.sh

# only one environment:
TARGET=dev  bash scripts/build-helix-base-images.sh   # -> tbi-dev  / 594765360358
TARGET=prod bash scripts/build-helix-base-images.sh   # -> tbi-prod / 489176460030

# local build only, no push (no AWS needed):
PUSH=false bash scripts/build-helix-base-images.sh
```

---

## Remaining manual steps

1. **Publish base images** — run `scripts/build-helix-base-images.sh` once per
   account (`tbi-php-85` and `tbi-php-81` are missing from both tbi-dev and
   tbi-prod ECR; `tbi-php-73` already exists in both). Uses `--profile tbi-dev`
   for dev and `--profile tbi-prod` for prod.
2. **Create per-service values/secrets in `tbi-environments`** for each env:
   - `<env>/values/<service>.yaml` — `name`, `image`, `hosts`, `acm_cert_arn`,
     `ingress_enabled`, resources (seed from each app repo's `.env.example`).
   - `<env>/secrets/secrets.<service>.yaml` — SOPS-encrypted `configs.dotenv`
     (the full `.env`). `tbi-rlv-helix-bridge` has no `.env.example`; it is
     configured via `docker/php.ini` / `docker/opcache.ini`.
   - Maintain separate value sets for Lumen vs Gescan where the brands differ
     (e.g. `whitelabel-frontend` `SITE_KEY`, logos, phone numbers).
3. **Add a `VERSION` file** to each app repo if missing (only
   `tbi-hlx-whitelabel-frontend` currently has one). The pipeline tags images
   from `VERSION`.
4. **Configure CircleCI projects** to use config path
   `<env>/<service>/.circleci/config.yml` from `tbi-devops-environments`, with
   contexts `devops-mgt` (dev/uat) and `devops-mgt-prod` (prod).

---

## Generator

All 15 directories are produced by `scripts/generate-helix-services.sh`
(idempotent — safe to re-run). Real Dockerfiles are copied from the app repo
clones with unqualified base-image `FROM` lines normalized to the full ECR path.
