Skip to content

Andrea redesign 1: baseline and route contract

Historical Step 1 record. The route spike below has been retired; current local Compose uses the deployed routes without an overlay. Start with the redesign story and local operations.

Date: 2026-09-24 (America/Bogota). Branch: jm/andrea-redesign-1.

This is the code and local-runtime baseline for Step 1 of andrea-redesign-1.md. It separates observed behavior, the tested route spike, and migration work still required. The opt-in local spike starts containers against existing local volumes but does not migrate, reseed, or reset commerce data. No VPS, production host, remote database, or remote API was inspected or changed.

Observed baseline

Checkout, runtime, and visual evidence

  • Authoritative checkout: /home/justin/repos/AndreaWeb, WSL Ubuntu-26.04, branch jm/andrea-redesign-1.
  • Docker Desktop's WSL integration was initially stopped. After starting it, the local portfolio, storefront, Medusa, PostgreSQL, Redis, and Garage all ran through the opt-in Compose overlay described below. The WSL zsh login shell loaded the local fnm Node/npm installation.
  • Existing local Medusa products were readable; no seed or database reset was run. A read-only query of product_collection found zero local collection rows. This says nothing about the VPS catalog; the two approved collection identities and their product assignments need a separate read-only audit before Step 4. Account behavior, verification email, and locale catalogs were not exercised here.

Screenshots were captured at 1440 × 900 on 2026-09-24 from the local services, before visual redesign. The detail screenshot reproduces the actual overlap: the first line of “Organizador Doble” extends beneath the main image.

The direct local catalog paths used for the screenshots were /co and /co/products/organizador-doble with an empty local Next.js base path. In the current deployed configuration, the equivalent storefront paths begin with /cementos. The images document baseline layout, not new Guanza styling.

Applications and URLs today

The repository has two customer-facing apps: a Vinext/Vite portfolio and a Next.js storefront backed by Medusa. The portfolio root re-exports its /portfolio page; both render the Spanish portfolio. /en/portfolio has an English portfolio route. The portfolio also serves /cementos and /en/cementos through CementStore; these are the old simulated shop, not the Medusa catalog.

The real storefront uses NEXT_PUBLIC_STOREFRONT_BASE_PATH, currently /cementos in Next config, Compose, and environment templates. Its proxy reads a country segment after stripping that base path, else choosing configured default country co. The backend seed defines a Colombia (co) region with COP. Thus co in current URLs is market/country selection, not language.

The storefront country-root route and /store route both render StoreTemplate; /store additionally consumes sort, page, and option-value filter parameters. Nginx sends /cementos and /cementos/... to the same Next.js service. That accounts for /cementos/co and /cementos/co/store showing the same principal catalog view.

The store wordmark links to its own root. A desktop-only portfolio link points to /portfolio; there is no consistent shared home link or mobile cross-app navigation. A side-menu language selector is conditionally populated by the optional Medusa /store/locales endpoint. Locale-cookie and cart-locale update code exists, but does not establish English availability or full translation. /en/cementos is the separate portfolio PoC and does not use this locale mechanism.

Catalog, collections, accounts

The checked-in Medusa foundation seed creates the Cementos sales channel, publishable key, Colombia region with COP, and stock location. The starter catalog seed defines four demo products with COP prices and stock, but does not create collections or assign products to collections. The catalog upgrade script only updates products marked as legacy starter data. Repository code cannot establish whether the intended production commerce database currently contains GUANZA or Piezas Intervenidas, nor their assignments. The local database had zero collections at this check. Read the intended commerce catalog through Medusa Admin/API before mapping collections; record IDs, handles, assignments, and unknowns. Preserve IDs, inventory, media, and merchant edits. Do not rerun seed/reset scripts to answer this.

Account code exists: email/password registration and login, customer creation/resolution, conditional email verification, cart transfer, profile, address, and order-history pages. Verification UI/action code is present too. Registration, email delivery, and login were outside this route spike and were not verified; account readiness remains unverified until a focused local audit.

