Skip to content

Andrea redesign: Step 7, cutover substeps 5–8

Justin authorized merge and production cutover on September 27, 2026, after reviewing the production-image rehearsal. The old preparation handoff remains the source for the original backup and rollback image IDs.

This is a completed release record, not a procedure to rerun. The one-time cutover, configuration-transform and collection-relabel helpers have been removed from the active tree. They remain in Git at the exact deployed release. Use the normal deployment runbook for later releases and the redesign story for the narrative overview.

Release boundary

Deploy only the portfolio and storefront. Keep the existing Medusa image, PostgreSQL, Redis, Garage, credentials, media URLs, accounts, carts and volumes. No migration, bootstrap, reseed, payment processing, account enablement or legacy-bookmark compatibility is part of this cutover. The conservative all-apps plan is intentionally narrowed to avoid rebuilding the backend for maintenance-script-only changes.

The already configured store WhatsApp destination is reused for architecture and landing contact links. Neither destination nor inquiry email is invented or printed. The private environment changes only the apex storefront URL, empty basePath, /guanza asset prefix and missing architecture contact setting.

Staging and privileged cutover

The two configuration-preparation scripts produce new files rather than editing the live settings. They reject an unexpected environment or apex configuration. Nginx changes preserve the existing Certbot TLS settings, security/privacy headers, robots policy, and API/Admin/media virtual hosts byte-for-byte outside the apex locations. Both frontend images must be built against the staged private environment and tagged with the exact merged commit before cutover.

For later releases, capture a private backup with capture-production-backup.sh --capture and verify its off-server copy before switching applications. Avoid concurrent catalog editing. The PostgreSQL restore check remains isolated; Garage full recovery is not rehearsed. Never restore a database just to roll back frontend code.

The VPS deployment user requires interactive sudo for Nginx. Do not bypass that requirement through Docker, weaken permissions, or ask for a password in chat. The operator ran scripts/cutover-redesign.sh interactively in the exact uploaded release directory with these arguments (historical command):

bash scripts/cutover-redesign.sh \
  /opt/andreaweb/shared/redesign-production-COMMIT12.env \
  /opt/andreaweb/shared/backups/EXACT_REFRESHED_BACKUP \
  FULL_MERGED_COMMIT

The helper authenticates before live writes, checks the backup/current-release identity, validates Nginx before reload, replaces only the two prebuilt frontends, verifies loopback/public routes, and records each application's actual release. An error during the switch restores the old frontends, environment and Nginx; it does not touch commerce data. A brief interruption while replacing the two applications and reloading Nginx is possible.

cutover-redesign.sh is a one-time transition helper, not the ongoing deployment entry point. Now that the route/environment contract is installed, future releases use the normal scripts/deploy-ovh.sh plan / apply workflow. Do not rerun this helper with the pre-cutover backup or old configuration. It has now been removed from the active tree; Git history retains the cutover procedure. Keep the private rollback artifacts separately.

For current read-only verification, run node scripts/check-release.mjs --production and check product images, guest-cart/language continuity and contact redirects in a browser. Do not send real inquiries or place an order as a smoke test.

Separate collection maintenance

apps/backend/src/scripts/relabel-origenes.ts was an explicit Medusa-module maintenance operation, not a migration or startup action. It changes only the existing guanza collection's title to Orígenes, rejects unexpected titles, and verifies that the ID, handle and product assignments stayed the same. It did not create a duplicate collection. It ran once using the existing backend image with the reviewed script mounted read-only for medusa exec, preserving the normal production configuration without starting another backend server. It is retired now that the title-only operation is complete.

Andrea should select Orígenes in Medusa's Collection field for these pieces, or Piezas Intervenidas for the separate artist-reimagined collection. The internal guanza handle remains an intentional compatibility/data contract, not a collection Andrea needs to recreate. Clearly marked samples remain removable through Admin.

Dependency triage / remaining risk

The full portfolio audit exposed react-server-dom-webpack 19.2.6, which was incorrectly outside the earlier --omit=dev audit's coverage: the portfolio ships its development dependencies and uses the RSC runtime. Before promotion, React, React DOM and the matching server-components package are patched together to 19.2.8 for GHSA-wx67-qw84-cm4g. An --omit=dev result alone is not an audit of this portfolio runtime image. Other bundled toolchain findings remain separately recorded; do not call the portfolio's full dependency tree clean. The deployment uses vinext start, not the development server, and runs on Linux with no public build/upload tool.

The backend still reports 69 high and 11 moderate production audit findings, propagated through seven underlying dependency groups. Its package/lockfile and running image are unchanged by this frontend cutover. Inspection found Admin authentication registered before the upload-specific Multer middleware; an unauthenticated POST to the live /admin/uploads returned 401. The examined Medusa UUID request-ID path uses v4, not the affected buffer-taking v3/v5/v6 functions. These limited checks do not prove all findings unreachable.

Multer, lodash, qs, CSV import, Ajv and logging dependency findings need a separate patch/test pass; no crafted exploit requests were sent to production. The frontend redesign neither exposes account controls nor adds backend upload routes. Retaining the old backend is risk containment, not a security waiver or a claim that the entire stack/OS images are security-cleared. See the original release-preparation handoff and upstream advisories for the audit details.

