OpenCart Mobile App Developer Guide, Part 1: Overview, Architecture, Repository Layout and Languages
How the OpenCart 4.1.0.4 mobile app works: why it uses a custom API extension, its architecture, the repository layout and the languages used.

This guide is for developers who will maintain or extend this project. It covers how the system is built and why. It also covers how each user flow works from start to finish, and how to add features safely.
For installing the extension and running the app the first time, see the OpenCart Mobile App: a Native iOS and Android App for OpenCart 4.1.0.4. This guide assumes you have done that.
This guide is published as a 5-part series. This is part 1.
In this post
1. What this project is
A native iOS and Android shopping app for an OpenCart 4.1.0.4 store. It has two parts that ship separately:
| Part | Folder | Runs on | Ships as |
|---|---|---|---|
| Mobile app | mobile/ | Phones (iOS, Android), with web for testing | App Store / Play Store build, or Expo Go during development |
| Mobile App API extension | opencart-extension/mobile_api/ | The OpenCart server (PHP) | mobile_api.ocmod.zip, installed via Extensions → Installer |
A local Docker store (docker-compose.yml, store/) is included for development only.
Why a custom extension instead of OpenCart’s built-in API
OpenCart 4.1.0.4 ships an API (catalog/controller/api/*), but it was built for the admin panel, not for public clients:
- Only the
api/orderandapi/subscriptionroutes are allowed. - Every call needs an HMAC-SHA1 signature with a secret that must stay on the server.
- Calls are limited to whitelisted IP addresses. Phones have changing IPs.
- It trusts prices posted by the caller, which is safe for an admin but not for a customer.
- It has no catalog browsing, customer accounts, wishlist, or order history.
So the extension adds a separate set of public JSON endpoints under extension/mobile_api/api/*. Wherever possible these call OpenCart’s own models and controllers, so stock checks, option validation, taxes, totals, shipping, and payment behave exactly as they do on the website.
2. Architecture at a glance
Key ideas:
- The server owns all state. The cart, checkout progress, login, and wishlist live in the OpenCart session on the server. The app is a thin client that renders what the server returns.
- The session travels in a header. Native apps don’t share the browser’s
OCSESSIDcookie, so the app sendsX-Session-Token. The extension’s startup action reopens that session. - One response shape. Every endpoint returns
{success, data, message}or{success:false, error, errors}. - Reuse over reimplementation. Adding to the cart calls core
api/cart.addProduct. Totals callapi/cart.getTotals. Offline payments run the payment extension’s ownconfirm(). Online gateways render their own forms in a WebView.
3. Repository layout
opencart-mobile-app/
├── README.md Setup, API reference, known limits
├── docs/
│ ├── DEVELOPER.md This guide (the source; edit this file)
│ ├── developer-guide.html Bootstrap web page built from it (build-html.cjs)
│ ├── developer-guide.wordpress.xml WordPress import (5 posts) built from it (build-wordpress.cjs)
│ └── featured-images/ Featured images for the 5 posts (build.cjs, README.md)
├── docker-compose.yml Local dev store: web (PHP 8.3 + Apache) and db (MariaDB 11.4)
├── docker/php/Dockerfile PHP image with gd, mysqli, zip, curl
├── .env Local DB and admin passwords (dev only, never commit real secrets)
├── store/ OpenCart 4.1.0.4 install used for local testing
│
├── opencart-extension/
│ ├── build.sh Packages mobile_api/ into mobile_api.ocmod.zip
│ └── mobile_api/ Extension source (the folder name is the extension code)
│ ├── install.json Name, version and description shown in the Installer
│ ├── system/library/
│ │ └── api_controller.php Base class for every endpoint
│ ├── catalog/controller/
│ │ ├── startup/mobile_api.php Session, currency and CORS handling for API routes
│ │ └── api/ One file per resource (see §8.4)
│ └── admin/
│ ├── controller/module/mobile_api.php Settings page, install and uninstall
│ ├── language/en-gb/module/mobile_api.php Admin texts
│ └── view/template/module/mobile_api.twig Settings form
│
└── mobile/ Expo / React Native app
├── App.tsx Entry: providers, boot screen, theme, lazy navigator
├── app.json Expo config: name, bundle ids, iOS ATS, plugins
├── package.json Dependencies and scripts
├── tsconfig.json TypeScript strict mode
└── src/
├── config.ts Store URL, API key, language, page size
├── theme.ts Colours, spacing, radius, font sizes, applyTheme()
├── api/
│ ├── client.ts fetch wrapper: headers, token storage, envelope, ApiError
│ ├── endpoints.ts Typed function per endpoint (the `api` object)
│ └── types.ts TypeScript types for every response
├── context/StoreContext.tsx Init data, customer, login/logout, currency
├── hooks/ useCart, useWishlist (shared React Query hooks)
├── navigation/ RootNavigator (stack + tabs) and param types
├── components/ Reusable UI (buttons, fields, product card, address form…)
├── screens/ One file per screen (23 screens)
└── utils/errors.ts Error message helpers
4. Languages
| Language | Version | Where | Why |
|---|---|---|---|
| TypeScript (TSX) | ~6.0 (see mobile/package.json), strict: true | All app code in mobile/ | Catches mistakes at compile time, such as a wrong field name in an API response or a wrong navigation parameter. The API types in src/api/types.ts and the navigation types in src/navigation/types.ts make the compiler check every screen against the server contract. |
| PHP | 8.3 in the dev container (OpenCart 4.1.0.4 needs 8.0+) | opencart-extension/ | OpenCart is written in PHP. An extension has to be PHP to run inside it and call its models. The code uses typed properties, str_starts_with, arrow functions and hash_equals. |
| Twig | OpenCart’s bundled version | Admin settings form | OpenCart’s admin view layer. |
| JavaScript / jQuery | Inside the Twig template | Admin colour pickers | The admin panel already loads jQuery and Bootstrap 5, so small scripts use them. |
| SQL | MariaDB 11.4 / MySQL | Only through OpenCart models | The extension writes almost no SQL. It calls core models. The one exception is a SHOW TABLES check for the optional bestseller table. |
| YAML / Dockerfile / shell | n/a | docker-compose.yml, docker/php/Dockerfile, build.sh | Local dev environment and packaging. |
Next: Part 2: Tools and Libraries, Why Expo, and the Development Environment →
The series
- Part 1: Overview, Architecture, Repository Layout and Languages (you are reading this part)
- Part 2: Tools and Libraries, Why Expo, and the Development Environment
- Part 3: The OpenCart Extension and the Mobile App
- Part 4: Design Patterns, Hooks and End-to-End Flows
- Part 5: Configuration, Security, Extending, Testing, Releasing and Troubleshooting




