Andrea redesign: Step 7, preparation substeps 1–4¶
Historical preparation record. Justin has since authorized substeps 5–8; see the completed cutover and verification record. The production switch and final checks completed on September 27, 2026. The preparation-only authorization and observations below are historical. Temporary filenames in this record belong to the original release. The spike and cutover transformers are retired; reusable backup/rehearsal/check tooling now has general names. Use local operations and the deployment runbook rather than replaying old commands.
Prepared September 27, 2026 in /home/justin/repos/AndreaWeb, branch
jm/andrea-redesign-1. This is the authoritative checkout; D:\git\AndreaWeb
is not the current repository.
Justin authorized preparation substeps 1–4 only, then a review before 5–8. No merge, push, production application replacement, live Nginx/environment change, collection rename, migration, reseed, or persistent-volume removal was performed. Creating private backups and an isolated restore check were the only VPS writes. The existing production services remained healthy.
1. Finish and commit the reviewed design¶
af7f0cb commits the pending galleries, variant selection, product viewport
layout, contact arrows, catalog-paper colors, compact collection spacing, and
opt-in preview media handling. Earlier commits already contain the height-aware
landing tiles and aligned related products.
The product/gallery handoff, layout review, and Steps 5–6 handoff describe the UI contracts and remaining artwork. The approved provisional/reference/sample labels remain. Final landing, carousel and portfolio artwork is not a deployment blocker per Justin's latest direction. Account access remains outside this release; see the account audit.
Legacy-link handling was explicitly deferred during this work. No new redirect bridge, category compatibility listing, account bridge, or old inquiry alias is included. Old bookmarks may fail or show retained old portfolio pages. There is no blanket redirect of old POST requests.
2. Prepare the production route/build contract¶
compose.prod.yaml, the storefront Dockerfile, environment generator/template,
and application health checks now describe the redesigned release:
| Setting | New value | Purpose |
|---|---|---|
STOREFRONT_BASE_URL |
https://andreazambrano.co |
Same-origin public URLs and metadata |
STOREFRONT_BASE_PATH |
empty | New /guanza and /en/guanza pages are application routes, not a Next basePath |
STOREFRONT_ASSET_PREFIX |
/guanza |
Isolate Next assets from the portfolio's root assets |
| Portfolio health | / |
Check the new landing |
| Storefront health | /guanza |
Check the real new store entry |
The asset prefix is supplied at both build and runtime. Compose no longer
turns an explicitly empty basePath into /cementos. The release helper refuses
a storefront/all-apps/bootstrap release with an old basePath, non-apex base URL,
or incompatible asset prefix, before building or replacing applications.
Changing a template does not update the existing private VPS environment.
deploy/nginx-redesign-routes.conf is the shared apex routing snippet:
/guanza,/en/guanzaand their nested routes belong to Next/Medusa./guanza/_next/...is rewritten to/_next/...for built Next assets./guanza/api/...is rewritten to/api/...for the storefront BFF.- Everything else belongs to the portfolio, including its contact API and
the shared
/og.pngartwork.
The snippet preserves the original host/port and sets forwarded host/protocol at the trusted Nginx boundary. It does not trust a client-supplied forwarded protocol. Store responses remain private/no-store, and the existing TLS, security headers, robots/privacy policy, and API/Admin/media virtual hosts must be preserved during installation.
deploy/nginx-vps.conf.example is still an HTTP bootstrap example, not a
replacement for the current Certbot-managed HTTPS configuration. At the later
cutover, define andrea_portfolio at 127.0.0.1:3000 and andrea_storefront at
127.0.0.1:3100, install the route snippet in
/etc/nginx/snippets/andreaweb-redesign-routes.conf, and replace only the apex
server's old application locations with that include. Preserve Certbot blocks,
certificate paths, headers and the other three subdomains. Run sudo nginx -t
before a reload. Privileged live Nginx validation was not run in preparation:
the SSH user requires an interactive sudo password.
The public Guanza layouts now reuse Andrea's existing /og.png social artwork,
not the Medusa starter-template image at an unowned root URL. Product Open Graph
images still come from that product's actual Medusa thumbnail.
Media and contact differences¶
The ngrok demo's media helper only rewrites a configured local Garage origin
to its same-origin preview proxy. It does not replace Medusa URLs in the DB and
is not needed in production. Production Compose does not pass either
NEXT_PUBLIC_MEDIA_SOURCE_ORIGIN or NEXT_PUBLIC_MEDIA_PROXY_PATH and does not
install the local /guanza/media/ proxy. Production media remains at the
existing https://media.andreazambrano.co host.
At approved cutover, set the two existing server-only WhatsApp settings in the private environment to the approved business destination; preserve the inquiry email alias. Do not rotate JWT/cookie/Garage/database credentials, regenerate the environment, change media URLs, or put business contact values into build arguments. New accounts/real payments are not being enabled.
Security scan follow-up¶
The storefront audit identified Next/Sharp, qs, and js-yaml advisories during the
release build. 91f2998 updates Next and its ESLint configuration to 16.3.6,
qs to 6.16.0, and the affected transitive packages through the lockfile.
Storefront full/production audits and the root production audit report zero
findings as of this check. This is not an audit of every container/OS package.
The unchanged backend lockfile has 80 production audit findings: 69 high and 11 moderate, zero critical. They include propagated Medusa dependency findings involving lodash, multer, qs, csv-parse, ajv, morgan and uuid. This is not 80 independent exploitable endpoints. The backend package/lockfile has no diff from the recorded production commit. A broad Medusa upgrade was not bundled into this redesign. These findings still require separate reachability/fix triage before promotion; do not describe the whole stack as security-cleared.
Relevant primary advisory links: Next, image optimization, qs, Sharp.
3. Rehearse locally with production application images¶
The existing demo at http://localhost:8080 is not replaced. An additional,
loopback-only review proxy runs at http://localhost:8081. Its two apps are
built with the real production Dockerfiles, with no source bind mounts or dev
server. Its Nginx includes the same route snippet intended for the VPS. It uses
the existing local Medusa database, not the production database.
From the WSL repository, with the Linux Node toolchain active and the existing local commerce stack running:
npm run storefront:env
docker compose -f compose.yaml -f compose.redesign-release-review.yaml \
--profile commerce --profile release-review config --quiet
docker compose -f compose.yaml -f compose.redesign-release-review.yaml \
--profile commerce --profile release-review up -d --build --no-deps \
release-web release-storefront release-nginx
docker compose -f compose.yaml -f compose.redesign-release-review.yaml \
--profile release-review exec -T release-nginx nginx -t
docker compose -f compose.yaml -f compose.redesign-release-review.yaml \
--profile release-review exec -T release-nginx nginx -s reload
node scripts/check-redesign-release.mjs
Reload the review Nginx after rebuilding/recreating an upstream so it resolves that container's current address. The browser can load local Garage URLs at port 3902 directly; this is deliberately not an ngrok-ready review environment.
To stop only this rehearsal without touching the original demo or its data:
docker compose -f compose.yaml -f compose.redesign-release-review.yaml \
--profile release-review stop release-nginx release-web release-storefront
Checks performed¶
- Root lint passed; the portfolio retains 12 existing image-element warnings.
- Root tests passed: 22 portfolio rendered-route/contact tests and 41 storefront tests. No legacy compatibility tests were retained.
- All three application builds passed. The production frontend Docker images
built successfully; Next is
16.3.6in the rehearsal. - Deployment tooling tests and production Compose validation passed, including empty basePath, matching build/runtime asset prefix, new health checks and absence of preview media configuration.
- Review Nginx syntax and release smoke checks passed: both apps/languages, new collections/cart, built JS/CSS and images, social artwork, API ownership, missing collection 404 and private catalog caching.
check-redesign-layout.mjs --release-review --gallery-fixturepassed landing height/width/minimum/phone behavior, aligned related cards, portrait/landscape product viewport spacing, expanded/collapsed details, thumbnail keyboard controls, many-photo rail and variant reset in both languages. Playwright and the fixture setup are documented in the gallery handoff; this is opt-in, not part ofnpm test.- A browser added the local Oso sample, switched languages while retaining the
same guest cart, verified the COP total, clipboard and email draft destination,
and removed the test item. Store and portfolio WhatsApp handlers returned 303
to
wa.me; cross-origin inquiry returned 403. No WhatsApp message/email was sent. - Browser page-error collection reported none on the inspected public journey.
Screenshots were saved outside Git in the desktop visualization directory:
release-review-landing-1640x800.png,
release-review-landing-1146x700.png,
release-review-landing-phone.png, and
release-review-product-1640x900.png. Andrea's real-device/content review remains
human work; browser tests do not substitute for that approval.
4. Capture backups and record rollback¶
Read-only VPS inspection confirmed all six running production services healthy, with this current release:
commit: aebdc81d8bda5d149b092615130b0eec99ee4496
release: /opt/andreaweb/releases/aebdc81d8bda
web: sha256:b16daa1e60ac95cf0f423f13bb0e616ea6061b3ec2f64a15a5bf173af3dc5142
store: sha256:288bf490e773cad61057fc4ef8a5a1f28a48cdcbd74e17c6d1e8706bfdeb1031
medusa: sha256:d2cd9165517cb098f63ca30cdc9500f05094a4b25efde4aef1439a916bc58b4b
The explicit capture-redesign-backup.sh --capture helper was run through SSH.
It created the private mode-0700 directory:
The same directory was securely copied off the VPS to:
These are private recovery artifacts, not documents to check into Git or serve from the web. They contain production credentials and database/customer data. Keep the directory and files private (0700/0600). The total size is roughly 3 GB, mostly the old application-image archive. The VPS had about 22 GB free afterward.
The backup includes the old application images/IDs, current release path,
production environment, live Certbot-managed Nginx site, production Compose and
Garage config, PostgreSQL custom-format dump, Garage metadata snapshot and media
blocks, and checksums. The PostgreSQL dump was actually restored with
pg_restore --exit-on-error in a new network-isolated, no-port, tmpfs container.
That restored database had 15 product rows. The temporary verifier was removed;
the production database was never a restore target. SHA-256 checks passed both
on the VPS and on the off-server copy.
Garage metadata was captured using its supported live
garage meta snapshot
command. The archive excludes the live SQLite/WAL files and includes the
snapshot plus node/layout information and media blocks. Archive readability
was verified; a full Garage recovery was not rehearsed. PostgreSQL and
Garage snapshots are not a single atomic cross-service transaction. Refresh
backups immediately before cutover, avoid concurrent catalog/media editing
during capture, and do not treat this one manual snapshot as an ongoing backup
schedule. Redis is unchanged and is not part of this manual recovery export.
To refresh later, only when approved, run from WSL using the SSH configuration
that resolves ovh:
For this workstation, Linux scp used the configured Windows SSH client via
-S /mnt/c/Windows/System32/OpenSSH/ssh.exe; Linux SSH does not currently define
the ovh alias. Do not change keys/configuration or expose secrets to work around
that difference.
Application rollback, not a database rollback¶
The redesign needs no schema migration. A normal rollback restores old apps,
environment and Nginx while retaining the current commerce database/media,
including any work Andrea did after deployment. Never import the dump over the
live database merely to undo frontend code, and never use down --volumes.
The following is a future rollback procedure, not something executed in preparation. On the VPS, after identifying the exact approved backup:
backup=/opt/andreaweb/shared/backups/redesign-20260927T180638Z-o3HeUo
old_release=/opt/andreaweb/releases/aebdc81d8bda
cd "$backup"
sha256sum -c SHA256SUMS
docker image load -i "$backup/application-images.tar"
cp "$backup/production.env" /opt/andreaweb/shared/production.env
chmod 0600 /opt/andreaweb/shared/production.env
export WEB_IMAGE="$(cat "$backup/web-image.txt")"
export STOREFRONT_IMAGE="$(cat "$backup/storefront-image.txt")"
export MEDUSA_IMAGE="$(cat "$backup/medusa-image.txt")"
docker compose --env-file /opt/andreaweb/shared/production.env \
-f "$old_release/compose.prod.yaml" up -d --no-deps --wait web storefront medusa
sudo install -m 0644 "$backup/nginx-andreaweb.conf" \
/etc/nginx/sites-available/andreaweb
sudo nginx -t && sudo systemctl reload nginx
ln -sfn "$old_release" /opt/andreaweb/current
Then restore each service's deployment marker under
/opt/andreaweb/shared/deployments/ to its actual old commit (all three were
aebdc81d8bda5d149b092615130b0eec99ee4496 at this capture), verify the old
/portfolio, /cementos/co, API health and real media, and record the rollback.
If only one app changed, roll back only that app. If health or Nginx validation
fails, stop and investigate; do not continue blind replacement steps.
Remaining approval boundary: substeps 5–8¶
After Justin/Andrea review, the next phase can merge/push the exact reviewed commit, update private production settings and the apex Nginx routing, deploy the approved target from the existing runbook, perform the separate collection label change, and verify the actual public journey. None is executed here.
deploy-ovh.sh plan is read-only and currently proposes all-apps with
migrations: false because the redesign spans both apps/shared configuration.
Re-run it for the final merged commit; do not deploy the earlier pending-work
commit merely because an old plan printed that ID. Never bootstrap/reseed/reset
this persistent VPS. The deploy command does not automatically install Nginx.
For Medusa, rename the existing collection's title from Guanza to Orígenes
only if approved, retaining its ID and guanza handle and all existing product
assignments. Do not create a duplicate collection. Public Orígenes/Origins is
already mapped from that handle; Piezas Intervenidas remains a distinct collection.
The sample products remain clearly marked as samples and Andrea can remove
them through Admin later. Final artwork, collection relabeling, account access,
backend security triage and production verification must not be inferred from
the successful local rehearsal.