Skip to content

AndreaWeb roadmap

Goal

Launch a small but real bilingual MVP for Andrea Carolina Zambrano Garcés:

  • a public architecture portfolio;
  • a cement-products storefront backed by Medusa;
  • a private Medusa Admin where Andrea can create products, upload several images, set Colombian-peso prices, and manage inventory;
  • a cart that sends a structured inquiry through WhatsApp or email instead of taking payment;
  • a safe, repeatable Docker deployment to the existing OVH VPS behind its system Nginx.

Spanish (Colombian) is the default language. English remains available through an explicit language switch.

Delivery principles

  1. Inspect before changing. Existing OVH services, Nginx sites, certificates, ports, DNS records, and Docker workloads must be inventoried read-only before deployment design is finalized.
  2. Additive VPS changes only. AndreaWeb receives its own Compose project, directories, Nginx site files, database, credentials, logs, and backups. Existing sites are not replaced or reformatted.
  3. Separate responsibilities. The storefront, portfolio, Medusa server, Medusa worker, PostgreSQL, and Redis are independently replaceable services. PostgreSQL is never bundled into the Medusa application container.
  4. Persistent state is explicit. Database data and product media must survive container replacement. Production media uses a separate S3-compatible storage container through Medusa's S3 File Module Provider rather than Medusa's development-only local file provider.
  5. Immutable deployments. A reviewed Git commit is deployed; migrations run deliberately; health checks pass before traffic changes; the prior release remains available for rollback.
  6. No invented checkout semantics. Sending a WhatsApp or email inquiry does not decrement inventory, reserve stock, or represent payment. Confirmed sales are reconciled manually until an order/reservation workflow is implemented.
  7. Keep tonight's cut line small. Configure forward-looking Medusa primitives now, but defer features that are not required to demonstrate the real merchant and customer loops.

Proposed public topology

The final domain is a placeholder until it is purchased. Using andreazambrano.co as an example:

Address Owner Purpose
andreazambrano.co/portfolio portfolio container Architecture portfolio, default landing destination
andreazambrano.co/cementos storefront container Cement catalog, product pages, and cart
andreazambrano.co/contact portfolio container Contact and inquiry options
andreazambrano.co/en/... corresponding public app English routes
api.andreazambrano.co Medusa server container Store API and health endpoint
admin.andreazambrano.co/app same Medusa server container Authenticated Medusa Admin UI

System Nginx terminates TLS and routes by hostname and path. It is not part of the production Compose project. The Medusa Admin is built into the Medusa server; it does not need its own image. The admin hostname points to the same server container through a separate Nginx virtual host so its access policy can be tightened independently.

TLS certificates are issued by Let's Encrypt and managed on the VPS with Certbot's Nginx integration. Namecheap provides registration and DNS only; a paid Namecheap certificate is not required. The initial certificate covers the apex, www, api, admin, and media hostnames. Port 80 remains reachable for ACME HTTP validation and redirects to HTTPS after issuance. Automatic renewal must be enabled and tested, and certificate-expiration monitoring is part of the launch baseline.

The /cementos path is retained because it describes Andrea's collection and keeps the portfolio and shop under one brand. The storefront must be built and tested with that base path; this is an explicit integration requirement, not an Nginx-only rewrite.

DNS and existing records

Multiple domains and hostnames can point to the same public IP. Nginx selects the correct site from the HTTP Host header and TLS SNI, so an existing site on the VPS is not inherently a conflict.

Before changing Namecheap DNS:

  1. Export or record the existing zone.
  2. Inventory existing A, AAAA, CNAME, MX, TXT, and CAA records.
  3. Confirm the VPS's current public IPv4 and whether IPv6 is intentionally configured.
  4. Check Nginx for duplicate server_name values and any default/catch-all server.
  5. Add only the new host labels. Do not replace mail, verification, or unrelated records.

Expected records are one A record from @ to the VPS IPv4 address and explicit CNAMEs from www, api, admin, and media to the apex. This keeps the VPS address in one record while avoiding an overly broad wildcard. Do not add an AAAA record until public IPv6 is deliberately configured. DNS is pointed at the VPS only after Nginx can serve a safe HTTP placeholder; all certificate hostnames must resolve before Let's Encrypt issuance is attempted.