Current route inventory

This describes code and proxy configuration, not a successful deployed request. Next.js route groups do not appear in public URLs.

Current path/family Current behavior and owner Migration implication
/, /portfolio Same Spanish portfolio page in portfolio app. / becomes landing; /portfolio redirects to /arquitectura.
/en/portfolio English portfolio in portfolio app. Redirect to /en/arquitectura.
/cementos, /en/cementos Simulated CementStore in portfolio app. Redirect to real Guanza destination in matching language.
/cementos/co, /cementos/co/store Real catalog via Nginx/Next; both render StoreTemplate; /store accepts listing state. /guanza becomes selector; decide catalog-root fallback after auditing old links/query intent.
/cementos/<country>/collections/<handle> Real Medusa collection route. Map verified collection identity to /guanza/origenes or /guanza/piezas; define unknown behavior.
/cementos/<country>/categories/<path...> Real category route. Map only with an equivalent destination; retain supported filters/sort/page.
/cementos/<country>/products/<handle> Real product details. /guanza/productos/<handle>; retain handle and supported query state.
/cementos/<country>/cart Real cart. /guanza/carrito; retain cart identity and contents.
/cementos/<country>/account..., /verify-account Account, verification, profile, address, and order routes. If retained after verification, map to /guanza/cuenta... and localized verification route.
/cementos/<country>/checkout, /order/... Checkout/order/transfer route files exist. Path presence does not establish paid-order behavior; purchasing principally hands off an inquiry. Audit each workflow; preserve inquiry semantics, never represent inquiry as paid order.
/api/..., /_next/..., static assets, server actions Next internal surfaces; matcher excludes API and static/image paths. Inventory during routing design; page redirects must not capture POST/API requests; prevent app asset collisions.

deploy/nginx.conf and deploy/nginx-vps.conf.example route exact /cementos and /cementos/ to port 3100; other paths go to portfolio on port 3000. Compose health checks and deployment templates also assume /cementos/co. This is checked-in configuration, not live service state.

Approved destination contract

Spanish is unprefixed; English always has /en first. Both initially use Colombia and COP; language does not select market. Display “Orígenes” with ASCII route slug origenes.

Experience Spanish English Owner
Personal landing / /en Portfolio
Architecture /arquitectura /en/arquitectura Portfolio
Guanza selector /guanza /en/guanza Storefront
Orígenes /guanza/origenes /en/guanza/origenes Storefront
Piezas Intervenidas /guanza/piezas /en/guanza/piezas Storefront
Product /guanza/productos/<handle> /en/guanza/productos/<handle> Storefront
Cart /guanza/carrito /en/guanza/carrito Storefront
Account, if exposed /guanza/cuenta /en/guanza/cuenta Storefront
Journal Existing Journal Spanish destination Existing Journal English destination External Journal app

The storefront has one build-time base path and country-prefixed filesystem routes. basePath: /guanza alone cannot also support /en/guanza. The tested decision is one storefront build with an empty base path and application-owned locale routes. Nginx dispatches both /guanza... and /en/guanza... to that same Next.js service. The region remains Medusa co/COP for both languages; co is an internal commerce parameter, not part of the new public URL. The portfolio continues to own /, /en, and architecture paths. No second shop instance or Nginx HTML rewriting is involved.

Tested local routing slice

The opt-in compose.redesign-spike.yaml and deploy/nginx.redesign-spike.conf apply only when explicitly selected alongside normal Compose. They do not alter the checked-in production Nginx configuration or its /cementos routing. New App Router entries /guanza and /en/guanza share one StoreTemplate backed by Medusa's Colombia region. The proxy accepts these exact public roots without redirecting to /co; existing country-prefixed routes continue to work in the local Next.js service while deeper public paths are built in later steps.

