Commit Graph
345 Commits
Author SHA1 Message Date
devopsandClaude Sonnet 5 711bb2c76f fix(ecommerce): bump next 15.5.10 -> 15.5.24 (CVE-2026-75604, CRITICAL)
Trivy bloqueó el build del frontend en el pipeline de CI: Next.js
15.5.10 tiene un RCE no autenticado en la API de optimización de
imágenes vía archivos AVIF (CVE-2026-75604 / GHSA-2xp9-vwfh-vxw4),
corregido en 15.5.24. Bump mínimo dentro del mismo minor, sin otros
cambios de dependencias.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-10 02:04:55 +00:00
devopsandClaude Sonnet 5 1abc69825c feat(ecommerce): banner dinámico desde catálogo real y buscador en dos filas en mobile
- hero-carousel.tsx: slides derivados de productos featured/nuevos reales
  (imagen, nombre, precio, link, badge de % OFF) en vez de un array
  hardcodeado; fallback estático solo si la tienda no tiene productos
  activos.
- navbar.tsx: en mobile/tablet el buscador pasa a una segunda fila a
  todo el ancho debajo de logo+iconos (antes competía por espacio en una
  sola fila y quedaba recortado); desktop sin cambios.
- docs: ADR 0010 documentando el pivote de pago PayU→Rapyd(descartado)→
  ePayco, la integración de EnvíoClick y checklist de pruebas reales
  pendientes desde el storefront; puntero agregado desde ADR 0009.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-09 21:45:25 +00:00