Target application architecture

Repository layout

Move toward a single workspace so compatible versions, scripts, tests, and Compose definitions are versioned together:

apps/
  backend/       Medusa v2 server, worker code, Admin customizations, migrations
  storefront/    official Medusa DTC Next.js storefront, branded and bilingual
  portfolio/     Vinext portfolio for the MVP; planned static-first Astro migration
packages/
  brand/         optional shared design tokens, translations, and assets
deploy/
  compose/       local and production Compose definitions
  nginx/         additive examples, never a dump of the live server
docs/
  decisions/     short architecture decision records
  operations/    local, deployment, backup, restore, and rollback runbooks

The official current Medusa direction is the DTC monorepo with a Medusa backend and a separately hosted Next.js storefront. The existing Vinext PoC is useful design material, but it is not the Medusa DTC storefront. The MVP keeps Vinext for the portfolio so tonight's work stays focused on the real merchant and customer loops. The approved visual design and content model can later move to Astro independently of commerce.

Portfolio framework plan

The portfolio and storefront deliberately use different frameworks because they solve different problems:

  • MVP: keep the current Vinext portfolio. It already demonstrates the design, bilingual routes, and responsive layout, so replacing it before the commerce launch would add risk without improving Andrea's product-management workflow.
  • Commerce: use the official Medusa DTC Next.js storefront. Vinext is a Vite-based reimplementation of the Next.js API surface, not the framework on which Vercel Commerce or the Medusa DTC starter is based. Migrating the commerce starter to Vinext is not part of the MVP.
  • After MVP: migrate only the portfolio to Astro. Astro is the preferred long-lived fit for a mostly static, image-heavy architecture portfolio because it provides static output, optimized images, typed content collections, Markdown/MDX authoring, built-in internationalized routing, and optional CMS integrations.

The Astro portfolio will keep Spanish unprefixed as the default and English under /en. Architectural projects will be typed content entries with fields such as title, location, year, project type, Andrea's role, status, description, credits, hero image, gallery, drawings, tags, display order, and featured status. Project lists, detail pages, filters, metadata, and navigation will be generated from those entries.

Astro should build to static files inside a small independently deployable image. The VPS's system Nginx will continue to route portfolio traffic to that service. Shared colors, typography, spacing, translations, and approved brand assets may live in packages/brand, but the portfolio must not depend on the Medusa backend.

When Andrea needs browser-based editing, add a Git-backed editor or headless CMS to the Astro content layer. That decision remains separate from Medusa Admin, which manages only commerce. Astro can also host a future Markdown/MDX article section with archives, tags, RSS, and search; a third blog application is optional rather than required.

Production services

Service Image/process Persistent state
portfolio Vinext web image for MVP; static Astro image after migration none
storefront Next.js DTC storefront image none
medusa-server Medusa production image in server mode; serves API and Admin none locally
medusa-worker same immutable Medusa image in worker mode none locally
postgres pinned PostgreSQL image named volume plus verified backups
redis pinned Redis image named volume if configured for persistence
object-storage pinned S3-compatible storage image separate metadata/data volumes plus off-VPS backups

Product media lives in a production S3-compatible object store through Medusa's S3 File Module Provider. The accepted self-hosted MVP implementation is a pinned Garage image: local upload compatibility and restart persistence are verified, while the Phase 0 VPS audit must still confirm its resource fit and the launch gate still requires tested off-VPS backup/restore. MinIO is not the default candidate because its former community repository and image distribution changed materially in 2026, and its own single-node/single-drive guidance describes that topology as development or evaluation rather than production.

For the MVP, Garage can run as one private single-node service because the VPS itself is already one failure domain. That is persistence, not high availability. Its metadata and object data receive separate persistent mounts, authenticated access, a private Docker network, and an automated encrypted copy off the VPS. Moving later to hosted S3 or a replicated Garage cluster should require configuration and data migration, not storefront changes.

Only system Nginx publishes ports 80/443. Application ports bind to loopback or remain on private Docker networks. PostgreSQL and Redis are never publicly exposed.

