villaEcommerceWeb
The Vue 2 + Quasar storefront behind shop.villamarket.com and dev.villamarket.net.
Branches map to environments
| Branch | Environment | VUE_APP_MODE |
|---|---|---|
master | shop.villamarket.com | master |
feature | dev.villamarket.net | feature |
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 matchThree 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/servicesAPI 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.