The Next build uses an empty base path for this spike. Its static chunks get the /guanza/_next/ public asset prefix, which local Nginx strips before forwarding to Next. This avoids claiming the portfolio's framework assets. The local-only /guanza/api/ location similarly forwards to the existing Next.js BFF /api/ without claiming any portfolio API route. Media remains on the separate Garage media host. Server actions, image optimization, metadata, and canonical URLs need end-to-end checks as actual deeper routes are moved; do not assume assetPrefix alone settles them.

The local media hostname resolved and returned HTTP 200 from WSL, but did not resolve from the Windows host during this check. Headless Windows screenshots of the new routes therefore showed product text with blank media tiles. This is a local preview hostname issue, not evidence of missing Medusa media; verify Windows browser hostname resolution before visual review in Step 4.

Local checks through Nginx at localhost:8080 returned HTTP 200 for /, /portfolio, /guanza, and /en/guanza. Both Guanza responses contained the real Medusa product “Organizador Doble.” A namespaced Next static chunk returned 200 and a GET to /guanza/api/inquiries/whatsapp returned 405 (the existing POST-only handler), showing the request reached the BFF. The Medusa cache cookie used Path=/ and survived a Spanish-to-English request in one browser session. This proves route ownership and reachability, not a completed English translation, cart/account journey, or production-ready proxy configuration.

Future public links must be generated by application-owned route builders: locale prefix first, then /guanza/...; never let existing /co links leak from the old LocalizedClientLink. Step 2 should define the small shared route API before independent UI work. Keep cross-app navigation as normal anchors where needed so Next's client router does not claim the Vinext portfolio. Cookies for cart/auth should remain same-origin and path /; language state must not change market or cart. Locale-aware responses and cache keys must be separated before translated content is enabled. The two new roots currently use dynamic rendering and identical Spanish content, so they do not yet establish English content or final cache behavior.

From the WSL repository root, the disposable routing overlay can be reproduced with docker compose -f compose.yaml -f compose.redesign-spike.yaml --profile commerce up -d --build. Open http://localhost:8080/guanza and http://localhost:8080/en/guanza. Stop it with the same file/profile arguments and down without --volumes; that leaves existing local commerce data intact. This overlay runs the storefront development server and is not the production build or production Nginx template.

Legacy migration inventory to finalize

These are intended relationships, not existing redirects. The user's transition allowance means old routes may keep serving their current content locally until the new journey is ready; no legacy redirect is activated by Step 1. At cutover, final redirects must avoid chains/loops, retain supported query parameters, exclude POST/API requests, and leave unknown paths as a helpful 404.

Legacy path Intended resolution
/portfolio, /en/portfolio /arquitectura, /en/arquitectura.
/cementos, /en/cementos Real Guanza entry in corresponding language.
/cementos/co, /cementos/co/store, country catalog roots Guanza selector unless a verified old link/filter identifies a collection.
/cementos/<country>/collections/<handle> Read-only Medusa audit; known identities map to new collection slugs.
/cementos/<country>/categories/<path...> Preserve category/filter intent only with a valid target.
/cementos/<country>/products/<handle> /guanza/productos/<handle> in current language, keeping supported query state.
/cementos/<country>/cart /guanza/carrito, retaining cart identity and contents.
Account and verification paths Map only flows verified and retained in the journey.
Checkout and /order/... Preserve or retire after audit; never imply inquiry completed a paid order.
/en/cementos#collection Fragment is client-side and not sent to server; consider saved-link compatibility.

Step 1 exit and remaining gates

The baseline screenshots, overlap reproduction, existing route inventory, read-only local catalog audit, and dual-language local integration slice satisfy the Step 1 route decision. The local overlay is deliberately not a production cutover. Before Step 4, identify the real collection IDs, handles, and product assignments in the intended non-production/production catalog without changing them. Before release, finish the legacy migration table with live equivalents, verify deep links and supported query state, eliminate /co leakage, and test actions, BFF requests, image/asset paths, metadata/canonicals, cart/auth cookies, locale cache isolation, and rollback against the finished journey. Production mutation is not a shortcut for any of these checks.