Commerce model

  • Region: Colombia.
  • Currency: COP, with the tax display policy explicitly configured.
  • Sales channel: public cement storefront.
  • Stock location: Andrea's current inventory location.
  • Products: cement objects with multiple images, descriptions, categories, dimensions/material notes, and status.
  • Variants: use Medusa product options such as Color when the physical item is genuinely available in selectable colors. Each variant can have its own SKU, price, images, and inventory.
  • Inventory: enable managed inventory for stocked variants; disable backorders initially.
  • Sales: use Medusa sale-type price lists. The storefront reads calculated prices and shows the original price crossed out only when Medusa identifies a real sale price.
  • Cart: use Medusa's cart APIs so variants, quantities, current prices, and availability come from the backend.
  • Checkout for MVP: no payment session. Generate a localized WhatsApp deep link and an email alternative containing product names, selected variants, quantities, displayed prices, and a cart reference where available.
  • Inventory after inquiry: no automatic decrement. Andrea confirms availability and adjusts stock after completing a sale. A later inquiry/reservation workflow can add expiring holds and auditable conversion to an order.

MVP tonight: definition of done

Tonight's MVP is complete only when all of the following are true in production or in an explicitly labeled staging hostname:

  • the purchased domain resolves to the VPS and HTTPS works;
  • existing VPS sites still respond normally;
  • the portfolio, store, API, and Admin routes are reachable through system Nginx;
  • the Admin requires authentication and has one deliberately created Andrea account;
  • Andrea can create and publish a product, upload several images, set a COP price, and set a stock quantity;
  • that product appears in the Spanish catalog without a code change;
  • the product page shows its images, price, and availability;
  • a visitor can add, change, and remove cart items;
  • the final cart action opens WhatsApp with an accurate Spanish order inquiry, with email as a fallback;
  • English navigation and essential store labels work, even if product copy initially falls back to Spanish;
  • PostgreSQL data and uploaded images survive a container rebuild;
  • database migration, health check, backup, restore, and rollback commands are documented;
  • no secret, private key, database dump, or live server configuration is committed.

Phase 0 — decisions and read-only discovery

Work

  1. Record the purchased domain and intended public hostnames.
  2. Inspect local SSH resolution with ssh -G ovh; do not print private key material.
  3. Connect read-only with ssh ovh and inventory:
  4. Ubuntu version, available memory/disk, and architecture;
  5. Docker Engine/Compose versions and current containers/networks/volumes;
  6. listening ports and firewall status;
  7. Nginx version, enabled sites, server_name ownership, include layout, and certificate tooling;
  8. the current Nginx effective configuration using nginx -T or sudo -n nginx -T only if permitted;
  9. existing deployment directories and ownership.
  10. Sanitize the findings before committing any notes. Live hostnames, secrets, tokens, and certificate material stay out of Git.
  11. Confirm Garage as the production object-storage service or record the reason for choosing another S3-compatible provider.
  12. Confirm whether the MVP should launch immediately on the primary domain or first on a staging hostname.

Exit gate

A short discovery report identifies safe ports, Nginx file locations, available resources, naming conflicts, backup destination, and any blocker. No server state has changed.

Phase 1 — establish the Medusa workspace locally

Progress as of 2026-08-25

The existing Vinext application has been isolated as apps/portfolio. Medusa v2, PostgreSQL, Redis, and Garage now run locally as separate services with health checks and persistent named volumes. Explicit migrations create the Colombia/COP commerce foundation and four PoC products; their existing images are stored through Medusa's S3 provider and survive a Garage restart. Local environment templates, generated secrets, health checks, media verification, commerce-foundation verification, and operating instructions are versioned. Medusa uses its production S3 File Module Provider against Garage locally; an upload/read/restart/read/delete check proves that the same provider interface and durable-volume boundary work before VPS packaging.

The official DTC storefront is now pinned under apps/storefront, runs as an independent Docker service at the real /cementos base path, and reads the seeded Medusa catalog with a Medusa-backed cart. It remains a separate technical preview until Phase 2 applies the approved visual design and bilingual content. Its framework layer is now Next.js 16.3.2 with React 19.2.8. A disposable OVH preview now packages the polished PoC alongside the real Medusa Admin/API, PostgreSQL, Redis, and Garage so Andrea can evaluate both halves before their Phase 2 integration. That preview is intentionally paveable; durable production Compose topology, backups/restore, and launch operations remain outstanding. The local Admin invitation workflow is implemented and a development invitation for Andrea is pending acceptance; the password is chosen in Admin and never enters Git or shell history.

