Case study
- Role
- Frontend & Web Developer - architected the front end from scratch
- Organisation
- Vi8e Interactive Pte Ltd
Activate ERP
A mobile-first ERP for retail and distribution: goods receiving, stocktaking, inventory, internal transfers, order assembly, picking, collections and sales orders. The people using it are on a warehouse floor with a phone in one hand, not at a desk, which shaped almost every decision in it.

01 / Overview
What I did.
I architected and built the entire front-end layer from scratch, delivering the mobile apps and the web application from one codebase. I led the mobile implementation specifically: biometric authentication, camera capture for proof-of-receipt photos, geolocation as a verification signal on stock movements, and encrypted storage for keys and tokens. I worked alongside a backend developer, a designer and product stakeholders, and handled the release path through Xcode and Android Studio to both stores.
02 / Architecture
Layers listed outermost first.
How it's put together.
One Vue codebase, three targets. Quasar provides the build modes for iOS, Android and web, and everything platform-specific is isolated behind a thin bridge so the feature code never branches on which device it happens to be running on.
Screens & flows
The operational surface.
Goods receiving, stocktaking, inventory, transfers, picking and collections. Built mobile-first: large targets, short flows, and scanning as the primary input rather than typing.
Design system
One look across phone and desktop.
Quasar components extended with SCSS, so a table on a desktop and a card list on a phone are the same underlying data rendered for the space available.
State
Predictable operational data.
Vuex modules per domain (receiving, inventory, picking) so a screen reads what it needs without becoming the owner of it. This matters when the same stock figure appears in three flows.
API layer
One way in and out.
Axios with interceptors handling auth headers, token refresh and error normalisation in a single place, so no screen has to know how authentication works.
Native bridge
Device hardware, isolated.
Cordova and Capacitor plugins for biometrics, camera, geolocation and secure storage, each wrapped in an internal module. Feature code calls the wrapper; only the wrapper knows the platform.
Release
Two stores from one source.
Builds through Xcode and Android Studio to the App Store and Google Play, tested across simulators and real devices before each submission.
03 / Decisions
Each of these had a credible alternative. The trade-off is stated, not hidden.
Choices, and what they cost.
One Quasar codebase for iOS, Android and web
- Chose
- A single Vue + Quasar source with three build targets
- Instead of
- Native iOS and Android apps plus a separate web front end
- React Native for mobile with a separate web application
- Why
- The front end was one developer. Three codebases would have meant every feature written three times and, in practice, three subtly different products. Quasar's build modes gave genuine platform packaging, not just a responsive website, from one source, which is what made the scope achievable at all.
- Trade-off
- The abstraction sets the ceiling. Anything the framework does not cover has to be bridged by hand, and you inherit the framework's upgrade cycle for all three targets at once.
Native capability through wrapped plugins, not a native rewrite
- Chose
- Cordova and Capacitor plugins behind internal wrapper modules
- Instead of
- Writing the mobile apps natively to access hardware directly
- Calling plugin APIs directly from feature code
- Why
- Biometrics, camera and GPS were requirements, and they were the usual argument for going native, but they are a small, well-bounded part of the app. Bridging them kept the single codebase, and wrapping each one meant a plugin could later be swapped for a different implementation without touching any screen that used it.
- Trade-off
- Plugin maintenance becomes your problem, and iOS and Android differ enough in permission behaviour that each capability needs testing on both rather than once.
Encrypted secure storage for keys and tokens
- Chose
- The platform keystore via a secure-storage plugin
- Instead of
- localStorage or a web storage API
- In-memory only
- Why
- Warehouse devices are shared, mislaid and handled by many people, which makes a token sitting in plain text a real exposure rather than a theoretical one. In-memory storage would have been safe but would have logged users out every time the app was backgrounded, which is unusable on a device that is constantly switched away from to scan something.
- Trade-off
- Keystore behaviour differs between platforms and OS versions, so the failure paths (enrolment changed, hardware unavailable) have to be handled rather than assumed to work.
Geolocation as a verification signal on stock movements
- Chose
- Capturing location alongside receiving and transfer actions
- Instead of
- Trusting the user-selected site
- No location data at all
- Why
- Inventory disputes come down to what happened where. Tying an action to a place gives the operational record something to check against, without asking the operator to enter anything extra.
- Trade-off
- Location can always be denied or unavailable, so the flow must complete without it rather than blocking. That means the signal is advisory, not a guarantee, and treating it as a guarantee would be the mistake.
04 / Stack
Grouped by the job they do rather than listed as a keyword run.
Technologies.
- Application
- Styling
- State & data
- Native
- Release
05 / Gallery
Select any image to view it full size.
How it looks.
Mobile
Sign in, with biometric unlock on return. Module navigation. Goods receive results: date-filtered GRN records, with scanning available from the floating action button. Delivery detail. Picking dashboard. Picking detail.
Desktop
The same codebase, built for the web. Inventory: the mobile card list, rendered as a table. Internal transfers.
06 / Outcome
Where it landed.
Shipped to both the App Store and Google Play from a single codebase, covering the full operational chain from receiving to collection. The single-source approach is what let one front-end developer deliver mobile and web together, and the wrapped native layer meant the mobile-only capabilities did not fragment the code that everything else shared.