# W3 (Pinbox24) v32-prod image-build + deploy pipeline — PROPOSED `.gitlab-ci.yml`
# for GitLab repo `pinbox24/p24-v-3.2`.
#
# Faza 3D of docs/plans/w3-w4-cicd-full-deployment.md (issue radieu/p24-infra#3769),
# unblocked by #3542 (docker-compose-w3.yml committed to git). This is the
# GIT-TRACKED SOURCE OF TRUTH for the v32-prod build/deploy pipeline — the same
# pattern used for W4 (docs/bms-1/gitlab-ci-w4.yml, issue #3768): land the
# artifact in p24-infra first, then a human applies it to the GitLab repo
# (p24-infra has push/MR rights but NO merge rights on these app repos —
# docs/pinbox24/gitlab-repo-locations.md).
#
# BEFORE APPLYING: diff this against the repo's live `.gitlab-ci.yml`. Job names,
# stage names, the runner tag, and the ECR repo path must match reality. The live
# file contains existing jobs (prod-back-end-deploy, autoheal, etc.) that must be
# preserved or merged — do NOT overwrite blindly. Apply via the single-file PUT
# endpoint (see docs/playbooks/w3-gitlab-ci-image-pipeline.md), NOT the
# multi-action Commits API (which times out on this runner).
#
# --- Design decisions honored (issue #3769 scope, 2026-07-11) ---
# Gap 8 (W3): persistent patches (pushNotification.helper.js, mongoose.js,
#        crudService.js, filesUpload.js, twilioService.js) are NOT baked into
#        the image — they stay volume-mounted at runtime via
#        docker-compose-w3.yml. The build stage produces the plain app image.
#        NOTE (#4708, 2026-07-30): excel_import.js used to be listed here as a
#        6th patch. It is not one — it is a stock, git-tracked file in
#        pinbox24/p24-v-3.2 and IS present in the built image (build-dir,
#        mounted and image copies are byte-identical). Its mount is a redundant
#        no-op; Gap 8 covers 5 files, not 6.
# v32-prod-reso/socket: INCLUDED with nightly-window (20:00–06:00 UTC)
#        force-recreate, per #3740 verdict (real but marginal WebSocket usage —
#        1 active client, backend already 502s 99.6% of the time). These
#        containers use private-registry.dev.pinbox24.com/v32-prod (not ECR);
#        the nightly force-recreate picks up env file updates from the autoheal
#        step (#3611), not a new image build.
# Rollback: if pipeline fails after 4+ attempts, leave on the current image and
#        document as tech-debt (plan §Faza 3D). Do not over-engineer retry logic.
#
# --- Secrets ---
# NEVER hardcode credential values. AWS ECR auth uses GitLab CI/CD variables
# (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, protected+masked). Runtime app env is
# read from the SOPS-maintained env files the autoheal step (#3611) keeps populated
# in the builder dir — never sourced (special chars break `source`; use grep|cut).

stages:
  - build
  - deploy

variables:
  AWS_REGION: "eu-central-1"
  ECR_REGISTRY: "563740926945.dkr.ecr.eu-central-1.amazonaws.com"
  IMAGE_REPO: "v32-prod"
  # Builder checkout dir on the bms-1 shell runner (matches docker-compose-w3.yml).
  BUILDER_DIR: "/home/gitlab-runner/builds/eZQeLfuJe/0/pinbox24/p24-v-3.2"
  COMPOSE_FILE: "/home/gitlab-runner/builds/eZQeLfuJe/0/pinbox24/p24-v-3.2/docker-compose-w3.yml"

# All jobs run on the bms-1 shell runner (register tag `v32-bms1-autodeploy` on the
# runner — same pattern as `mailgun-bms1-autodeploy` / `s3-v2-bms1-autodeploy`,
# Faza 1, and `v42-bms1-autodeploy` from Faza 3C / #3768).
default:
  tags:
    - v32-bms1-autodeploy

