All projects

Enterprise Super App — Sale Service

Iran Fava Gostaresh · IKCO Group

High-traffic vehicle sales app covering direct-sale, lottery and flash-sale workflows, shipped as an installable PWA — rebuilt around measurement, cutting the first visit by 69% and taking Lighthouse accessibility to 100.

Role
Senior Frontend Engineer — Frontend Architect
Period
2025 — Present
Type
Enterprise
Enterprise Super App — Sale Service screenshot

Overview

The sales service inside the IKCO Group super app: browsing the active sale plans, registering for a release under direct-sale, lottery or flash-sale rules, paying, and tracking the order afterwards. One build runs in three places — embedded in the super app’s native WebView, installed to the home screen as a PWA, and as an ordinary browser tab — and it is the surface that absorbs launch-day demand.

The problem

Demand does not spread out. A sale opens at a published minute and the whole eligible population arrives in the same few seconds, almost all on mobile, many on connections that are slow rather than absent. At that shape of traffic every kilobyte of the first visit is a capacity decision, not a preference. The harder problem was that nobody could say what the first visit actually cost. The figure on record was the size of the files on disk, and the performance score everyone quoted had been taken against the dev server — which does not bundle, does not minify and runs React in development mode. So the work started as measurement rather than optimisation, and the first real request to a running instance showed the largest bundle arriving uncompressed, with no Content-Encoding header at all.

Approach

  • Measured the delivered bytes rather than the built ones. Compression turned out to be off for everything except HTML — the server default — so 62% of the JavaScript weight came back from a configuration change, with no application code involved.
  • Split the bundle at the route level, with one deliberately small shared chunk holding only what every route needs, so it survives in the browser cache across deploys. Everything else was left to be pulled in beside the route that actually uses it — the date-picker and calendar libraries load with the one form that needs them, not on the landing page.
  • Replaced four TTF font weights with subset WOFF2 generated by a build step: 476 KB down to 135 KB, and four separate families collapsed into one family with four real weights.
  • Built two dependency-free audit harnesses on the Chrome DevTools Protocol, because the internal network could not reach the npm registry and Lighthouse could not be installed. They drive the production build and measure effective rendered contrast, rendered touch-target size and accessible names, alongside FCP, LCP, CLS and on-the-wire transfer sizes.
  • Ran the accessibility audit through real navigation — clicking into each page and then confirming the URL actually landed — after the first authenticated run reported four clean guarded routes that it had never reached, having silently audited the redirect target four times instead.
  • Split a colour token that was doing two jobs. One variable served both secondary text and borders, so fixing its 2.54:1 contrast against white would have darkened every border on the site; a separate placeholder token moved the thirteen text uses without touching the fifteen border uses.
  • Derived every loading skeleton’s height from the real component’s CSS instead of guessing, with a comment beside each number naming the class it came from, so a design change does not silently reintroduce the jump.
  • Wrote per-route caching strategies for the service worker, and was explicit about what must not be cached: authenticated endpoints are declared NetworkOnly rather than merely omitted, because browser cache is shared between everyone using the device. The catalogue is network-first with no timeout on purpose — stale prices should appear when the network is genuinely down, not when it is slow.
  • Unified 401 handling across all four runtime modes, where only one had been correct; broke a cross-domain SSO redirect loop by detecting whether the session had ever succeeded; and moved token capture out of React entirely, since a child effect ran before the effect that stored the token and sent the first request unauthenticated.
  • Renamed store bindings across 27 files to the use* convention, so the React Compiler stops treating store reads as pure calls and memoising them behind a sentinel — which breaks hook ordering and crashes the component in production.
  • Measured a font-preload optimisation and then deleted it. It did what it was meant to, moving font discovery from ~1,600 ms to ~205 ms, but seven runs per arm showed FCP and LCP both about 400 ms worse: on a throttled mobile link bandwidth is the constraint, not discovery order. The reasoning and the numbers were left in the source so the next person does not walk the same path.

What shipped

  • First-visit payload 1,668 KB → 525 KB (−69%); initial JavaScript 986 KB → 370 KB, CSS 206 KB → 20.3 KB, fonts 476 KB → 135 KB.
  • Lighthouse accessibility 98 → 100 and SEO 92 → 100, with audit coverage raised from 14 to 22 authenticated page states.
  • Cumulative layout shift on the landing page 0.10 → 0.001.
  • Installable PWA with per-route Workbox strategies, manual service-worker registration so the embedded WebView build does not register one, and an update that waits for the user rather than refreshing mid-form.
  • An enforcing Content-Security-Policy validated across 11 routes with no violations, plus DOMPurify sanitisation of CMS-supplied contract HTML.
  • Zero ESLint errors, exhaustive-deps suppressions reduced from 28 to 7, and Prettier enforced by a pre-commit gate.
  • The largest file down from 2,050 to 1,360 lines, six copies of a modal collapsed into one component, and thirteen hand-rolled empty states across nine files replaced by a single one.

Outcome

The launch surface is now sized by measurement instead of estimate, and the two harnesses run against the production build, so a regression in contrast, touch-target size or first-visit weight is caught by a number rather than by review. The most useful result was a negative one — an optimisation that worked, was measured, cost 400 ms, and was removed with its evidence left behind.

More work