Work

  1. Tag or branch the current PoC so it remains easy to compare.
  2. Scaffold the supported Medusa v2 DTC monorepo structure using a pinned Node LTS and package manager.
  3. Place the Medusa backend and official DTC Next.js storefront under apps/.
  4. Move the existing Vinext portfolio into its own app without redesigning or migrating frameworks.
  5. Add local Compose services for PostgreSQL, Redis, and Garage object storage, with health checks, named volumes, and isolated networks.
  6. Add separate development and production environment templates containing names only, never secrets.
  7. Configure migrations, seed data, Colombian region/COP, sales channel, stock location, and a development admin.
  8. Add production S3-compatible file-provider configuration, with a development equivalent that exercises the same upload interface. Complete locally; the public production URL and reverse-proxy contract are recorded in ADR 0002.

Exit gate

One documented command starts the complete local stack. Medusa health, Admin login, database migrations, Redis, product creation, and image upload work after a clean rebuild.

Phase 2 — connect the real catalog and merchant loop

Progress as of 2026-08-25

All six Phase 2 steps are complete and verified locally. The local Nginx rehearsal now sends /cementos to the official Medusa DTC storefront, and the public catalog reads its products, categories, collections, prices, images, variants, and inventory availability from the Medusa Store API. The storefront uses the configured publishable API key and formats prices in Colombian pesos. Single-variant and multi-variant products are both handled without requiring an unnecessary selection from the customer.

The DTC storefront now carries the approved ACZG editorial identity, Spanish commerce copy, responsive catalog and product layouts, and accessible cart controls. Local browser and Store API checks exercised adding a Medusa line item, changing its quantity and total, and removing it again on desktop and phone-sized layouts. Personalized cart reads bypass Next.js's shared data cache so mutations are visible on the next render. The storefront does not present a fake payment action.

The cart now produces one localized summary for WhatsApp, email, and clipboard use. Its same-origin, POST-only BFF reloads the Medusa cart before returning an uncacheable 303 WhatsApp redirect, keeping the configured number out of HTML, client bundles, repository data, and JSON responses. The form opens a new tab without clearing or mutating the original cart. Cross-site, direct-GET, and empty-cart requests are rejected, while email targets the approved public cementos@andreazambrano.co alias. Until a number is configured, WhatsApp opens the recipient-free sharing flow.

Catalog reads intentionally bypass the Next.js data cache during this MVP phase, so a normal browser refresh reflects changes made through Medusa Admin. Replace that broad freshness policy with targeted tag or webhook invalidation when the production caching strategy is introduced. The committed production candidate now includes the DTC container, publishable-key synchronization, loopback health checks, and an additive Nginx route; it has not yet been deployed to the VPS.

The Spanish-first Admin guide documents the complete merchant workflow for products, multiple images, variants and colors, COP prices, inventory, sales, publishing, and the most likely troubleshooting paths. The versioned starter catalog provides four Spanish-first products, English metadata, COP prices, managed inventory with demo stock, and persistent media. Its seed and media import preserve any Admin-created product that already owns a handle or image.

Work

  1. Replace the hard-coded public PoC with the DTC storefront's existing Medusa Store API integration and publishable API key flow.
  2. Implement collections/categories, product lists, product details, galleries, variant selection, COP formatting, and availability states.
  3. Apply the approved visual design to the DTC storefront and validate its Medusa-backed cart end to end.
  4. Build the WhatsApp and email inquiry actions with localized, URL-encoded summaries and clear wording that availability is confirmed manually.
  5. Add Admin documentation for creating products, images, variants, prices, and inventory.
  6. Seed a small approved catalog using Andrea's supplied imagery without overwriting products created in Admin.

Exit gate

Andrea can add a previously unknown product entirely through Admin and see it in the public catalog. A visitor can create a correct inquiry without any fake Stripe UI.

