villaEcommerceWeb

The Vue 2 + Quasar storefront behind shop.villamarket.com and dev.villamarket.net.

Branches map to environments

BranchEnvironmentVUE_APP_MODE
mastershop.villamarket.commaster
featuredev.villamarket.netfeature

This trips people up: dev is built from feature, not master. Confirm which build is live by comparing the app version in the browser console with the branch head:

// console on the site
// > Fetched app version: {version: b8856dd0, gitHash: b8856dd0, ...}
git rev-parse --short=8 origin/feature   # must match

Three separate dev-only bugs in July 2026 were feature regressions where master was already correct, so always diff the two before assuming a bug is real:

git diff origin/master origin/feature -- src/store/v2/config src/store/v2/services

API endpoints

src/store/v2/config/env.js maps a relative path onto the current environment’s host, so endpoints must be declared relative and go through that helper:

export const DELIVERY_ENDPOINT = getEndpoint("/api/polygon/getPolygonCost");

Hardcoding an absolute execute-api URL breaks environment isolation — dev then talks to a production API. That has happened twice, in config/delivery.js and in services/calculatePrice.js (2026-07-29-shipping-forced-nationwide).

Delivery type selection

getDeliveryFee in src/views/checkoutV2/CheckoutV2.vue decides between Regular, Express and Nationwide. It calls delivery/GetDeliveryFee, then branches on the response:

if (t.success) { const n = t.top5.filter(e => e.cost >= 0); /* pick branch, set REGULAR */ }
// no match falls through to:
console.log("apply nationwide"); this.delivery.forceNationwide = true;

The fallback is silent and total: forceNationwide disables Regular and Express for every address. So any failure of that endpoint — wrong URL, wrong response shape, network error — presents to a tester as “shipping always defaults to nationwide” rather than as an error.

The console log tells you which path ran. apply regular is healthy; apply nationwide on a Bangkok address is not.

Discount display

Cart and checkout build their Discount line by summing individual fields rather than using totalDiscount. That list has to be kept in step with what calculatecost2 can return, or a coupon lowers the Total while the Discount line still reads 0:

const promotionDiscount =
  (response.bogoDiscount || 0) +
  (response.two4Discount || 0) +
  (response.specificSkuDiscount || 0);

Sites to keep in sync: views/checkoutV2/CheckoutV2.vue and two places in views/cartV2/CartV2.vue.

Service worker

The app registers a Workbox service worker with a precache manifest. Editing a file in S3 is not enough to reach users — the worker keeps serving the precached copy until its revision changes. See patch-dev-web-bundle.