devops 1e6009daf7 Merge chore/envioclick-datos-reales-negocio into main 2026-09-09 03:35:59 +00:00
devopsandClaude Sonnet 5 7a95957945 chore(envioclick): actualizar datos reales de contacto/dirección de origen
Placeholders reemplazados por los datos reales que dio el usuario --
dirección de la bodega (Cra 100 #42-65), email y teléfono de contacto.
Estos valores aparecen como remitente en las guías reales de EnvíoClick.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-09 03:35:51 +00:00
gitea-actions a973b2671e chore(gitops): deploy Medusa v1.0.234 [skip ci] 2026-09-08 21:52:18 +00:00
devops bdd7c06a32 chore: release v1.0.235 [skip ci] 2026-09-08 21:25:08 +00:00
devops 0c356d6fbe Merge feat/envioclick-fulfillment into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 31s
Build and Push Medusa / Escaneo de Secretos (Gitleaks) (push) Successful in 19s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 12m5s
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 27m11s
2026-09-08 21:11:54 +00:00
devopsandClaude Sonnet 5 c507da8abc feat(fulfillment): integrar EnvíoClick para cálculo real de envío
ADR 0009 §2 ya había anticipado esto: la shipping option actual es un
placeholder de negocio ($15.000 COP fijo), no un cálculo real por
peso/volumen -- y el modelo de direcciones del checkout (IDs DIVIPOLA
en vez de texto libre en lib/data/colombia.ts) ya se había construido
pensando en esta integración. Este commit la implementa.

Investigación en vivo (no solo documentación -- misma disciplina que
ya costó varios rehechos con las pasarelas de pago): la SPA de docs
públicas (apidoc.envioclickpro.com.co) no renderiza sin sesión, pero
está generada con apiDoc, así que se bajó y leyó directo su
api_data.json/api_project.json (spec completa real), y se probó
/quotation en vivo con la API key real del usuario -- 200 OK con
tarifas reales de PIBOX/COORDINADORA/ENVIA/RAPPI/TCC. Esto corrigió
varios datos mal asumidos de un plugin de WordPress desactualizado
usado como referencia inicial (API v1): la URL base real es
api.envioclickpro.com.co/api/v2 (no api.envioclickpro.com a secas), y
el header de auth real es "Authorization" a secas, no
"AuthorizationKey".

Hallazgo crítico evitado leyendo el código fuente de
@medusajs/utils/dist/common/define-config.js: defineConfig() ya
registra por defecto un módulo de fulfillment con el provider
manual_manual, aunque medusa-config.ts no lo mencione explícitamente
-- pero transformModules() indexa por serviceName y el último que
llega pisa al anterior (no mezcla providers). Agregar un bloque propio
de fulfillment sin incluir también manual_manual ahí habría roto en
silencio el envío manual que ya usa la shipping option existente.
Verificado cargando la config compilada real: ambos providers quedan
registrados juntos.

- src/modules/envioclick-fulfillment/: AbstractFulfillmentProviderService.
  calculatePrice() cotiza en vivo durante el checkout -- Medusa advierte
  explícitamente que un error acá bloquea el checkout completo, así que
  NUNCA se deja propagar una excepción: cualquier falla (red, dirección
  sin id DIVIPOLA, EnvíoClick caído) cae al precio fijo de $15.000 que
  ya se usaba, para no romper la compra. createFulfillment() vuelve a
  cotizar en el momento de generar la guía real en vez de reusar el
  idRate mostrado en checkout (más correcto: CalculatedShippingOptionPrice
  no tiene forma de persistir ese id entre llamadas, confirmado leyendo
  el tipo real, y un idRate viejo podría estar vencido si el fulfillment
  pasa horas/días después). cancelFulfillment() sí cancela de verdad
  (cancellation/batch/order existe y está confirmado, a diferencia del
  refund de ePayco que quedó sin implementar).
- Solo 1 paquete por cotización/guía (límite real de la API, confirmado:
  "min 1, max 1") -- el carrito se agrega a un solo paquete. Como hoy
  NINGÚN producto tiene peso/dimensiones cargados (confirmado en vivo:
  18 productos activos, 0 con weight), se usa un paquete de fallback
  conservador completo en vez de mezclar datos reales con inventados a
  medias -- la cotización no va a ser precisa hasta que se carguen esos
  datos (tarea de datos, no de código, fuera de alcance de este commit).
- Frontend: cambio chico pero necesario en checkout-client.tsx/
  medusa-cart.ts -- el checkout mandaba el nombre de la ciudad a Medusa,
  nunca el id DIVIPOLA (aunque el form sí lo tenía disponible). Hay
  municipios con el mismo nombre en distintos departamentos de Colombia,
  así que el nombre solo no alcanza para identificar la ciudad sin
  ambigüedad -- se guarda el id real en la metadata de la dirección
  (Medusa sí tiene ese campo), que el fulfillment provider lee para
  derivar el código DANE real que pide EnvíoClick (5 dígitos + "000" de
  relleno, confirmado contra su propio ejemplo: "11001000" = Bogotá).

Pendiente de verificar con una llamada real (no se quiso generar una
guía de prueba en la cuenta real del usuario sin avisar): /shipment_sandbox
y cancellation/batch/order, verificados contra la spec oficial real
pero no probados en vivo todavía.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-08 21:11:43 +00:00
gitea-actions e42d588514 chore(gitops): deploy Medusa v1.0.233 [skip ci] 2026-09-07 04:47:15 +00:00
devops e2938248f8 chore: release v1.0.232 [skip ci] 2026-09-07 04:23:21 +00:00
devops d4716382d3 Merge fix/epayco-pse-reemplaza-payu into main
Build and Push Medusa / Escaneo de Secretos (Gitleaks) (push) Successful in 30s
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 23s
Build and Push Medusa / Construir y publicar Medusa (push) Failing after 4m19s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 18m42s
2026-09-07 03:58:44 +00:00
devopsandClaude Sonnet 5 12c4afa09c fix(payments): reemplazar PayU LatAm por ePayco como pasarela PSE
PayU LatAm (integrado en el commit anterior) resultó inviable: Rapyd
compró ese negocio completo en LatAm/África en 2023, y el registro real
del usuario quedó en la plataforma de Rapyd (board.rapyd.net,
credenciales access_key/secret_key incompatibles con el módulo ya
construido, API completamente distinta). Se evaluó reconstruir contra
Rapyd, pero el usuario comparó costos para su volumen real (~8
ventas/mes) y encontró que ePayco cobra menos en PSE. Se investigó
ePayco en vivo: es 100% de Davivienda desde 2024, acepta liquidación a
cualquier banco colombiano (no exige Bancolombia/Nequi como Wompi) y da
tarifa preferencial a cuentas Davivienda -- el usuario ya tiene una.
Mejor encaje de negocio y más barato que PayU/Rapyd. Confirmado como
elección definitiva.

- src/modules/epayco-pse/ reemplaza a src/modules/payu-pse/: mismo
  contrato AbstractPaymentProvider (initiatePayment/authorizePayment
  "pending_authorization"/getWebhookActionAndData con firma SHA256
  verificada), pero envuelve el SDK oficial `epayco-sdk-node` en vez de
  llamar la API cruda -- leyendo el código fuente del SDK (no la
  documentación pública, que resultó desactualizada en más de un campo)
  se confirmó que el protocolo real de ePayco para PSE es bastante más
  particular de lo que sugieren los ejemplos: cada campo del payload se
  cifra con AES usando la private key del comercio, más un login previo
  que da un bearer token que también viaja en la misma request.
  Reimplementar esto a mano tenía mucho más riesgo de error que delegar
  en el SDK mantenido por el propio proveedor.
- Corregido en el camino: el método real para listar bancos es
  `bank.getBanks()`, no `pseBank()` (así aparecía en un resumen de
  búsqueda, pero no existe en el SDK real -- confirmado leyendo
  node_modules/epayco-sdk-node/lib/resources/bank.js directamente). El
  campo real para la URL de confirmación es `method_confirmation`
  (con guión bajo en medio), no `metodoconfirmacion` como mostraba la
  documentación pública -- confirmado contra tests/bank.js del propio
  paquete.
- retrievePayment sí se implementó esta vez (endpoint de validación de
  ePayco documentado); refundPayment sigue sin implementar -- ese
  endpoint no quedó verificado en vivo, tira error explícito en vez de
  fingir éxito.
- Frontend: el step de pago recupera el selector de banco + tipo de
  persona + documento (a diferencia del diseño que se había planeado
  para Rapyd, donde esos datos se recolectaban en la página del propio
  Rapyd/SafetyPay) -- ePayco sí necesita esos campos de nuestro lado,
  como PayU.
- Dos puntos quedan sin verificar contra un sandbox real (anotados en
  el código con qué hacer si fallan): el nombre exacto del campo con la
  URL del banco en la respuesta de bank.create() (initiatePayment tira
  un error con el payload completo si no matchea ningún candidato
  probado), y si p_cust_id_cliente/p_key del webhook son iguales a las
  API keys o valores aparte del dashboard de ePayco.

Verificado: build real de Medusa con las 7 env vars EPAYCO_* dummy,
smoke test del wrapper del SDK cargando y la verificación de firma
dando el resultado esperado contra un caso conocido, typecheck+lint+
build completo del frontend.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-07 03:58:33 +00:00
gitea-actions f0b4245676 chore(gitops): deploy Medusa v1.0.229 [skip ci] 2026-09-07 02:24:57 +00:00
devops e9e78e64c1 chore: release v1.0.230 [skip ci] 2026-09-07 02:02:25 +00:00
devops 95cf791737 Merge feat/payu-pse-pago into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 1m8s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 14m42s
Build and Push Medusa / Escaneo de Secretos (Gitleaks) (push) Successful in 22s
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 19m56s
2026-09-07 01:18:06 +00:00
devopsandClaude Sonnet 5 2ceea23f40 feat(payments): integrar PayU LatAm (PSE) como pasarela de pagos
ADR 0009 ya había decidido PayU LatAm como proveedor (única opción que
no exige cuenta Bancolombia/Nequi) y confirmado que no existe ningún
plugin real de Medusa para su API -- los paquetes que aparecen
buscando "PayU" son para PayU Polonia/CEE, API completamente distinta
(clientId/posId/secondKey vs. apiLogin/apiKey/merchantId/accountId).
Este commit implementa esa decisión: módulo de pago custom
(AbstractPaymentProvider) para PSE (transferencia bancaria), primer
alcance del método de pago -- Nequi/Daviplata quedan fuera por ahora.

Backend (commerce-backend):
- src/modules/payu-pse/: initiatePayment arma y postea SUBMIT_TRANSACTION
  contra la API real de PayU LatAm; authorizePayment devuelve
  "pending_authorization" (PSE es async, la confirmación real llega por
  webhook, no en el momento de completar el carrito); getWebhookActionAndData
  valida la firma MD5 del webhook antes de confiar en cualquier
  confirmación de pago -- falla cerrado si no matchea. refundPayment/
  retrievePayment tiran error explícito en vez de simular éxito: esos
  endpoints de PayU no quedaron verificados en vivo y hay dinero real de
  por medio.
- No hace falta un subscriber propio para completar la orden -- el
  subscriber nativo de Medusa (payment-webhook + process-payment-workflow)
  ya hace ese trabajo con los métodos de arriba bien implementados
  (confirmado leyendo el código fuente instalado de @medusajs/medusa
  2.18.0, no la documentación).
- Correlación webhook↔sesión: Medusa inyecta su propio session_id en
  `data` antes de initiatePayment; se usa ese mismo valor como
  referenceCode de PayU, así el reference_sale que vuelve en el webhook
  ya es directamente el session_id de Medusa.
- src/lib/payu.ts: cliente HTTP + firmas (orden y webhook, fórmulas
  distintas, confirmadas contra el SDK PHP oficial de PayU).
- src/api/store/payments/pse-banks/route.ts: lista de bancos PSE,
  cacheada en memoria.
- medusa-config.ts, Dockerfile, configmap/secrets.template: 7 env vars
  nuevas (PAYU_API_LOGIN/API_KEY/MERCHANT_ID/ACCOUNT_ID/ENV/RESPONSE_URL/
  NOTIFY_URL), dummies de build agregados, secrets con placeholder
  "CAMBIAR".

Frontend (ecommerce):
- Nuevo step "payment" en components/checkout/checkout-client.tsx
  (reemplaza al step "review" que solo ofrecía WhatsApp): selector de
  banco, tipo de persona (N/J), tipo/número de documento, botón "Pagar
  con PSE" que crea la sesión de pago, completa el carrito y redirige
  al banco (navegación completa, no iframe -- así lo exige PayU).
  WhatsApp queda como respaldo manual si falla la iniciación del pago.
- lib/headless/providers/medusa-payment.ts + 3 rutas proxy nuevas bajo
  app/api/cart/, mismo patrón que el resto del carrito
  (medusaCartFetch, ahora exportado desde medusa-cart.ts).
- app/checkout/pse/return/: página de vuelta del banco -- nunca afirma
  éxito, la confirmación real es el webhook async.

Arranca contra las credenciales de sandbox genéricas y públicas de
PayU (developers.payulatam.com) mientras el usuario termina su propio
registro de comercio -- swap de las 4 credenciales via secret cuando
estén listas, sin cambios de código.

Verificado: build real de Medusa con las env vars dummy (no solo tsc),
tipos de AbstractPaymentProvider/WebhookActionResult/PaymentActions
confirmados contra @medusajs/utils y @medusajs/types instalados
(node_modules limpiado después), typecheck + lint + build completo del
frontend, páginas nuevas renderizando sin error. Pendiente: prueba
end-to-end contra el sandbox real de PayU (necesita el backend
desplegado) y habilitar el provider en la región Colombia desde el
Admin.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-07 01:17:22 +00:00
devops 4d1804eeeb chore: release v1.0.228 [skip ci] 2026-09-06 21:46:27 +00:00
gitea-actions 9b8b96fd02 chore(gitops): deploy Medusa v1.0.227 [skip ci] 2026-09-06 21:31:24 +00:00
devops 313bb2eab4 Merge fix/navbar-departamentos-hover-gap into main
Build and Push Medusa / Escaneo de Secretos (Gitleaks) (push) Successful in 27s
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 23s
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 26m6s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 14m54s
2026-09-06 21:04:24 +00:00
devops 710da06c0a Merge fix/catalog-sidebar-scroll into main 2026-09-06 21:04:23 +00:00
devopsandClaude Sonnet 5 1aa7802a61 fix(navbar): el menú Departamentos no se cierra al mover el cursor hacia él
El panel del mega-menu tenía mt-1 respecto al botón -- como es
position:absolute no suma a la altura del contenedor que escucha
mouseenter/mouseleave, así que ese margen quedaba como una franja
muerta: mover el cursor del botón hacia el panel disparaba
mouseleave a mitad de camino y cerraba el menú antes de poder hacer
clic en una categoría (reportado en vivo).

Se elimina el gap (mt-1) y se agrega un delay de 200ms antes de cerrar,
cancelable si el cursor vuelve a entrar, como margen extra para
movimientos rápidos o en diagonal cerca del borde.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-06 21:04:16 +00:00
devopsandClaude Sonnet 5 b83722e9c5 fix(catalog): scroll propio en el sidebar de filtros
El <aside> de Filtros es sticky pero sin altura máxima ni overflow
propio -- con 30+ categorías más marca/edad/precio, el panel se pasa
del viewport y queda inalcanzable (reportado en vivo: había que bajar
el zoom del navegador para ver "Marca"/"Edad"/"Precio").

overflow-y-auto + max-h acotado al viewport (solo en lg, que es donde
aplica sticky) le da scroll propio al panel sin depender del scroll de
la página.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-06 21:04:04 +00:00
devops df791e0c28 chore: release v1.0.226 [skip ci] 2026-09-06 19:55:30 +00:00
gitea-actions feda1283d4 chore(gitops): deploy Medusa v1.0.225 [skip ci] 2026-09-06 19:46:05 +00:00
devopsandClaude Sonnet 5 8517102b63 feat(product-gallery): zoom automático de la imagen al pasar el cursor
Antes el único zoom era el modal interactivo (click -> Dialog con scale/
drag). Ahora la imagen principal también hace zoom estilo lupa (2.2x)
que sigue la posición del cursor con mousemove/transform-origin, sin
tocar el modal existente (sigue abriéndose igual con el click).

Solo mouse -- mousemove no dispara de forma continua en touch, así que
en mobile simplemente no aparece el efecto, sin romper nada ahí.

Verificado: tsc --noEmit limpio, página de producto renderiza 200 con
datos mock y el nuevo markup presente. No se pudo verificar visualmente
el hover en un navegador real (sin chromium-cli ni claude-in-chrome
disponibles en este shell headless).

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01THZFwPzrwv6VAbuwmaf5vR
2026-09-06 19:18:11 +00:00
gitea-actions 997a00c284 chore(gitops): deploy Medusa v1.0.223 [skip ci] 2026-09-06 17:16:31 +00:00
gitea-actions 9e1adf4627 chore(gitops): deploy Medusa v1.0.222 [skip ci] 2026-09-04 14:18:07 +00:00
gitea-actions 11ac6d7949 chore(gitops): deploy Medusa v1.0.221 [skip ci] 2026-09-04 05:27:25 +00:00
gitea-actions 8126bb3d81 chore(gitops): deploy Medusa v1.0.220 [skip ci] 2026-09-02 21:53:50 +00:00
devops 601378a77e chore: release v1.0.219 [skip ci] 2026-08-29 20:31:52 +00:00
devops 1dccd0aa6a Merge branch 'feat/out-of-stock-ui' into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 20s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 8m30s
2026-08-29 20:23:02 +00:00
devops 474ac3795b fix(ecommerce): deshabilitar compra y mostrar "Agotado" sin stock real
variant.available (calculado en lib/headless/providers/medusa.ts a
partir de manage_inventory/allow_backorder/inventory_quantity) ya
llegaba correcto hasta el componente, pero ningun boton de compra lo
usaba -- se podia seguir agregando al carrito un producto con stock 0.

Afecta product-purchase.tsx (pagina de producto), mobile-add-to-cart.tsx
(barra fija mobile) y product-card.tsx (tarjetas de catalogo): boton
deshabilitado + label "Agotado" en los tres, mas badge/overlay en la
tarjeta de catalogo.
2026-08-29 20:22:55 +00:00
gitea-actions bb2ad3c317 chore(gitops): deploy Medusa v1.0.218 [skip ci] 2026-08-29 19:19:15 +00:00
devops 42c90d8534 chore: release v1.0.216 [skip ci] 2026-08-29 17:10:35 +00:00
devops cd8d2edd8f Merge branch 'feat/google-oauth-frontend' into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 20s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 8m39s
2026-08-29 17:01:39 +00:00
devops 77389aea19 feat(ecommerce): login con Google para clientes
Implementa el flujo completo de OAuth social de Medusa para el
storefront: boton "Continuar con Google" en account-dialog, ruta proxy
que arranca el flujo (GET /api/customer/google/start) y pagina de
callback en /auth/google/callback (coincide con GOOGLE_CALLBACK_URL del
secret) que resuelve el code/state contra el backend, decodifica el JWT
para distinguir cliente nuevo vs existente, crea el customer si hace
falta y refresca el token a sesion final -- mismo patron de
store/customer-store.ts que login/register por email.

Flujo verificado en vivo contra el backend ya desplegado (GET
/auth/customer/google, /auth/customer/google/callback con state
invalido, /auth/token/refresh con bearer invalido) antes de escribir el
codigo, no solo contra la documentacion.
2026-08-29 17:01:32 +00:00
gitea-actions 7ce11ecbb4 chore(gitops): deploy Medusa v1.0.215 [skip ci] 2026-08-29 16:34:34 +00:00
devops 811e0e0887 chore: release v1.0.213 [skip ci] 2026-08-29 15:24:19 +00:00
devops aee6515890 Merge feat/cuenta-icono-mobile-indicador into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 20s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 12m58s
2026-08-29 15:11:02 +00:00
devops 2e47f7b55d feat(ecommerce): icono de cuenta visible en mobile + indicador de sesion
Pedido explicito del usuario tras probar el login real: el boton de
'Mi cuenta' estaba oculto en mobile (hidden sm:inline-flex, solo
alcanzable desde el menu hamburguesa). Pasa a estar siempre visible en
el header, y agrega un punto verde cuando hay sesion iniciada -- mismo
patron visual que los badges de cantidad de carrito/favoritos, pero de
presencia (con sesion o sin ella), no de conteo.
2026-08-29 15:10:59 +00:00
devops 54be99fa2c chore: release v1.0.212 [skip ci] 2026-08-29 14:33:18 +00:00
devops 3b748cc014 feat(ecommerce): cuentas de cliente reales (registro + login)
Conecta el dialogo 'Tu cuenta ARI' (antes solo ofrecia WhatsApp) al
Store API real de Medusa. Flujo verificado en vivo con un cliente de
prueba real antes de escribir el codigo: registro -> crear customer
-> login -> /store/customers/me, todo confirmado funcionando.

Detalle no documentado que se confirmo en vivo: el token que devuelve
/auth/customer/emailpass/register sirve para crear el customer via
POST /store/customers, pero no queda como sesion real -- hay que
loguear de nuevo (/auth/customer/emailpass) para obtener el token de
sesion. Mensajes de error tambien verificados: correo repetido -> 401
'Identity with email already exists'; credenciales invalidas -> 401
'Invalid email or password'.

Mismo patron arquitectonico que el carrito real (ADR 0009): rutas
puente /api/customer/* (MEDUSA_BACKEND_URL es DNS interno, no resuelve
desde el navegador), store de Zustand con sesion persistida y
resincronizada contra el servidor al rehidratar. WhatsApp se mantiene
como opcion secundaria, ya no es la unica salida.
2026-08-29 14:24:43 +00:00
devops 73f9424331 chore: release v1.0.211 [skip ci] 2026-08-29 05:23:55 +00:00
devops 61024b8f31 feat(ecommerce): selector Departamento/Ciudad con DIVIPOLA real en checkout
Reemplaza los inputs de texto libre de Ciudad/Departamento por dos
selects en cascada, poblados con el dataset oficial de DIVIPOLA (33
departamentos + 1123 municipios, fuente proyecto26/colombia,
verificado contra la codificacion real del DANE antes de incorporarlo
-- id 5001 = Medellin, departmentId 5 = Antioquia, etc.). Sin
dependencia npm nueva (JSON estatico + helper propio).

Se guarda el id DIVIPOLA seleccionado en el estado del formulario, no
solo el nombre -- EnvioClick (la integracion de envios real que
reemplazara la tarifa fija de este ADR) va a necesitar identificar la
ciudad sin ambiguedad, y las transportadoras colombianas referencian
ciudades por este codigo. El nombre derivado del id sigue siendo lo
que se manda a Medusa (shipping_address espera texto, no cambia el
contrato existente).
2026-08-29 05:16:18 +00:00
devops 7dc54a1d20 chore: release v1.0.210 [skip ci] 2026-08-29 04:20:02 +00:00
devops bb2c0bbe85 feat(ecommerce): ADR 0009 - checkout con direccion y seleccion de envio
Siguiente corte tras el carrito real: pagina /checkout de 3 pasos
(direccion -> envio -> confirmar) contra el Store API real, usando la
shipping option que ya se verifico en produccion. Endpoints nuevos
(setShippingAddress, getShippingOptions, addShippingMethod) probados
en vivo con un carrito de prueba real antes de escribir el codigo --
direccion, opciones de envio y total ya confirmados correctos
(80.000 + 5.000 = 95.000).

El pago (PayU custom) sigue sin existir, asi que el ultimo paso sigue
siendo WhatsApp -- pero ahora el mensaje incluye direccion, metodo de
envio y total real en vez de solo la lista de productos. El boton del
CartDrawer pasa de abrir WhatsApp directo a llevar a /checkout.
2026-08-29 04:12:11 +00:00
devops cdab538cfb chore: release v1.0.209 [skip ci] 2026-08-29 03:53:43 +00:00
devops f124ae0bbd Merge fix/carrito-thumbnail-real into main
Build and Push Frontend / Escaneo de Secretos (Gitleaks) (push) Successful in 21s
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 11m47s
2026-08-29 03:24:11 +00:00
devops b8ce9ded87 fix(ecommerce): carrito muestra la foto real del producto
Reportado en produccion: el carrito mostraba el logo generico de ARI
en vez de la foto del producto. Verificado en vivo: item.thumbnail
viene null en la respuesta de Medusa para todo el catalogo real
(confirmado tambien contra /store/products directamente -- el campo
thumbnail del producto es null en la fuente, no solo omitido en la
respuesta del carrito). El catalogo ya resuelve esto cayendo a
images[0] (mapProduct() en medusa.ts); la linea del carrito necesita
pedir esa relacion explicita via fields=*items.product.images (no
viene por defecto) y aplicar el mismo fallback.
2026-08-29 03:24:09 +00:00
devops b12dd848af chore: release v1.0.208 [skip ci] 2026-08-29 02:52:32 +00:00