What's new
Every change to the shop, in plain language.
The same changes written for people who run the shop rather than build it. For commit hashes, file paths and migration notes, read the technical changelog.
29 October 2026 — Shipping price and refund instructions
The delivery price shown when a customer picks a courier is now the price they are charged. Until now the list priced the parcel at 1 kg minimum while checkout charged 2 kg, so a light order could show a lower price and then charge more.
The staff guides for Payments and Orders were wrong about refunds and are fixed:
- Refund from the order in the admin, never from the Curlec dashboard. Doing both pays the customer back twice.
- Cancelling an order refunds it automatically. Do not refund again afterwards.
- A customer charged with no order is not resolved by waiting. Look up the
pay_reference in Curlec and pass it to the developer the same day.
6 September 2026 — Checkout and reliability fixes
Payment returns now recover the original basket from the signed payment receipt. They no longer depend on a cookie surviving the trip to the bank or create a replacement payment session. Returning twice uses Medusa's existing order completion.
Connecting EasyParcel now requires a signed-in administrator. Open Shipping → Connect or renew EasyParcel in the admin and finish in the same browser. The courier charged at checkout is also the courier retained for booking.
Fitment answers cannot be counted twice when a request is retried. Return requests must be saved before success is reported; identical retries reuse the same request and notification keys. A failed notification leaves the saved request visible on the order, and the customer can retry safely.
These changes went live on 29 October 2026. An end-to-end gateway and courier rehearsal is still to do.
4 September 2026 — The shop can run itself
You can manage cars from the admin now
All 701 vehicles are editable in a new Vehicles page: search, add, edit, delete. Until today every new model, corrected year range or merged duplicate needed a developer to run a script, which for a shop built around "find the part for your car" was the one thing it could not do for itself.
The page shows how many parts each car has, which is how you spot a duplicate worth merging — 20 vehicles currently have no parts at all, and 13 have no years set. Deleting a car that parts are listed against asks twice, because that tag is what makes those parts findable for people who drive one.
In stock or pre-order is a switch
Marking a part out of stock used to mean editing raw metadata and typing a key by hand, on the most frequent job at the counter. A mistyped key does not error — it silently leaves a sold-out part advertised as available.
The shop finds out when something breaks
A server error now emails you, with the route and the time. It is deduplicated, so a broken page emails once an hour rather than once a request, and capped so a bad deploy cannot send four hundred. Separately, a watchdog loads the actual shop every 15 minutes and tells you if it stops answering.
Baskets get one reminder
A cart with an email that never became an order now gets a single reminder four hours later, with a link that restores the actual basket rather than asking someone to find eleven parts again. Never twice, and never after two days.
Referral codes, for the walk-in customers
Every customer now has a short code they can hand to someone at the counter. Codes avoid characters people confuse — no O/0 or I/1 — because someone reads one off a receipt and types it on a phone. A link with a code is remembered for thirty days, since being handed a card and getting round to ordering are weeks apart.
What a referral is worth is your decision, so the account page says it is arranged at the counter rather than promising a discount nobody has agreed. The admin shows each customer's code and how many people used it.
"Did it fit?"
The delivery email now asks, and the answer takes two taps on the order page. Confirmations show on the product as "3 buyers have confirmed this fitted their car" — which is the thing that settles the doubt that stops people buying parts online. A "no" is just as useful: it tells us the fitment data is wrong.
Shipping has its own page
Whether EasyParcel access is alive and how long it has left, whether rates are answering right now, and every parcel that has gone out.
3 September 2026 — Customers pick their courier
The courier is a dropdown now
Checkout used to quote whichever courier was cheapest and give the customer no say. It now lists every courier that will carry the parcel to that address, priced for that exact cart, and the customer picks one from a dropdown.
Eight couriers for a Peninsular address, from SPX Xpress at MYR 8.60 up to Skynet at MYR 20.74. East Malaysia gets seven — Skynet does not serve Sabah, Aramex does not serve Sarawak — and the list changes on its own to match.
Only couriers that collect from the shop are offered. EasyParcel quotes most of them twice, once for drop-off and once for pickup at the same price, and drop-off means someone drives the parcel to a collection point. Lazada and Celsius are drop-off only, so they are not on the list.
The flat "Standard delivery" option has been removed.
Returns, receipts, refunds and delivery updates
The order lifecycle had six places where a customer simply had nowhere to go. All six now exist:
- Returns. A "Request a return" on the order page that emails the counter and the customer and records it on the order. The returns policy already existed and is linked from the form.
- Receipts. A printable invoice on every order. It is headed "Invoice", not "Tax Invoice" - that phrase means something specific under SST and should only appear once the shop holds a registration to print.
- Failed payments. The customer is now told, and told first that no money left their account, which is the only thing anyone wants to know at that moment.
- Refunds made in Curlec. Medusa could not see them, so the order still read as fully paid. They are now recorded on the order and emailed to the shop.
- Cancellations. The email always promised a refund and nothing sent one. Cancelling now refunds automatically, and the wording only claims the money is moving when it actually is.
- Deliveries. A parcel that arrives now closes the order and tells the customer, rather than the story ending at "on its way".
Stock: an honest promise instead of a false one
Nothing in the system holds a stock count, and the shelf is shared with walk-in customers in Jitra, so no software can stop the same last part selling twice. Rather than pretend otherwise, the shop now says what it actually does: every part is checked against the shelf before it ships, and if one has gone you get a call and a refund the same day. It appears before payment as well as after.
Delivery to Sabah and Sarawak no longer loses money on an outage
When EasyParcel cannot be reached the shop quotes a fallback rate. That rate was RM 25 for East Malaysia against a real cost of RM 62.90 to RM 120.87, so every outage quietly sold Sabah delivery at a loss. It is now RM 65.
Couriers are searchable, and show their own logo
The courier list is a combobox you can type into rather than a plain dropdown - typing "pos" gets you Pos Laju without reading the list - and each row carries the courier's own logo, served by EasyParcel rather than drawn by us.
Loading states are skeletons everywhere
Seventy-six placeholder boxes across the cart, order confirmation, product grid and account pages were hand-written and slightly different from each other: square where the real content is rounded, and in a grey that belongs to no part of the palette. They are one component now, so a loading page looks like the page that is coming rather than a set of grey bars. The account pages had a spinner and now show the shape of your orders instead.
The first version of this quietly charged the wrong price
Worth recording plainly, because everything on screen looked right. The first build let the customer choose, but the shop was still charged for the cheapest courier whichever one they picked. Nothing in any receipt, order or admin screen would have shown the difference.
It was caught by checking the cart total after choosing a mid-priced courier rather than trusting that the choice had registered. Picking Pos Laju, quoted at MYR 12.09, produced a cart charging MYR 8.60.
Parcels still cannot be booked automatically. A courier is chosen, priced and recorded on the order, but the shipment has to be submitted to EasyParcel by hand and no tracking number comes back. See the launch audit for the full list of gaps around returns, refunds, receipts and delivery updates.
1 September 2026 — Going live
Delivery is priced by the courier now
Checkout quotes a real rate from EasyParcel for the actual destination, instead of one flat price for the whole country. Penang and Kuala Lumpur come back at MYR 8.60; Kota Kinabalu at MYR 62.90, which is what East Malaysia genuinely costs. The cheapest courier of the ones offered is the one quoted.
The flat option stays alongside it on purpose: if EasyParcel is unreachable, a cart is never left with nothing to choose.
Movement is consistent now
Animation runs through one shared set of timings instead of each component choosing its own, so things move the same way across the shop. It respects the "reduce motion" setting in your phone or computer — if that is on, nothing animates at all rather than animating slowly.
Payment logos
The footer shows FPX, Visa and Mastercard as plain badges. Drop the official
logo files into public/brand/payments/ and they appear automatically — see the
README there for where to get them.
These are registered trademarks, so they have to be the official artwork. A redrawn or AI-generated version is a wrong mark, which is worse than none and is a trademark problem.
Two things I broke, now fixed
Yesterday's mobile change made the filters collapse behind a toggle on phones — and accidentally hid them completely on desktop. And the Shop menu's sub-category links pointed at addresses that do not exist, so clicking one gave "Page not found". Both fixed.
Emails now actually send
Order confirmation, despatch, cancellation, password reset and a welcome message
all send through Resend from info@autoxspare.com. Before this the shop sent
nothing at all — a customer could pay and hear silence.
The account page is worth opening
It used to report that your profile was "75% complete" and how many addresses you had saved. Both are facts about the account rather than anything you came there to do, and a percentage tells you that you are incomplete without saying what is missing.
It now leads with your car, then tells you plainly what to add ("Add your address") and why. The help panel at the bottom used to link to a customer service page that did not exist — a 404 offered to someone who needed help. It points at the contact page and the WhatsApp number now.
A footer that says what this shop is
Three generic columns and a newsletter box became something specific to Autoxspare: a brand-blue strip leading with "Not sure it fits?" and a WhatsApp button, then columns for finding a part, getting help, and how payment works.
The newsletter box is gone. It stored nothing — the form posted to the contact page — so it was collecting addresses it could not honour.
Share and Compare do something now
Share did nothing on a computer. navigator.share exists in desktop Chrome,
so the code took that path and then swallowed every failure, with no fallback.
It now copies the link and says so. Compare worked but only tinted an icon,
so it looked like nothing happened; the button now reads "In compare".
Delivery dates skip Sundays
The estimate counted calendar days, so it could promise delivery on a day the shop is closed. It counts working days now, using the shop's published times: 1–2 days to dispatch, 2–5 across Peninsular Malaysia.
Still an estimate, not a courier quote. Once EasyParcel is connected it will use the real transit time for the actual postcode.
Signing up told you the wrong thing
Trying to become a member showed "Error: Invalid email or password" — a login error, on a sign-up form, which reads as though the form is broken. What had actually happened is that the email already had an account.
It now says so, and points you at signing in or resetting the password. Other sign-up failures give a plain sentence instead of a raw error code.
victorlee@vigordigital.org and info@autoxspare.com are admin logins.
Use a different email for a member account — one email cannot be both.
Cart and checkout look like the shop now
Buttons were black with square corners, which is the default of the software underneath, not this shop. They are brand-blue pills matching the product page. The cart is a proper card with an Order summary panel, and the checkout header carries the wordmark.
Claims we could not stand behind are gone
The band above the footer promised "Free Shipping" while checkout charges a flat MYR 10, and "100% Money Back — 30 days to Return", which is a returns policy nobody has confirmed. Both replaced with things that are true: where orders ship from, that parts are filtered to your car, and the WhatsApp number.
Mobile
The filters no longer fill the whole first screen on a phone — they collapse behind a "Filter & sort" toggle, so products start at the top where they should. The bottom bar reorders to Home, Shop, Wishlist, Cart, Account, so the two buying-related tabs sit together.
The Shop menu is readable now
Every link in the dropdown was italic capitals, because the panel sat inside the top nav and inherited its styling — so nothing scanned. Category headings keep that voice; the parts underneath are plain text.
The columns balance too. Seven categories forced into seven equal columns left Suspension with six items beside Driveshaft with none; they now flow and fill evenly. And the empty space on the right asks the question a parts shop should always ask: it shows your saved car with a link to parts that fit, or offers to pick one, with the shop's phone number underneath.
Also fixed a name that read as a typo: vehicles showed as "Alfa Romeo Romeo 147 156", because the brand was stored as "Alfa" with "Romeo 147 156" as the model.
Add to cart was broken, and is fixed
For about an hour, clicking Add to cart or Buy it now did nothing at all on every product — no error, no message, nothing. Caused by my own tidy-up: the European warehouse was deleted, but the invisible link joining it to the shop survived, and that broke the delivery lookup that runs every time an item is added.
Also fixed in the same pass: the cart no longer says "Variant: Default Title" on every line, quantity is now a proper editable field with −/+ instead of a grey dropdown capped at 10, and the checkout header carries the AUTOXSPARE logo rather than plain grey text.
Payments page, and the European leftovers are gone
A new Payments item in the admin shows what Curlec actually captured, the fees it deducted, refunds, and what it settled to the bank. Those figures will not match the Analytics page to the sen — a gateway reports after fees, on its own schedule — and seeing both is the point.
The shop was also still carrying pieces of the European starter it was built from: a European Warehouse and seven European tax regions (Denmark, UK, Germany, Sweden, Italy, Spain, France). All removed, and a Malaysian tax region created in their place.
The Malaysian rate is set to 0%. Malaysia charges SST, which for most parts retailers is already paid upstream rather than added at the till — but whether the business must register and charge is a question for your accountant, not a default. Say the word and it takes one command to change.
An analytics page in the admin
A new Analytics item in the admin sidebar: revenue and orders for today, the week and the month, average order value, a 14-day trend, best sellers by units, and recent orders. It reads zero right now because there are no orders yet.
These are the figures the shop recorded, not what the payment gateway settled — those differ by fees and timing, and are shown in Curlec instead.
The shop currently sends no email at all — no order confirmation, no despatch notice, no password reset. Medusa does not send mail on its own and no provider is connected yet. This has to be fixed before launch.
The checkout no longer names the wrong company
The last screen before paying said you accepted "Medusa Store's Privacy Policy" — the name of the software the shop is built on. It now names Autoxspare and links the actual Terms and Privacy pages.
Parts say which car they fit, readably
The fitment panel printed the internal code
(toyota-vios-ncp93-at-mt-2007-2012-esr2030000). It now reads
"Toyota Vios NCP93 2007–2012".
Your car no longer gets forgotten when you click a category
The worst bug found so far. You picked your Vios, clicked "Suspension", and got 1,539 parts — mostly Proton — while the header still showed "Toyota Vios NCP93". The page looked filtered and was not, which for parts means buying something that does not fit.
The filtering itself was always right; the category links simply dropped the car. The same journey now returns 11 parts, all of them for the Vios.
Sub-categories look like the rest of the shop
They were a stack of blue underlined links with arrows, left over from the software the shop is built on. They are now filter chips, and they keep your car when clicked.
Dead links behave properly
A link to a product that no longer exists used to return a server error instead of a "not found" page. That matters when the old shop's addresses are retired: search engines drop a "not found" page but keep retrying an error, so the old links would have lingered in Google.
The admin sign-in page is ours
The page you log into no longer says "Welcome to Medusa" with the Medusa logo. It shows the AUTOXSPARE wordmark and is always in light mode, so the black logo stays readable no matter how your computer is set. Signing in is unchanged — same address, same email, same password.
These docs
The site you are reading. A user guide, this changelog, and an API reference,
published at docs.autoxspare.com and updated as part of the work rather than
afterwards.
Payments are live
Curlec is switched to live keys. Real customers can pay by FPX online banking or card, and the money settles to the shop's account. Card details never touch our system.
Test mode still exists for practice, and the admin home page shows a LIVE or TEST badge so you can always tell which is on.
Nobody has completed a real payment through FPX yet. The first live order is worth watching closely, ideally a small one you make yourself.
Ringgit only
The shop used to also list Euro and US Dollar, left over from the original setup. Those are gone, which removes the chance of saving a price that quietly never applies to anything.
Somewhere to ship from
The shop now has a warehouse address — Jitra, Kedah — and one delivery option covering all of Malaysia. Before this, checkout could reach the delivery step and offer nothing at all.
Pre-order labelling makes sense again
A product could previously show "Pre-order" and "Buy it now" side by side, which contradicted itself. A pre-order item now says Pre-order and hides the buy-now shortcut. The terms page was also reformatted — it had been rendering as one unbroken wall of text.
Better failure messages
A customer whose payment failed could be shown a raw React error code. They now get a plain sentence saying nothing was charged, with the shop's phone number.
Search suggests as you type
The search box offers matching products while you type instead of waiting for you to finish. The store sidebar filters were restyled at the same time.
31 August 2026 — Rebuild and integrations
The shop asks the only question that matters
The homepage now leads with which car do you drive, rather than a catalogue. Pick brand, model, engine and year, and see only parts that fit. The choice follows you as you browse, and now survives being shared as a link.
If a vehicle is chosen and nothing in a category fits it, the page no longer comes up empty — it shows everything in that category with a note explaining the vehicle filter was set aside.
Vehicle data repaired
The fitment data imported from Shopify was inconsistent enough that filters missed parts that genuinely fit. It was cleaned up, and the fitment dropdowns became searchable — useful when a list runs to hundreds of models.
Search that works
Search was, quite simply, broken — it returned nothing. It now works, including for part numbers written with brackets, and a search with no results offers somewhere to go next.
Payments and delivery built
The Curlec payment provider and EasyParcel delivery provider were both written from scratch for Malaysia. European payment methods were removed.
Parcel weights recovered
The original import dropped variant weights, which delivery pricing depends on. 4,404 were recovered.
Sign in with Google, Apple or Facebook
Built, but not switched on — each needs credentials from that provider first.
A shop that looks like itself
The homepage and product page were rebuilt, and the last Medusa and Next.js branding was removed from the customer-facing shop. A full accessibility and mobile pass followed.
18 August 2026 — Depth
- Mobile tab bar along the bottom, the way an app behaves, with a working Wishlist tab
- Wishlist tied to your account, so saves made before signing in are merged in rather than lost
- Store filters restored, with a native sort control on phones, and filters that match nothing are no longer offered
- Browse past the first 100 products — the catalogue was previously capped
- Parent categories show their products instead of appearing empty
- Shop megamenu, product rails, compare, hover previews and the hero carousel
- Search rankings preserved across the move from Shopify, so existing Google results keep working
- Contact, terms and privacy pages, which the footer had been linking to without them existing
- Stock status carried over from Shopify, and pre-order items labelled
- Faster images — resized versions instead of full-resolution originals
- Moved closer to customers — the shop now runs from Singapore rather than the US, which cut loading times substantially
17 August 2026 — Images and the theme
- All product images moved to permanent storage (8,708 references repointed). They had been served from Shopify, which would have broken the moment that account closed.
- Listing thumbnails fixed — several products showed an old or missing picture
- The storefront rebuilt to match the shop's existing look, including the header, footer and mobile drawer
15–16 August 2026 — Foundation
- The shop was built from scratch, not migrated: a Medusa backend, a Next.js storefront, and deployment to Railway and Vercel
- 4,445 products and 3,299 vehicle-fitment links imported from Shopify
- Product descriptions converted from Shopify's HTML into clean text
- A full audit of the old Shopify shop, to establish what actually had to be rebuilt
Known gaps
Things that are genuinely not finished, so nobody is surprised by them:
| Gap | What it means |
|---|---|
| Stock is not tracked | The shop cannot prevent overselling |
| EasyParcel connection must be verified | Check grant and rates in Admin → Shipping; production status was not rechecked during this audit |
| Social sign-in not switched on | Google, Apple and Facebook are built but have no credentials |
admin.autoxspare.com | Not serving yet; use api.autoxspare.com/app |
| Domain auto-renew is off | autoxspare.com will not renew itself |
| 47 product weights look wrong | 6 are off by a decimal, 41 have none |