Execution status

Live and verified on September 27, 2026. The exact application release is 0f56ca8156ef96068bd0ded5fa5b833c9e4c742f, uploaded to /opt/andreaweb/releases/0f56ca8156ef. Later documentation-only commits do not change these built artifacts or the deployment identity.

  • Portfolio image: sha256:719c1ec8f5a5a59c7218f6ff0d65bacf8524aa99009a1507ace3bca05217d1a5.
  • Storefront image: sha256:2f8b72aaa5abe64b3e492cc13e1d4ee51e416d9b744875bebb258d4d0bd6dee9.
  • Both images are tagged 0f56ca8156ef. The portfolio image's RSC package was checked directly and is 19.2.8; storefront runtime/full-install audits are zero.
  • Private candidate environment: /opt/andreaweb/shared/redesign-production-0f56ca8156ef.env (0600).
  • Staged, reviewed Nginx site: /opt/andreaweb/shared/redesign-nginx-0f56ca8156ef.conf.
  • Refreshed private backup: /opt/andreaweb/shared/backups/redesign-20260927T192130Z-ucS3UQ.
  • Verified off-server copy: /home/justin/.local/state/andreaweb/backups/redesign-20260927T192130Z-ucS3UQ.

Checks passed: 22 portfolio tests, 41 storefront tests, three cutover transformation tests, lint (12 existing portfolio image warnings), backend maintenance-script build, formatter, and shell syntax. The refreshed PostgreSQL dump restored successfully with 15 products in an isolated temporary container; checksums passed on the VPS and the off-server copy. No database was restored over live data. Garage full restore remains untested.

The exact staged images were started temporarily on loopback-only ports 3300 and 3400 with the real production configuration/catalog. Read-only checks passed for /, English architecture, Guanza, Orígenes, English Piezas Intervenidas, cart and a real image from media.andreazambrano.co; no local-only media URLs appeared. Those temporary containers were removed. All six original production services remained healthy. No guest cart, account, order or inventory was changed by these checks. The backend image/lockfile has no change from the old release.

The portfolio full audit remains at 20 findings (14 high, five moderate, one low), versus zero with --omit=dev; its image includes tooling classified as development dependencies, so record the full result too. The directly relevant RSC finding was patched before staging. Broader toolchain and the unchanged backend's 80 findings remain follow-up work, not a clean security attestation.

Completed operator action: Justin ran the following bounded switch in his own terminal, supplying interactive sudo there (never in chat). Nginx syntax validation and the helper's cutover verification succeeded:

ssh -t ovh "cd /opt/andreaweb/releases/0f56ca8156ef && bash scripts/cutover-redesign.sh /opt/andreaweb/shared/redesign-production-0f56ca8156ef.env /opt/andreaweb/shared/backups/redesign-20260927T192130Z-ucS3UQ 0f56ca8156ef96068bd0ded5fa5b833c9e4c742f"

The final checks confirmed:

  • /opt/andreaweb/current resolves to /opt/andreaweb/releases/0f56ca8156ef. Web/storefront release markers contain the full deployed commit; Medusa's marker remains aebdc81d8bda. Both frontend image IDs match the artifacts above; the existing Medusa image remains sha256:d2cd9165517cb098f63ca30cdc9500f05094a4b25efde4aef1439a916bc58b4b.
  • All six services are healthy. The mounted persistent volumes remain andreaweb_postgres_data, andreaweb_redis_data, andreaweb_garage_data and andreaweb_garage_meta. Service uptime changed during the operator's session; do not interpret frontend-only scope as proof that no other service restarted.
  • The title-only Medusa script ran successfully in a disposable execution container using the existing backend image and read-only script mount. Collection pcol_01M20YRTCSXB92CAD32JJGD9WD is now Orígenes; its handle remains guanza, and the script verified identical product assignments. Piezas Intervenidas remains a separate existing collection. The Store API lists 10 published products, including the four clearly marked samples; the earlier backup restore count of 15 includes the database's broader product records.
  • check-redesign-release.mjs --production passed for both languages, landing, architecture, Guanza, both collections, carts, built assets, social images, API ownership and the missing-collection 404.
  • An isolated Chromium session loaded the live landing, architecture and real product/media URLs successfully. Desktop (1440 × 900) and phone-sized (390 × 844) landing screenshots were reviewed, with no horizontal overflow on the phone-sized page. The live Bowl page shows Orígenes, its actual media and purchase controls. No browser page errors were observed.
  • A sample was added to a disposable guest cart. Switching Spanish to English preserved the same cart cookie, quantity and COP 80,000 price; item removal returned the cart to empty. Ordinary cart-link navigation was verified after initial test-selector/time-out issues. No account, order or payment was created.
  • Same-origin contact and cart-inquiry POST checks returned 303 to wa.me; redirects were not followed, and no message was sent. The cart email link rendered the existing configured destination and summary; no email was sent.

Cutover substeps 5–8 are complete. Final Andrea artwork/content approval, real-device/touch review and the separately recorded dependency remediation remain follow-up work; they are not implied by these bounded deployment checks.