Athena — ops/interimplaza-rename-plan.md

Rename plan: mahmoud-consultancyinterimplaza

Status: APPROVED FOR PHASED EXECUTION (planning doc, updated 2026-05-29). This pass is still read-only — no renames, PRs, 1P writes, or git/ns mutations performed here. The owner has approved the §(b) P3 8-step procedure and made three sequencing decisions (below); this document now carries the exact owner click-paths and re-seal/DB commands so execution can fire back-to-back.

Owner decisions (2026-05-29, this revision):

  1. P3 approved — the full k8s namespace + chart + 1P-item + DB rename is in scope, brief downtime accepted, owner-gated. (Earlier "SKIP P3" recommendation overruled; carried over from v2.)
  2. O1 + O2 (1P item renames + re-seal) execute NOW, in parallel with the auditPic team-dashboard work, so P2/P3-staging can fire back-to-back the moment PR-A merges. They were the long-pole owner actions — front-loading them removes the wait.
  3. DB rename is now INCLUDED (no longer optional): recruitment_dbinterimplaza_db, via the fresh-install + pg_dump/pg_restore path in P3 step 4/restore (not a live ALTER DATABASE). See §(b) P3 DB-rename procedure.
  4. PROD ns-swap window is DEFERRED — a separate owner decision taken once the staging swap is done and verified. (Was O3; stays deferred.)

The exact owner-facing 1P rename steps (web UI click-path and op item edit CLI), the O2 re-seal flow, and the DB rename/pg_dump procedure are in §(b) P3 below; the reordered owner-action list is in §(c.1).

Prepared by: adhoc-interimplaza-rename-plan (one-shot swarm agent), revised by -v2, then -v3 (this revision — owner approval + exact 1P/DB steps).


0. TL;DR + premise corrections

The thing called "mahmoud-consultancy" is only a repo name + a GHCR image path + a local directory name + workspace prose. Two premises in the original task brief are wrong and change the plan materially:

  1. The repo is already under mahmoudholding, not theroomyapp. git remote -vhttps://github.com/mahmoudholding/mahmoud-consultancy.git. gh repo view theroomyapp/mahmoud-consultancy → resolves (via GitHub's redirect) to mahmoudholding/mahmoud-consultancy. So the repo was already transferred to the holding org at some earlier point; theroomyapp/... references in the swarm prompts and root CLAUDE.md are stale redirects that still happen to work. → Owner decision (i) "keep under theroomyapp or transfer to mahmoudholding" is moot — it is already on mahmoudholding. The rename command is gh repo rename interimplaza --repo mahmoudholding/mahmoud-consultancy.

  2. The k8s namespace is NOT mahmoud-consultancy. Staging is recruitment-staging, prod is recruitment, the Helm chart is recruitment-platform, and the 1P items are recruitment-platform-secrets-*. None of these contain the literal mahmoud-consultancy. So a repo rename does not force a namespace/chart/secret rename — those are an entirely separate, much riskier piece of work (see P3). Per owner override (2026-05-29) P3 is now in scope (downtime accepted), executed as its own backup→re-seal→reinstall migration after P1/P2.

Net: the literal token mahmoud-consultancy (or mahmoud_consultancy) appears in 259 files, but the operationally-load-bearing occurrences are a short list (≈10 files). The other ~250 are docs, archived session reports, and swarm/bus history — cosmetic, batchable, and mostly safe to leave or sweep lazily.


(a) Enumeration of references, grouped

Group A — Operationally load-bearing (the literal mahmoud-consultancy)

These actually break / change behaviour if the repo or image path changes.

| # | File | Reference | What it controls | |---|------|-----------|------------------| | A1 | (local) git remote | https://github.com/mahmoudholding/mahmoud-consultancy.git | push/pull target | | A2 | mahmoud-consultancy/helm/recruitment-platform/values.yaml:15 | ghcr.io/mahmoudholding/mahmoud-consultancy/backend | backend image pull | | A3 | …/values.yaml:19 | ghcr.io/mahmoudholding/mahmoud-consultancy/frontend | frontend image pull | | A4 | …/values.yaml:366 | ghcr.io/mahmoudholding/mahmoud-consultancy/cv-service | cv-service image pull (optional component, off by default) | | A5 | .github/workflows/ci-backend.yml:15 | IMAGE: ghcr.io/mahmoudholding/mahmoud-consultancy/backend | image push (CI) | | A6 | .github/workflows/ci-frontend.yml:19 | IMAGE: …/mahmoud-consultancy/frontend | image push (CI) | | A7 | .github/workflows/deploy-backend.yml:27 | IMAGE: …/mahmoud-consultancy/backend | image ref used in CD | | A8 | .github/workflows/deploy-frontend.yml:27 | IMAGE: …/mahmoud-consultancy/frontend | image ref used in CD | | A9 | package.json:47 | git+https://github.com/glorylabs/recruitment-platform.git | STALE repo URL (points at neither org — pre-existing bug, fix opportunistically) | | A10 | local directory mahmoud-consultancy/ | dir name | every cd, every script path, swarm start-claude.sh PROJECTS array |