# --------------------------------------------------------------------------------
# BUILD — produce the v32-prod app image and push to ECR.
# Patches are NOT copied in (Gap 8); Dockerfile builds the plain JS app only.
# Verify the default branch name before applying — likely "development" or "master".
# --------------------------------------------------------------------------------
build:v32-prod:
  stage: build
  rules:
    - if: '$CI_COMMIT_BRANCH == "development"'   # ← verify: adjust if W3 uses "master"
    - if: '$CI_PIPELINE_SOURCE == "web"'         # allow manual pipeline trigger
  script:
    - echo "Building v32-prod image (patches stay volume-mounted — Gap 8)"
    - aws ecr get-login-password --region "$AWS_REGION"
        | docker login --username AWS --password-stdin "$ECR_REGISTRY"
    - export IMAGE_TAG="merged-$(date -u +%Y%m%d-%H%M)-${CI_COMMIT_SHORT_SHA}"
    - docker build -t "${ECR_REGISTRY}/${IMAGE_REPO}:${IMAGE_TAG}" -f Dockerfile .
    # Retag current :latest as :old-<date> before overwriting — preserves a rollback target.
    - docker pull "${ECR_REGISTRY}/${IMAGE_REPO}:latest" || true
    - docker tag "${ECR_REGISTRY}/${IMAGE_REPO}:latest"
        "${ECR_REGISTRY}/${IMAGE_REPO}:old-$(date -u +%Y%m%d-%H%M)" || true
    - docker push "${ECR_REGISTRY}/${IMAGE_REPO}:old-$(date -u +%Y%m%d-%H%M)" || true
    - docker tag "${ECR_REGISTRY}/${IMAGE_REPO}:${IMAGE_TAG}"
        "${ECR_REGISTRY}/${IMAGE_REPO}:latest"
    - docker push "${ECR_REGISTRY}/${IMAGE_REPO}:${IMAGE_TAG}"
    - docker push "${ECR_REGISTRY}/${IMAGE_REPO}:latest"
    - echo "Pushed ${IMAGE_REPO}:${IMAGE_TAG} (and :latest)"

# --------------------------------------------------------------------------------
# DEPLOY v32-prod (manual) — operator runs this INSIDE the 20:00–06:00 UTC window.
# compose enforces env-file refresh (autoheal step #3611) and bind-mount patches.
# --------------------------------------------------------------------------------
.deploy_v32_script: &deploy_v32_script
  - echo "Deploying v32-prod via compose"
  - aws ecr get-login-password --region "$AWS_REGION"
      | docker login --username AWS --password-stdin "$ECR_REGISTRY"
  - docker compose -f "$COMPOSE_FILE" pull v32-prod
  # `up -d` (not `restart`) so the host env_file is re-read and volume-mount
  # patches (Gap 8) are applied from the compose file. Does not touch reso/socket.
  - docker compose -f "$COMPOSE_FILE" up -d v32-prod
  - sleep 15
  - docker ps --filter name=v32-prod --format '{{.Status}} {{.Image}}'
  # Health gate — fail the deploy if W3 API is not serving.
  - curl -sS -o /dev/null -w '%{http_code}\n' https://api.w3.pinbox24.com/api/i18n/langs | grep -q '^200$'
  # Post-deploy env resync (#3874). GitLab's checkout/`git clean` wipes the SSH-delivered
  # env files (backend-environment.env / s3-environment.env / redis-v32-environment.env) that
  # hold the ENTIRE runtime config — so the next container (re)start would boot with zero env
  # vars (root cause of the 2026-07-09 W3/W4 cascading outage). Re-trigger secrets-sync.yml so
  # those files are repopulated immediately after every deploy. Async dispatch (does not wait);
  # runs last so it never affects the health-gated deploy result. GH_TOKEN is a masked CI/CD
  # variable already provisioned on the bms-1 runner (Faza 1) — read from env by `gh`, never inlined.
  - gh workflow run secrets-sync.yml --repo radieu/p24-infra -f target=bms1-all

deploy:v32-prod:
  stage: deploy
  when: manual
  rules:
    - if: '$CI_COMMIT_BRANCH == "development"'   # ← adjust to match W3 default branch
  script: *deploy_v32_script

# Schedule-gated variant — attach a CI schedule set to the 20:00–06:00 UTC window.
# Hands-off nightly rollout; only fires on schedule triggers.
deploy:v32-prod:nightly:
  stage: deploy
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
  script: *deploy_v32_script

# --------------------------------------------------------------------------------
# DEPLOY v32-prod-reso + v32-prod-socket (nightly only, per #3740 verdict).
# These containers use private-registry.dev.pinbox24.com/v32-prod — not ECR.
# Force-recreate in the nightly window to pick up env-file updates (autoheal);
# NOT a new image build — they use whichever private-registry image is cached.
# --------------------------------------------------------------------------------
deploy:v32-prod-reso-socket:nightly:
  stage: deploy
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule"'
  script:
    - echo "Force-recreating v32-prod-reso and v32-prod-socket in nightly window (#3740)"
    # No ECR login needed — images from private-registry.dev.pinbox24.com.
    # `up -d` picks up the current cached image and refreshes env_file + bind-mounts.
    - docker compose -f "$COMPOSE_FILE" up -d v32-prod-reso v32-prod-socket
    - sleep 10
    - docker ps --filter name=v32-prod-reso --format '{{.Status}} {{.Image}}'
    - docker ps --filter name=v32-prod-socket --format '{{.Status}} {{.Image}}'
    # Post-deploy env resync (#3874) — this force-recreate also re-reads env_file, so keep the
    # reso/socket nightly deploy consistent with the backend deploy: repopulate any env files a
    # prior `git clean` may have wiped. Async, non-blocking; GH_TOKEN from the runner env.
    - gh workflow run secrets-sync.yml --repo radieu/p24-infra -f target=bms1-all