Phase 3 — bilingual portfolio and public pages

Work

  1. Preserve Spanish-default and English routes across both applications.
  2. Add shared global navigation between portfolio, store, contact, and language switch.
  3. Add /contact with approved email/WhatsApp links and privacy-conscious form behavior if a form is later enabled.
  4. Add placeholder /gracias and /en/thank-you pages that only claim success when reached from a genuine supported flow.
  5. Keep portfolio projects in typed local content for the MVP, with image and copy replacement documented.
  6. Record the proposed Astro project schema and route mapping so the later migration does not require redesigning approved content.

Exit gate

Navigation, language switching, metadata, responsive behavior, accessibility basics, and cross-app visual continuity pass on mobile and desktop.

Phase 4 — production packaging and local rehearsal

Work

  1. Keep the storefront on a supported Next.js line and require clean complete and production-only dependency audits before public exposure. The initial Next.js 16 migration is complete.
  2. Build non-root, multi-stage images for portfolio, storefront, and the shared Medusa server/worker image.
  3. Add production Compose for PostgreSQL, Redis, Garage object storage, Medusa server, Medusa worker, storefront, and portfolio—without containerized Nginx.
  4. Keep local Nginx as a separate override that rehearses the production routes and hostnames.
  5. Add health checks, dependency readiness, resource limits appropriate to the audited VPS, log rotation, and restart policies.
  6. Store production secrets outside the Git release directory with restrictive permissions.
  7. Add database backup and restore scripts and test a restore into a disposable database.
  8. Exercise migrations, seed behavior, restart persistence, image persistence, and rollback locally.

Exit gate

A clean machine can build and test each app separately or start the integrated stack. A backup can be restored, and rolling back application code does not silently roll back the database schema.

Phase 5 — additive OVH deployment and launch

Work

  1. Prepare an exact deployment plan from a clean Git commit and take backups before stateful changes.
  2. Create dedicated AndreaWeb directories and the Compose project without touching unrelated workloads.
  3. Start data services privately, run migrations once, then start Medusa worker/server and public apps.
  4. Install new Nginx site files alongside existing sites. Validate with nginx -t before every reload.
  5. Test routing locally on the VPS with explicit Host headers before DNS changes.
  6. Add DNS records at Namecheap without changing unrelated records.
  7. Install or reuse Certbot through the server's package convention, issue a Let's Encrypt certificate for the apex, www, api, admin, and media, and then enable HTTPS and the canonical www-to-apex redirect.
  8. Verify unattended renewal with a Certbot dry run and record the renewal timer status without committing certificate material.
  9. Create Andrea's production Admin account through an interactive, non-logged command.
  10. Run end-to-end acceptance checks and capture the deployed commit.
  11. Complete the public-indexing checklist in docs/seo.md: choose the canonical hostname, generate bilingual canonical/hreflang metadata and sitemaps, remove preview noindex only from approved public pages, and register webmaster tools.

Exit gate

All MVP acceptance criteria pass over public HTTPS, existing sites remain healthy, backups have run, and rollback instructions reference a known-good release.

Phase 6 — immediate hardening after MVP

  • Restrict Admin exposure with an IP allowlist, VPN, or an additional Nginx authentication layer if Andrea's access pattern permits it.
  • Add automatic PostgreSQL backups, retention, off-VPS copies, and scheduled restore drills.
  • Add object-storage versioning/lifecycle rules and verify media recovery.
  • Add uptime checks for portfolio, storefront, Medusa health, and certificate expiry.
  • Add structured logs, disk alerts, dependency update policy, and vulnerability scanning.
  • Add rate limits and a reviewed content-security policy.
  • Add CI that builds images, runs migrations against a disposable database, tests routes, and publishes immutable image tags.
  • Document Medusa upgrades and migration sequencing.
  • Add automated SEO checks for crawlability, canonical/hreflang reciprocity, sitemap contents, structured-data validity, redirects, and accidental noindex.

The staged checks, lint-warning policy, branch protection, immutable artifacts, protected production approval, and future delivery workflow are detailed in CI/CD pipeline plan.