Note: the GHCR image org stays mahmoudholding. Only the middle segment mahmoud-consultancyinterimplaza changes: ghcr.io/mahmoudholding/interimplaza/{backend,frontend,cv-service}.

Group B — Internal chart/namespace tokens that DON'T contain mahmoud-consultancy

These use recruitment-platform / recruitment-staging / recruitment / recruitment-platform-secrets-*. They do not need to change for a repo rename. They are listed only so the owner understands the namespace decision (P3) is independent. Touching them is the high-risk path:

  • Helm chart name + all _helpers.tpl template names (recruitment-platform.*), every templates/*.yaml, values.yaml, values-local.yaml.
  • Namespaces in deploy-backend.yml:66, deploy-frontend.yml:73 (NS="recruitment-staging"), and recruitment (prod) across rotation workflows (rotate-db-password.yml, rotate-jwt.yml, rotate-redis-password.yml), disaster-recovery.md, setup-vps.sh.
  • 1P items recruitment-platform-secrets-{production,staging} (vault InterimPlaza), seal-secrets.sh, backend-secret name recruitment-platform-backend-secret.

Group C — Workspace control plane (root, swarm, launcher)

Cosmetic-but-coordinating; update so the fleet/docs refer to the new name.

| File | Reference | |------|-----------| | CLAUDE.md (root) | corporate structure table, port registry row, Ingress/Issues table (theroomyapp/mahmoud-consultancy) | | start-claude.sh:27 | PROJECTS=( … mahmoud-consultancy … )functional: launcher iterates this | | .swarm/designqa-eligible:7 | mahmoud-consultancyfunctional: design-QA rotation list | | .swarm/inbox/mahmoud-consultancy | inbox dir name — functional if renamed | | .swarm/DOD-PROMPT.md (lines 15, 31, 39) | project list + theroomyapp/mahmoud-consultancy repo map | | .swarm/BUSINESS-PROMPT.md (lines 19, 32, 49) | project list + repo map | | .swarm/BUS-PROTOCOL.md:9 | workers list | | SWARM.md | project references | | .swarm/pending/post-refocus-multi-arch-fleet.task | task body mentions it | | .swarm/sanity-eligible | NOT present (mahmoud-consultancy is not yet in the sanity rotation — only valideerleeftijd, claimio) |

Note: sanity-eligible does not list mahmoud-consultancy, so no sanity rotation change needed.

Group D — Documentation (workspace docs/, ocs/, repo docs/)

Large but low-risk; batch sed + review. Live (non-archive) docs:

  • Root workspace: docs/README.md, docs/mahmoud-consultancy/README.md, docs/mahmoud-consultancy/compliance/README.md, docs/mahmoud-consultancy/disaster-recovery.md, docs/mahmoud-consultancy/frontend-setup.md, docs/definition-of-done.md, docs/ci-cd-reference.md, docs/mvp-readiness.md, docs/dod-compliance.md, docs/human-actions.md, docs/claude-github-app-setup.md, docs/ops/ci-alternatives-proposal.md, docs/ops/node-capacity-guardrail-proposal.md.
  • Compliance: ocs/README.md, ocs/mahmoud-consultancy/README.md.
  • In-repo: mahmoud-consultancy/README.md, mahmoud-consultancy/CLAUDE.md (lines 117/146/166: namespace, GHCR path, 1P items), mahmoud-consultancy/CURRENT_TASK.md, …/docs/frontend-setup.md, …/docs/compliance/README.md, …/docs/interimplaza/Execution/…, …/website/website/src/pages/contact.astro, …/bin/readme.md.
  • Cross-repo doc mentions: auditPic/docs/architecture.md, auditPic/docs/CLUSTER_ACCESS.md, claimio/docs/CLUSTER_ACCESS.md, valideerleeftijd/{CLAUDE.md,PLAN.md,docs/*}, europeLogin/CLUSTER_ACCESS.md, developer-portal/{README.md,consultancy.html,docs/workspace/*}.
  • The directory paths themselves: docs/mahmoud-consultancy/, ocs/mahmoud-consultancy/ (rename dirs → interimplaza/).

Group E — Frozen history (DO NOT TOUCH)

Leave as-is; rewriting history is noise and risks. ~200 of the 259 files:

  • mahmoud-consultancy/docs/archive/**, mahmoud-consultancy/bin/SESSION_*, docs/mahmoud-consultancy/archive/**, mahmoud-consultancy/archive/old-directories/**.
  • .swarm/bus.log, .swarm/logs/*.log, glorylabs/logs/*, HANDOFF-2026-05-19.md, HANDOFF-2026-05-20.md, docs/audit-2026-05-18.md, interimplaza.zip (already named interimplaza — a prior export).
  • .idea/*, .obsidian/workspace.json, e2e-results/* (regenerated).

(b) Phases with risk

P1 — Low risk, parallel-safe (repo + workspace rename)

GitHub keeps a redirect on rename, so nothing breaks instantly.

  1. gh repo rename interimplaza --repo mahmoudholding/mahmoud-consultancy (GitHub auto-redirects old URL → no immediate breakage).
  2. git -C mahmoud-consultancy remote set-url origin https://github.com/mahmoudholding/interimplaza.git
  3. Rename local dirs: mahmoud-consultancy/interimplaza/, docs/mahmoud-consultancy/docs/interimplaza/, ocs/mahmoud-consultancy/ocs/interimplaza/, .swarm/inbox/mahmoud-consultancy.swarm/inbox/interimplaza.
  4. Update workspace control plane (Group C): start-claude.sh PROJECTS, .swarm/designqa-eligible, swarm prompts, root CLAUDE.md, SWARM.md. Fix the stale theroomyapp/mahmoudholding/interimplaza while here.
  5. Update workspace + repo docs (Group D) via batched sed, then eyeball diffs.
  6. Fix stale package.json repo URL (A9) → mahmoudholding/interimplaza.

Risk: low. No running workload touched. Redirect covers any missed git URL. Worktree-isolatable; reversible by renaming back.

P2 — Medium risk (GHCR image path flip — order matters)

The CD pull path and the CI push path must both point at the new image, and an image must EXIST at the new path before CD references it, or the next deploy pulls a 404.

  1. Push images to the new path first (build once under ghcr.io/mahmoudholding/interimplaza/{backend,frontend}), OR re-tag/copy existing mahmoud-consultancy/* images to interimplaza/* (crane/skopeo).
  2. Flip IMAGE: env in ci-backend.yml, ci-frontend.yml, deploy-backend.yml, deploy-frontend.yml and repository: in values.yaml (A2–A8) in ONE PR.
  3. Confirm imagePullSecrets/GHCR visibility on the new path (new package = may default to private; grant the same pull token).
  4. Deploy to staging (recruitment-staging) and verify /actuator/health + pods Ready before letting prod CD run.
  5. Leave the old mahmoud-consultancy/* packages in GHCR for a cooldown (cheap rollback), delete later.

Risk: medium. Mitigated by push-before-flip ordering, staging-first, and keeping old images. Helm chart name (recruitment-platform) is NOT changed here — release name stays the same so helm upgrade stays in-place.

P3 — HIGH risk (full namespace + chart + 1P-item + DB rename) — IN SCOPE (owner override 2026-05-29, downtime accepted)

This is a backup→re-seal→reinstall migration, not an in-place edit. Sealed secrets and PVCs do not move across namespaces, so the new namespace is built fresh alongside the old one and the old one is deleted only after the new one is verified serving. Staging first, then prod in a separate owner-gated window.

Full P3 scope — exact tokens to change (verified against the chart, 2026-05-29)

| Layer | From | To | |---|---|---| | Helm chart dir | helm/recruitment-platform/ | helm/interimplaza/ | | Chart.yaml name: | recruitment-platform (v1.0.0) | interimplaza | | _helpers.tpl template defines | recruitment-platform.{name,fullname,chart,labels,selectorLabels,serviceAccountName} | interimplaza.{…} (all 6 defines + every {{ include "recruitment-platform.* }} call in templates/*.yaml) | | Derived fullname (used for Deployment/Service/SA/Secret names) | recruitment-platform-* (because nameOverride/fullnameOverride are both empty → fullname = chart name) | interimplaza-* | | Bitnami subchart service hosts | recruitment-platform-postgresql, recruitment-platform-redis-master (values.yaml:197,211) | interimplaza-postgresql, interimplaza-redis-master (these track the release name — re-point backend database.host/redis.host accordingly) | | Backend secret name | recruitment-platform-backend-secret (backend-secret.yaml, seal-secrets.sh:41, bitnami existingSecret at values.yaml:296,336) | interimplaza-backend-secret | | k8s namespace (staging) | recruitment-staging (deploy-backend.yml:66, deploy-frontend.yml:73, seal-secrets.sh:46) | interimplaza-staging | | k8s namespace (prod) | recruitment (rotation workflows, disaster-recovery.md, setup-vps.sh, seal-secrets.sh:44) | interimplaza | | 1P items (vault InterimPlaza) | recruitment-platform-secrets-{production,staging} | interimplaza-secrets-{production,staging} | | seal-secrets.sh defaults | OP_VAULT=InterimPlaza (unchanged), OP_ITEM=recruitment-platform-secrets-${ENV} (:50), SECRET_NAME=recruitment-platform-backend-secret (:41), NAMESPACE=recruitment[-staging] (:44,46) | item → interimplaza-secrets-${ENV}; secret → interimplaza-backend-secret; ns → interimplaza[-staging] | | DB name | recruitment (values.yaml:199, bitnami postgresql.auth.database=recruitment at :290) — DOES contain the old token | interimplaza_dbNOW INCLUDED (owner decision 2026-05-29, decision (v) flipped to "yes"). ⚠️ Verified current name is recruitment (not recruitment_db) — owner's target interimplaza_db is the new name; confirm the owner doesn't instead want bare interimplaza to match the ns/role convention. See DB-rename procedure below. |

DB-rename note (owner decided 2026-05-29: INCLUDE the name rename): the database name is recruitment and the bitnami admin user / Flyway user is recruitment, with a DML app role recruitment_app. The role names are baked into Flyway migrations (V008__app_role.sqlCREATE ROLE recruitment_app, V010__app_role_password.sql, and the ALTER ROLE "recruitment" WITH CREATEROLE init SQL at values.yaml:315).

  • DB name rename (recruitmentinterimplaza_db)IN SCOPE. Do not use a live ALTER DATABASE … RENAME (Postgres requires zero active connections to that DB). Instead use the fresh-install + dump/restore path: let the new-ns bitnami install create the DB under the new name, pg_dump the old DB before deleting the old ns, and pg_restore/psql into the new DB. The data dump is portable across DB names. Full commands + the brief data-frozen window are in the DB-rename procedure immediately below.
  • DB role names (recruitment, recruitment_app)leave as-is. Renaming them means rewriting committed Flyway history (forbidden) or adding ALTER ROLE … RENAME migrations + re-pointing every grant; zero external benefit, internal-only labels. Flag as explicitly out of scope for P3. (So: DB name changes to interimplaza_db; the owning role stays recruitment — set bitnami postgresql.auth.username=recruitment and postgresql.auth.database=interimplaza_db in the new-ns values.)

DB-rename procedure (recruitmentinterimplaza_db, dump/restore, data-frozen window)

Folded into P3 step 4 / the restore. Runs per env (staging first). The dataset is small on staging, so the freeze window is < 5 min.

  1. Set the new DB name in the new-ns values (part of the P3 PR): bitnami postgresql.auth.database: interimplaza_db (keep username: recruitment), and re-point the backend database.name/JDBC URL to interimplaza_db. The fresh helm install (step 4) then creates an empty interimplaza_db owned by role recruitment, and Flyway runs its migrations into it.

  2. FREEZE — scale the OLD backend to 0 so no writes land during the dump (this opens the data-frozen window):

    kubectl -n recruitment-staging scale deploy/recruitment-platform-backend --replicas=0
    
  3. Dump the OLD DB (this is the step-1 backup of the 8-step, now naming the target DB explicitly):

    kubectl -n recruitment-staging exec recruitment-platform-postgresql-0 -- \
      bash -c 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dump -U recruitment -d recruitment \
        --no-owner --no-privileges -Fc' \
      > /tmp/interimplaza-staging-$(stamp).dump
    

    (-Fc custom format → use pg_restore; or drop -Fc for plain SQL → use psql. Either is DB-name-agnostic, which is exactly why the rename is safe.)

  4. Restore into the NEW DB in the new ns (after step 4 helm install brought interimplaza-postgresql up with an empty interimplaza_db):

    kubectl -n interimplaza-staging exec -i interimplaza-postgresql-0 -- \
      bash -c 'PGPASSWORD="$POSTGRES_PASSWORD" pg_restore -U recruitment \
        -d interimplaza_db --no-owner --no-privileges' \
      < /tmp/interimplaza-staging-*.dump
    

    (Plain-SQL variant: … psql -U recruitment -d interimplaza_db < dump.sql.) Flyway may have already created the schema on install; if the restore conflicts, restore into a DB created with helm install … --set backend.flyway.enabled=false (or scale backend to 0 during install) so the dump is the sole source of schema+data, then scale up.

  5. UNFREEZE — verify the new ns serves (8-step step 5), then end the freeze: the new backend is already at its normal replica count from helm install; the OLD backend stays at 0 (it is about to be deleted in step 7). Total data-frozen window = dump + restore + verify ≈ < 5 min on staging (small dataset). Prod's window is sized in its own deferred decision but expected to stay a few minutes given the dataset size.

The freeze exists so the dump is a consistent point-in-time copy with no writes lost between dump and cutover. Because the OLD ns is deleted only at step 7 (after the NEW ns is verified), a failed restore is a zero-data-loss fallback: scale the OLD backend back to 1 and you are exactly where you started.

Owner-action-NOW: exact 1P item rename (O1) + re-seal flow (O2)

Scheduled NOW, in parallel with the auditPic team-dashboard work (owner decision 2026-05-29) so P2/P3-staging can fire back-to-back once PR-A merges. Vault, item, and secret names below are verified against mahmoud-consultancy/scripts/seal-secrets.sh (vault InterimPlaza; items recruitment-platform-secrets-{staging,production}; secret recruitment-platform-backend-secret; namespaces recruitment[-staging]). Do the staging item now; the production item waits for its deferred window (O3).

O1 — rename the 1P items. Either path works; the field names inside each item are unchanged, so nothing else in the item needs editing.

Option A — 1Password web UI (click-path):

  1. Sign in to https://mahmoudholdingbv.1password.com.
  2. Open the InterimPlaza vault (left sidebar).
  3. Find the item recruitment-platform-secrets-staging (search box top-left).
  4. Open it → click the three-dot (⋯) menu top-right → Edit.
  5. Click the title field and change it to interimplaza-secrets-staging.
  6. Click Save.
  7. Repeat for recruitment-platform-secrets-productioninterimplaza-secrets-production only when the prod window opens (O3) — not now.

Option B — op CLI (requires an authenticated op session — op signin, or OP_SERVICE_ACCOUNT_TOKEN with write scope):

# staging (do now):
op item edit "recruitment-platform-secrets-staging" \
  --vault "InterimPlaza" \
  --title "interimplaza-secrets-staging"

# production (defer to the prod window, O3 — do NOT run now):
op item edit "recruitment-platform-secrets-production" \
  --vault "InterimPlaza" \
  --title "interimplaza-secrets-production"

Verify: op item get "interimplaza-secrets-staging" --vault "InterimPlaza" --format json | jq .title.

O2 — re-seal once the item is renamed. The seal script reads the item name from OP_ITEM (default recruitment-platform-secrets-${ENV}, seal-secrets.sh:50). Two ways to make it read the new name:

  • Now / quick (no code change): pass OP_ITEM inline (the script honors the env override), regenerating the staging sealed manifest from the renamed item but still targeting the OLD ns recruitment-staging (the manifest is ns-scoped and the NEW ns doesn't exist yet — that re-seal happens in 8-step step 3):

    cd mahmoud-consultancy
    OP_SERVICE_ACCOUNT_TOKEN=<token> \
      OP_ITEM=interimplaza-secrets-staging \
      ./scripts/seal-secrets.sh staging
    # → regenerates k8s/sealed-secrets/backend-secrets-staging.yaml, ns=recruitment-staging
    git add k8s/sealed-secrets/backend-secrets-staging.yaml
    git commit -m "chore(secrets): re-seal staging from renamed 1P item interimplaza-secrets-staging"
    

    This keeps the OLD ns deployable from the renamed item right now, decoupled from the ns swap.

  • In the P3 PR (permanent): edit seal-secrets.sh:50 default OP_ITEM=recruitment-platform-secrets-${ENV}OP_ITEM=interimplaza-secrets-${ENV} (and, when the ns/chart rename lands, SECRET_NAME :41interimplaza-backend-secret and NAMESPACE :44,46interimplaza[-staging]). After that edit, a plain ./scripts/seal-secrets.sh staging reads the new item with no inline override.

Ns scope reminder: the re-seal done NOW (above) targets the OLD ns recruitment-staging — correct for keeping the current release deployable. The NEW ns interimplaza-staging re-seal is a separate run done in 8-step step 3 (with OP_ITEM+SECRET_NAME+NAMESPACE all overridden to the new values), because a SealedSecret cannot be retargeted across namespaces by edit.

Destructive-order procedure (STAGING first, then PROD as a separate window)

Run for recruitment-staginginterimplaza-staging end-to-end and verify before even scheduling prod. The old namespace is the rollback artifact and is kept until step 7.

⏸️ DATA-FROZEN WINDOW (callout). Because the DB name rename is now in scope, step 1's dump must be a consistent point-in-time copy. The window opens when the OLD backend is scaled to 0 (no more writes) and closes when the NEW ns is verified serving (step 5). Target: < 5 min on staging (small dataset). The exact freeze/dump/restore commands are in the DB-rename procedure above; the 8-step below references them at steps 1 and 4. Prod's freeze is sized in its own deferred window decision (O3).

  1. FREEZE + backup the DB in recruitment-staging. Opens the data-frozen window: scale the OLD backend to 0 (kubectl -n recruitment-staging scale deploy/recruitment-platform-backend --replicas=0), then take a logical dump of Postgres (note any MinIO bucket if the optional object-store component were ever enabled — off by default here):

    # pod name: the bitnami postgres primary in the OLD ns
    kubectl -n recruitment-staging exec -it recruitment-platform-postgresql-0 -- \
      bash -c 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dump -U recruitment -d recruitment --no-owner --no-privileges' \
      > /tmp/interimplaza-staging-$(stamp).sql
    tar czf /tmp/interimplaza-staging-pgdump.tar.gz -C /tmp interimplaza-staging-*.sql
    

    Lands at: the operator's laptop /tmp/interimplaza-staging-pgdump.tar.gz (copy to the project's offline backup location before proceeding). Restore path (DB rename in scope): psql -U recruitment -d interimplaza_db < dump.sql into the NEW ns's postgres pod (data dump is DB-name-agnostic — that is what makes the recruitmentinterimplaza_db rename safe). See the DB-rename procedure above for the full freeze/dump/restore commands. Keep the dump until prod is also cut over and verified.

  2. OWNER renames the 1P items in the InterimPlaza vault. This is O1 and runs NOW (in parallel with the auditPic work) — see the exact web-UI click-path and op item edit CLI in **"Owner-action-NOW: exact 1P rename

    • O2 re-seal"** below. Rename the staging item now; the production item only when prod's deferred window opens. The owner also updates the seal script's OP_ITEM/SECRET_NAME/NAMESPACE references (these go in the P3 PR). Field names inside each item are unchanged.
  3. Re-seal secrets under the NEW item names into the NEW namespace. SealedSecrets are namespace-scoped — you must re-seal, never sed the namespace field (root CLAUDE.md forbids it; a re-targeted manifest cannot be decrypted). The O2 re-seal flow (run NOW for the OLD ns, re-run for the NEW ns at this step) is detailed in the same subsection below. With the owner's OP_SERVICE_ACCOUNT_TOKEN:

    kubectl create namespace interimplaza-staging
    OP_SERVICE_ACCOUNT_TOKEN=<token> \
      OP_ITEM=interimplaza-secrets-staging \
      SECRET_NAME=interimplaza-backend-secret \
      NAMESPACE=interimplaza-staging \
      ./scripts/seal-secrets.sh staging
    kubectl apply -f k8s/sealed-secrets/backend-secrets-staging.yaml   # now ns-scoped to interimplaza-staging
    
  4. helm install in the new namespace with the new chart name + new image path (from P2) + new secret name + new DB name (postgresql.auth.database: interimplaza_db, postgresql.auth.username: recruitment unchanged, backend database.name/JDBC URL re-pointed — all in the P3 PR's values):

    helm install interimplaza ./helm/interimplaza \
      -n interimplaza-staging \
      -f helm/interimplaza/values-staging.yaml
    

    (New chart name ⇒ new fullname ⇒ bitnami subcharts come up as interimplaza-postgresql / interimplaza-redis-master; backend config must already point at those hosts from the scope table.) Then restore the step-1 dump into the new interimplaza_db (DB-rename procedure step 4) before unfreezing — pg_restore/psql … -U recruitment -d interimplaza_db. If Flyway-on-install conflicts with the restore, install with backend scaled to 0 / Flyway disabled so the dump is the sole schema+data source, then scale up.

  5. Verify the new namespace serves before deleting anything:

    kubectl -n interimplaza-staging get pods            # backend 1/1, postgres/redis Ready
    kubectl -n interimplaza-staging exec deploy/interimplaza-backend -- \
      wget -qO- localhost:<containerPort>/actuator/health   # expect {"status":"UP"}
    
  6. DNS / ingress hostname is UNCHANGED — confirm only. Staging already uses interimplaza.staging.glorylabs.nl (values-staging.yaml:124,135) and prod uses the brand hosts (glorylabs.nl / www.glorylabs.nl, later app.interimplaza.nl). The ingress object is namespaced, so the new release recreates it in the new ns with the same Host: rules — no DNS change, no cert reissue needed (same hostnames → same TLS secret content, re-sealed in step 3 if it lived in the backend secret). Verify the new ingress has the address and the host responds.

  7. Delete the OLD recruitment-staging namespaceonly after step 5/6 confirm the new ns is fully serving real traffic:

    helm uninstall recruitment-platform -n recruitment-staging
    kubectl delete namespace recruitment-staging
    

    This drops the old PVCs; the step-1 dump remains the cold-backup.

  8. Repeat 1–7 for PROD (recruitmentinterimplaza) in its own owner-gated window — scale backend to 0 / accept the brief downtime while the new ns comes up and the dump restores. Prod uses the prod 1P item, prod values, and the prod hostnames; otherwise identical ordering.

Risk: high but bounded — old ns retained through step 6 means any failure before deletion is a zero-data-loss fallback to the still-running old release. Downtime is the deliberate cost the owner has accepted (mainly the prod cutover window in step 8).


(c) Owner decisions required before execution

| # | Decision | Recommendation | |---|----------|----------------| | (i) | Keep repo under theroomyapp or transfer to mahmoudholding? | Moot — already on mahmoudholding. Just rename in place; fix the stale theroomyapp/ strings in swarm prompts/CLAUDE.md while renaming. | | (ii) | Rename the k8s namespace too (P3) or skip? | DECIDED: EXECUTE P3 (owner override 2026-05-29, downtime accepted). Run the §(b) P3 backup→re-seal→reinstall procedure, staging first then prod in a separate window. | | (iii) | Timeline vs. letting the auditPic team-dashboard API land first? | Sequence after any in-flight auditPic team-dashboard work to avoid cross-repo churn, but P1 (repo/docs rename) is parallel-safe and could run anytime; only P2 (image flip) needs a quiet CD window. Recommend: do P1 now if convenient, schedule P2 for a deliberate staging-verified window. | | (iv) | (new) Re-tag existing GHCR images vs. rebuild under new path? | Re-tag/copy (crane/skopeo) is faster and preserves the exact deployed digest; rebuild is cleaner provenance. Either works — re-tag recommended for the cutover, rebuild on next normal CI run. | | (v) | Rename the DB name (recruitmentinterimplaza_db) during P3? | DECIDED: YES, INCLUDED (owner 2026-05-29). Via the fresh-namespace install creating a DB named interimplaza_db + pg_dump/pg_restore (no live ALTER DATABASE, which needs zero active connections). Brief data-frozen window (< 5 min staging). DB role names stay recruitment/recruitment_app (baked into Flyway — out of scope). See §(b) DB-rename procedure. |


(c.1) Explicit OWNER-ACTION list (cannot be automated)

These steps require the owner — credentials, irreversible go/no-go, or human-only 1P UI — and gate the rest of P3. Everything else (chart/file edits, helm install, kubectl) a worker can do once these are cleared. Scheduling (owner decision 2026-05-29): O1 + O2 run NOW, in parallel with the auditPic team-dashboard work (front-loaded so P2/P3-staging fire back-to-back when PR-A merges); O4 is now decided "yes" and folded into P3 (no longer a gate); O3 (prod window) stays deferred until the staging swap is verified.

Listed in execution order:

| # | Owner action | When | Why owner-only | |---|---|---|---| | O1 | Rename the 1P item(s) in vault InterimPlaza (exact web-UI click-path + op item edit CLI in §(b) "Owner-action-NOW"). Staging item recruitment-platform-secrets-staginginterimplaza-secrets-staging NOW; prod item only when O3's window opens. | NOW (staging) / P3 step 2 (prod) | 1P writes are owner-gated; no service-account write path in CI. | | O2 | Re-seal from the renamed item — provide OP_SERVICE_ACCOUNT_TOKEN (or run it personally). NOW: re-seal staging into the OLD ns from the renamed item (quick, decoupled). At P3 step 3: re-seal into the NEW ns. Both flows in §(b) "Owner-action-NOW". | NOW (old-ns) / P3 step 3 (new-ns) | Holds the only credential that reads the vault to seal. | | O4 | DB-rename: DECIDED YES — new-ns DB named interimplaza_db via dump/restore (decision (v)). No longer a go/no-go gate; remaining owner input is only confirming interimplaza_db vs. bare interimplaza as the final name. | folded into P3 step 4 | Schema/identity decision — owner confirms final DB name. | | O3 | Prod ns-swap go/no-go windowDEFERRED: decided separately once the staging swap is done and verified. Approve the brief prod downtime + freeze and pick the window for P3 step 8 (and the prod 1P-item rename). | DEFERRED — after staging swap; before P3 step 8 | Accepts the user-visible downtime; irreversible delete of old prod ns at step 7/8. |


(d) Rollback plan

  • P1 repo rename: gh repo rename mahmoud-consultancy --repo mahmoudholding/interimplaza to revert; GitHub redirect works in both directions. Local: git remote set-url back, mv dirs back. Docs/control-plane: git revert the PR.
  • P2 image flip: the previous image at the OLD path is retained (not deleted during cooldown) — revert the IMAGE:/repository: PR and redeploy; Helm release name unchanged so helm rollback also works to the prior revision. Verify on recruitment-staging before prod.
  • P3 (per step, old ns is the rollback artifact):
    • Steps 1–6 (before the old ns is deleted): the OLD release in recruitment[-staging] is still running and serving — abort by simply not cutting traffic / not deleting it; kubectl delete namespace interimplaza[-staging] to discard the half-built new ns and retry.
    • SealedSecret rollback artifact: the old ns's k8s/sealed-secrets/backend-secrets-${ENV}.yaml (scoped to recruitment[-staging]) stays valid for the old ns — it is the secret rollback. The re-sealed new-ns manifest is additive, not a replacement.
    • After step 7 (old ns deleted): rollback = kubectl create namespace recruitment[-staging], re-seal the old item into it (if 1P item still renamed, seal from the renamed item but with old SECRET_NAME/NAMESPACE), helm install recruitment-platform from the pre-P3 chart commit, and restore the step-1 pg_dump. Hence: keep the step-1 dump until prod is cut over and verified, and do prod (step 8) only after staging is proven.
    • 1P item rollback: op item edit (or web UI) to rename items back; trivial and reversible.
  • General: do P1, P2, and P3 as separate PRs (and P3-staging vs. P3-prod as separate windows) so each reverts independently. Keep old GHCR packages ≥1 week before deletion; keep old namespaces until the new ones are verified serving.

Suggested sequencing

Run NOW, in parallel (owner decision 2026-05-29): O1 (rename the staging 1P item) + O2 (re-seal staging into the OLD ns from the renamed item). These are independent of PR-A and front-loaded so the rest fires back-to-back the moment PR-A lands.

Gate for everything else: nothing in P2/P3 executes until the auditPic team-dashboard PR-A merges (itself gated on the org billing clear). Once that lands:

P1 (anytime, parallel-safe) → P2 (deliberate staging-verified CD window) → P3-staging (O1/O2 already done now; then re-seal-into-new-ns → FREEZE+dump → reinstall(new DB interimplaza_db)+restore → verify → unfreeze → delete old ns) → P3-prod (DEFERRED, separate owner-gated window: prod O1/O2 + O3 window + accepted downtime/freeze).

Recommended P3 ns-swap timing: a low-traffic owner-attended maintenance window — staging anytime after P2 is verified; prod is DEFERRED to a deliberate off-hours window (evening / weekend), decided once the staging swap is proven, with the owner present for the prod 1P-item rename + O3 + the brief cutover downtime/freeze.

Reacties

Nog geen reacties