Modul master Level 3 VibeKoding: Aplikasi Store Inspection: React Native & Expo.Modul master Level 3 VibeKoding: Aplikasi Store Inspection: React Native & Expo.
Suppose a retail team needs one small application for daily store inspections. Staff open a checklist, mark each item, leave a note, and save the result. The same project should eventually run on Android and iPhone, while a browser version is useful for quick internal reviews.Suppose a retail team needs one small application for daily store inspections. Staff open a checklist, mark each item, leave a note, and save the result. The same project should eventually run on Android and iPhone, while a browser version is useful for quick internal reviews.
This is a good React Native and Expo project: the product is mainly forms, lists, photos, and business data, and the team wants to share most of the TypeScript code across platforms.This is a good React Native and Expo project: the product is mainly forms, lists, photos, and business data, and the team wants to share most of the TypeScript code across platforms.
React Native lets you build Android and iOS interfaces with React and TypeScript. It renders native controls rather than placing the website inside an app window.React Native lets you build Android and iOS interfaces with React and TypeScript. It renders native controls rather than placing the website inside an app window.
Expo supplies the project tools around React Native: project creation, development servers, common device APIs, builds, updates, and store submission services. You can begin with Expo and still use native code later when the product needs it.Expo supplies the project tools around React Native: project creation, development servers, common device APIs, builds, updates, and store submission services. You can begin with Expo and still use native code later when the product needs it.
The project in this chapter is a store inspection app. “Inspection” simply means that an employee checks a short list—entrance lighting, shelf labels, fire exits, and so on—and records the result.The project in this chapter is a store inspection app. “Inspection” simply means that an employee checks a short list—entrance lighting, shelf labels, fire exits, and so on—and records the result.
Shopify POS is the application employees use at a shop counter to sell products, check stock, and work with retail hardware. Shopify has described moving its POS application to React Native while continuing to test on the lower-powered devices that stores actually use.Shopify POS is the application employees use at a shop counter to sell products, check stock, and work with retail hardware. Shopify has described moving its POS application to React Native while continuing to test on the lower-powered devices that stores actually use.
🖼️ Shopify POS inventory and store screens from its official product pageShopify POS inventory and store screens from its official product page
The lesson for our inspection app is practical: the home screen should show the next task and today's progress immediately. A real store worker should not have to navigate through several decorative pages.The lesson for our inspection app is practical: the home screen should show the next task and today's progress immediately. A real store worker should not have to navigate through several decorative pages.
Read: [Shopify's React Native migration](https://shopify.engineering/migrating-our-largest-mobile-app-to-react-native).Read: [Shopify's React Native migration](https://shopify.engineering/migrating-our-largest-mobile-app-to-react-native).
Discord is a communication platform for communities, friends, and work groups. Its mobile team uses React Native to share product work between Android and iOS while keeping room for platform-specific behavior.Discord is a communication platform for communities, friends, and work groups. Its mobile team uses React Native to share product work between Android and iOS while keeping room for platform-specific behavior.
🖼️ Discord's official comparison of the Android roles screenDiscord's official comparison of the Android roles screen
This is the second lesson: share the screen and business logic first. Add an Android-only or iOS-only file only when the two platforms genuinely need different behavior.This is the second lesson: share the screen and business logic first. Add an Android-only or iOS-only file only when the two platforms genuinely need different behavior.
Read: [How Discord improved React Native on Android](https://discord.com/blog/how-discord-achieves-native-ios-performance-with-react-native).Read: [How Discord improved React Native on Android](https://discord.com/blog/how-discord-achieves-native-ios-performance-with-react-native).
MTA TrainTime is the official journey-planning and ticketing application for commuter rail services around New York. Expo's case study explains how its team uses Expo tooling for builds and releases.MTA TrainTime is the official journey-planning and ticketing application for commuter rail services around New York. Expo's case study explains how its team uses Expo tooling for builds and releases.
🖼️ The MTA TrainTime application in Expo's official case studyThe MTA TrainTime application in Expo's official case study
Its value here is not the railway interface. It shows that Expo can support a production release process, not only classroom demos.Its value here is not the railway interface. It shows that Expo can support a production release process, not only classroom demos.
Read: [MTA's Expo case study](https://expo.dev/customers/mta).Read: [MTA's Expo case study](https://expo.dev/customers/mta).
🖼️ How React Native and Expo organize a multi-platform projectHow React Native and Expo organize a multi-platform project
You write screens and state in TypeScript. React Native supplies the mobile controls. Expo starts the project, provides common APIs, and creates builds. A web build can reuse much of the same project, although not every native capability has an identical browser equivalent.You write screens and state in TypeScript. React Native supplies the mobile controls. Expo starts the project, provides common APIs, and creates builds. A web build can reuse much of the same project, although not every native capability has an identical browser equivalent.
That is why “one codebase” does not mean “every line is identical.” It means the shared product logic stays together and the few real platform differences remain small and explicit.That is why “one codebase” does not mean “every line is identical.” It means the shared product logic stays together and the few real platform differences remain small and explicit.
Install a current Node.js LTS release, then open a terminal in the folder where you keep projects:Install a current Node.js LTS release, then open a terminal in the folder where you keep projects:
bash npx create-expo-app@latest store-inspection cd store-inspection npm run web
When the browser shows the starter application, stop and keep that version working. It gives you a safe point to return to.When the browser shows the starter application, stop and keep that version working. It gives you a safe point to return to.
Now ask your coding assistant:Now ask your coding assistant:
> Turn this Expo starter into a store inspection home page. Show the store name, today's progress, and one button that opens the inspection checklist.> Turn this Expo starter into a store inspection home page. Show the store name, today's progress, and one button that opens the inspection checklist.
Do not ask for login, camera access, offline sync, and a backend in the same message. First confirm that the home page opens.Do not ask for login, camera access, offline sync, and a backend in the same message. First confirm that the home page opens.
Use four ordinary items for the first version: entrance lighting, price labels, aisle cleanliness, and fire exits.Use four ordinary items for the first version: entrance lighting, price labels, aisle cleanliness, and fire exits.
> Add an inspection page with four checklist items. Tapping an item should switch it between complete and incomplete, and the progress number should update.> Add an inspection page with four checklist items. Tapping an item should switch it between complete and incomplete, and the progress number should update.
Run the page again. Click every item once, then click one item a second time. The count should increase and decrease correctly.Run the page again. Click every item once, then click one item a second time. The count should increase and decrease correctly.
🖼️ The store inspection app running in Expo WebThe store inspection app running in Expo Web
Next narrow the browser window. The controls should remain readable without horizontal scrolling.Next narrow the browser window. The controls should remain readable without horizontal scrolling.
🖼️ The same Expo Web app in a narrow layoutThe same Expo Web app in a narrow layout
The first record needs only a note and a Save button.The first record needs only a note and a Save button.
> Add a note field and a Save button. After saving, show the time, completed item count, and note in a record card below the checklist.> Add a note field and a Save button. After saving, show the time, completed item count, and note in a record card below the checklist.
Test three cases:Test three cases:
🖼️ A real inspection record after clicking and savingA real inspection record after clicking and saving
At the moment, refreshing the page may erase the record. “Local storage” means keeping a copy on the current device so the user can close the app and continue later.At the moment, refreshing the page may erase the record. “Local storage” means keeping a copy on the current device so the user can close the app and continue later.
> Save the checklist progress and records on this device. Restore them when the app opens again. Do not add a server yet.> Save the checklist progress and records on this device. Restore them when the app opens again. Do not add a server yet.
For a few simple values, AsyncStorage is usually enough on mobile. When the data grows into inspections, line items, and a retry queue, expo-sqlite is easier to manage. The browser version needs an equivalent web storage path.For a few simple values, AsyncStorage is usually enough on mobile. When the data grows into inspections, line items, and a retry queue, expo-sqlite is easier to manage. The browser version needs an equivalent web storage path.
After the change, save two records, close the tab, reopen it, and confirm both records return.After the change, save two records, close the tab, reopen it, and confirm both records return.
References: [AsyncStorage](https://react-native-async-storage.github.io/async-storage/) and [Expo SQLite](https://docs.expo.dev/versions/latest/sdk/sqlite/).References: [AsyncStorage](https://react-native-async-storage.github.io/async-storage/) and [Expo SQLite](https://docs.expo.dev/versions/latest/sdk/sqlite/).
Photos are useful when an employee needs to record a damaged sign or blocked exit. First add one small action:Photos are useful when an employee needs to record a damaged sign or blocked exit. First add one small action:
> Let the user attach one photo to an incomplete checklist item. Show a preview and allow the photo to be removed.> Let the user attach one photo to an incomplete checklist item. Show a preview and allow the photo to be removed.
Expo's [ImagePicker guide](https://docs.expo.dev/versions/latest/sdk/imagepicker/) covers the system photo picker. A camera adds permission prompts and more device-specific testing, so do not claim it works until it has been tried on the target phone.Expo's [ImagePicker guide](https://docs.expo.dev/versions/latest/sdk/imagepicker/) covers the system photo picker. A camera adds permission prompts and more device-specific testing, so do not claim it works until it has been tried on the target phone.
A backend is the server that owns accounts, store permissions, shared records, and uploaded photos. The mobile app should display that data; it should not decide who is a manager by itself.A backend is the server that owns accounts, store permissions, shared records, and uploaded photos. The mobile app should display that data; it should not decide who is a manager by itself.
Begin with the data relationships:Begin with the data relationships:
> Describe how users, stores, inspections, checklist items, and photos relate. Do not write code yet.> Describe how users, stores, inspections, checklist items, and photos relate. Do not write code yet.
Then connect login:Then connect login:
> Connect the existing login API. A user may only see stores assigned by the server.> Connect the existing login API. A user may only see stores assigned by the server.
Keep mobile login tokens in SecureStore, not ordinary text storage. Never put a server secret in EXPO_PUBLIC_ variables: values shipped inside an app can ultimately be read by the user.Keep mobile login tokens in SecureStore, not ordinary text storage. Never put a server secret in EXPO_PUBLIC_ variables: values shipped inside an app can ultimately be read by the user.
For photo upload:For photo upload:
> Upload inspection photos through the backend. Limit file type and size, show progress, and keep the local record when an upload fails.> Upload inspection photos through the backend. Limit file type and size, show progress, and keep the local record when an upload fails.
Test with two accounts. Account A must not read account B's stores, records, photos, or retry queue. Hiding a button is not access control; the backend must reject the request.Test with two accounts. Account A must not read account B's stores, records, photos, or retry queue. Hiding a button is not access control; the backend must reject the request.
“Offline sync” means the device saves work locally when the network is unavailable and uploads it later. It is not required for the first prototype.“Offline sync” means the device saves work locally when the network is unavailable and uploads it later. It is not required for the first prototype.
Once ordinary local saving and the backend both work, add one state at a time:Once ordinary local saving and the backend both work, add one state at a time:
> Mark unsent records as Pending. Add a Retry button that sends one pending record when the network returns.> Mark unsent records as Pending. Add a Retry button that sends one pending record when the network returns.
Later you can add Sending, Synced, and Failed states. Give every submission a unique request ID so a retry cannot create the same inspection twice.Later you can add Sending, Synced, and Failed states. Give every submission a unique request ID so a retry cannot create the same inspection twice.
During early work, Expo Go is convenient for features supported by its built-in native modules. A development build is your own installable test app and is the better choice once you add custom native code.During early work, Expo Go is convenient for features supported by its built-in native modules. A development build is your own installable test app and is the better choice once you add custom native code.
Follow Expo's [development build guide](https://docs.expo.dev/develop/development-builds/introduction/) and [EAS Build guide](https://docs.expo.dev/build/introduction/).Follow Expo's [development build guide](https://docs.expo.dev/develop/development-builds/introduction/) and [EAS Build guide](https://docs.expo.dev/build/introduction/).
Before release, test the actual Android and iOS builds on real devices:Before release, test the actual Android and iOS builds on real devices:
The prototype was created with Expo SDK 57 and TypeScript. Type checking passed, the web production export completed, and the application was opened in a browser. Checklist interaction, saving a record, and the narrow layout shown above were tested in the running build.The prototype was created with Expo SDK 57 and TypeScript. Type checking passed, the web production export completed, and the application was opened in a browser. Checklist interaction, saving a record, and the narrow layout shown above were tested in the running build.
This machine did not have a usable Android emulator or iOS Simulator runtime, so this chapter does not pretend that mobile builds, camera permissions, signing, or store submission were completed. Use the same rule in your own project: write down exactly what ran, on which device, and with which build.This machine did not have a usable Android emulator or iOS Simulator runtime, so this chapter does not pretend that mobile builds, camera permissions, signing, or store submission were completed. Use the same rule in your own project: write down exactly what ran, on which device, and with which build.
The first useful milestone is small: open the checklist, complete an item, save a note, and see the record again. Once that path is dependable, add photos, accounts, synchronization, and release work in that order.The first useful milestone is small: open the checklist, complete an item, save a note, and see the record again. Once that path is dependable, add photos, accounts, synchronization, and release work in that order.