The staged self-hosted monitoring stack, operational dashboards and alerts, safe database reporting/maintenance rules, client-data boundaries, marketing outreach, and loyalty direction are detailed in Observability, operational tooling, client relationships, and growth.

Later product capabilities

Color choices

Use Medusa's existing product options and variants rather than a custom color field. Each purchasable color is a variant with independent inventory, price, SKU, and optional variant media. Add swatches and unavailable-state UI after the base variant selector is stable.

Sales

Use sale-type Medusa price lists with optional start/end dates. The storefront displays the calculated sale amount and Medusa's original amount; it does not calculate discounts independently. Add badges, crossed-out original prices, and accessible sale messaging.

Inquiry reservations and manual orders

Add a custom Medusa workflow that records an inquiry, snapshots the cart, optionally reserves inventory for a limited period, and lets Andrea convert it into a manual order. Define cancellation and expiry rules before enabling automatic stock holds.

Stripe support

If full checkout becomes useful, add Stripe through Medusa's payment provider and test webhooks, refunds, taxes, and fulfillment before launch. A simpler support option can use a Stripe Payment Link or equivalent pay-what-you-want page. Redirect to the thank-you page only after a provider-confirmed success state.

The provider must support Andrea's actual Colombian account and business situation. The staged manual Nequi/Bre-B workflow, support links, Wompi/Mercado Pago candidates, future Medusa payment-provider design, professional domain email, and WhatsApp Business plan are detailed in Future commerce, payments, and communications.

Portfolio editing and blog

After the commerce MVP is stable, migrate the portfolio from Vinext to Astro without changing its approved URLs or visual direction. Define typed Astro content collections for projects and later articles, generate responsive project galleries at build time, and preserve Spanish-default/English routing.

Keep portfolio content in Markdown or MDX until editing frequency justifies a CMS. A later Git-backed editor or headless CMS should be selected independently from Medusa and can manage portfolio projects, biography, articles, and media. A Git-only authoring workflow may not be friendly enough for Andrea, so test the editing experience with her before declaring it complete.

Astro can provide the future article/blog section directly, including generated navigation, archives, tags, RSS, and search integration. Hugo remains a strong Go-based alternative if a completely separate Markdown site is later desirable, but it is no longer the default plan.

The future architecture/astronomy journal, audience analytics, cookie banner and consent model, CMP decision, and journal-only advertising boundary are detailed in Publishing, audience analytics, consent, and advertising.

The public-launch crawl/index plan, bilingual URL signals, structured-data boundaries, image discovery, Search Console/Bing setup, and recurring SEO review are detailed in SEO and public indexing.

Explicitly not in tonight's MVP

  • real card payments, refunds, shipping quotes, or tax automation;
  • automatic inventory reservations from WhatsApp inquiries;
  • customer accounts and order history;
  • custom Admin extensions when standard Medusa Admin already covers the need;
  • portfolio CMS or blog;
  • advanced product personalization, bundles, reviews, wish lists, or analytics;
  • high-availability database infrastructure or multi-node orchestration.

Delegation and handoff protocol

This roadmap is designed for work to move between Codex agents or other models without losing control of state.

Every delegated unit should specify:

  1. phase and narrow objective;
  2. files or service boundary it owns;
  3. inputs and decisions it may assume;
  4. actions it must not perform, especially DNS, SSH, secrets, migrations, and deployment;
  5. exact acceptance checks;
  6. expected documentation updates;
  7. commit or patch produced and remaining risks.

Avoid concurrent ownership of package lockfiles, Compose files, database migrations, Nginx routing, or shared translation files. Integrate those changes serially. Record material choices as short files under docs/decisions/, including context, decision, alternatives, and consequences.

Remaining decisions

The domain, VPS audit, Garage, configured inquiry contact, and Medusa-backed inquiry flow are implemented. Decisions still open are:

  1. Whether exact stock counts are public or the storefront shows only Disponible, Pocas unidades, and Agotado.
  2. Whether Andrea should access Admin from anywhere or through a restricted access layer.
  3. The off-VPS PostgreSQL/Garage backup destination, retention, encryption, and restore-test schedule.
  4. The canonical hostname and exact public-indexing date/checklist.

Primary technical references