eMart is an all-in-one marketplace: customers shop from local stores and an e-commerce catalogue, book on-demand services, send parcels, hail cabs and rent cars from one app and one website, while drivers, stores, providers and the admin run their side from dedicated apps and panels. This document covers the complete setup of the Admin Panel, the Store (Vendor) Panel, the Provider Panel, the Website (Customer) Panel and the mobile applications.
Welcome to eMart, the all-in-one solution for everyday needs. One platform brings together several services — from meals and groceries to transportation — so customers get everything with a tap, and you run them all from one admin panel. The platform is built on secure, modern technologies:
All clients (Admin, Store, Provider, Website and Mobile) share a single Firebase project, so data stays consistent in real time across the whole platform.
Important — third-party services & costs: eMart integrates several external services operated by third parties that may incur their own charges, separate from this product:
You are responsible for creating and funding these third-party accounts. Please review each provider's current pricing before going live.
eMart ships as Flutter mobile apps (the Customer App, the Store App, the Delivery Boy / Driver App, the Service Provider App and the Worker App) and four Laravel web panels (the Admin Panel, the Store Panel, the Provider Panel and the Website Panel) — all powered by Google Firebase. What you need depends on which part you are setting up.
Full steps are in App Documentation → Setting up Flutter.
mod_rewrite.Full server details are in Web Documentation → Server Requirement.
eMart includes several Flutter (Dart) applications — the Customer App, the Store App, the Delivery Boy / Driver App, the Service Provider App and the Worker App. Each is a separate project with its own source folder, package name and store listing, but they share one Firebase project and the setup below is identical for all of them: install Flutter once, then repeat sections 4–10 for each app. The official reference is docs.flutter.dev, but you should not need it to complete this guide.
C:\src\flutter
on Windows, or ~/development/flutter on macOS/Linux.flutter/bin folder to your system PATH so the flutter
command works from any terminal.flutter doctor --android-licenses.sudo xcodebuild -runFirstLaunch, then install CocoaPods with
sudo gem install cocoapods.Run the doctor command and fix anything it reports:
flutter doctor -v
Every item that matters for your target platform should show a green check.
Unzip the application source, open the app's folder in your IDE, and fetch the dependencies:
flutter pub get
Start an emulator/simulator or connect a physical device, then run:
flutter devices flutter run
Hot reload (r in the terminal) applies code changes instantly while the app keeps running.
The package name (Android) and bundle identifier (iOS) uniquely identify an app on the stores. Use reverse-domain form, and give each app its own identifier — they are published as separate listings and registered as separate apps in Firebase:
com.yourcompany.emart ← Customer App com.yourcompany.emart.store ← Store App com.yourcompany.emart.driver ← Delivery Boy / Driver App com.yourcompany.emart.provider ← Service Provider App com.yourcompany.emart.worker ← Worker App
Change the identifier before registering the app in Firebase, because the Firebase config files are tied to it. The steps below apply to one app — repeat them in each project folder.
On current Flutter versions the identifier lives in android/app/build.gradle, not in the
manifest. Open that file and change both values:
android {
namespace = "com.yourcompany.emart"
...
defaultConfig {
applicationId = "com.yourcompany.emart"
...
}
}
namespace — the package the generated R class and
MainActivity belong to.applicationId — the identifier Google Play and Firebase key off. This is the one
that must match your google-services.json.package attribute of the
<manifest> tag in
android/app/src/main/AndroidManifest.xml (and in the debug /
profile variants) — update it there too if your copy still has it.
Rename the folders under android/app/src/main/kotlin/ (or .../java/) to match the
new package, and update the package declaration at the top of MainActivity.kt /
MainActivity.java.
ios/Runner.xcworkspace in Xcode.
Tip: After renaming, run flutter clean followed by
flutter pub get, and download fresh google-services.json /
GoogleService-Info.plist files for the new identifiers (see
Firebase Setup (Mobile)).
Start from a single square PNG at 1024×1024, with no transparency for iOS.
ic_launcher.png inside each
android/app/src/main/res/mipmap-* folder (mdpi, hdpi, xhdpi, xxhdpi, xxxhdpi), keeping
the same file names and sizes.AppIcon image set in
ios/Runner/Assets.xcassets (open the project in Xcode and drop the sizes in).Generating every size by hand is error-prone. Add the helper package to pubspec.yaml:
dev_dependencies: flutter_launcher_icons: ^0.13.1 flutter_launcher_icons: android: "launcher_icon" ios: true image_path: "assets/icon/icon.png"
Then generate all sizes at once:
flutter pub get dart run flutter_launcher_icons
This is the name shown under the launcher icon on the device.
Open android/app/src/main/AndroidManifest.xml, find the <application> tag
and change android:label:
<application android:label="Your App Name" ... >
Open ios/Runner/Info.plist and set both display keys:
<key>CFBundleDisplayName</key> <string>Your App Name</string> <key>CFBundleName</key> <string>Your App Name</string>
The apps use Google Maps for store locations, address selection, cab and rental pick-up points and live driver tracking. Create the key first — see Create Google Map API Key — then add it to both platforms.
Open android/app/src/main/AndroidManifest.xml and set the key inside the
<application> element:
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="YOUR_API_KEY_HERE"/>
Open ios/Runner/AppDelegate.swift and set the key in
didFinishLaunchingWithOptions:
GMSServices.provideAPIKey("YOUR_API_KEY_HERE")
Rebuild the app after changing the key on either platform.
All the apps talk to the same Firebase project as the web panels. Create the project first — see Create Firebase Project — then register every app inside it.
Two registrations per app, one project. Each app needs its own Android
and iOS entry, so a full eMart setup registers every app twice in the one Firebase project
(Customer, Store, Driver, Provider and Worker, each for Android + iOS). Each produces its own
google-services.json / GoogleService-Info.plist — keep them
straight, as they are not interchangeable.
Repeat this for each app:
google-services.json.GoogleService-Info.plist. iOS does not need SHA fingerprints.
google-services.json in android/app/.ios/Runner.xcworkspace in Xcode and drag
GoogleService-Info.plist into the Runner group (tick "Copy items if
needed").
Instead of downloading the files by hand, you can let the FlutterFire CLI generate
lib/firebase_options.dart for both platforms:
npm install -g firebase-tools firebase login dart pub global activate flutterfire_cli flutterfire configure --project=YOUR_PROJECT_ID
The CLI writes a firebase_options.dart holding the per-platform configuration, which
main.dart passes to Firebase.initializeApp():
import 'package:firebase_core/firebase_core.dart';
import 'firebase_options.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
runApp(MyApp());
}
The Firebase plugins the app uses are already declared in pubspec.yaml — Core, Auth,
Firestore, Storage, Messaging and Cloud Functions. Just fetch them:
flutter pub get
In the Firebase console open Authentication → Sign-in method and enable the providers eMart uses:
Then open Authentication → Settings → Authorized domains and add the domains of your Website, Store and Provider panels.
The apps send push notifications and emails and delete accounts through the Website Panel, and pay through the payment Cloud Functions. They read the website address from Settings → Global Settings → Version → User Panel URL in the Admin Panel, so fill it in before testing the apps.
SHA fingerprints are required for Google Sign-In and Phone (OTP) authentication on Android. Add the fingerprints for both your debug keystore (for testing) and your release keystore (for the Play Store build).
From the android folder of the project:
# macOS / Linux ./gradlew signingReport # Windows gradlew signingReport
The report lists the SHA-1 and SHA-256 values for each build variant.
# Debug keystore keytool -list -v -alias androiddebugkey -keystore ~/.android/debug.keystore # Password: android # Release keystore keytool -list -v -keystore path/to/your-release-key.jks -alias your-key-alias
google-services.json and replace the one in
android/app/.Each app is published as an independent listing on each store, so this section runs once per app. You can sign all of them with the same keystore; only the package name, the store listing and the artwork differ.
Android release builds must be signed with your own keystore. Create it once and keep it safe — if you lose it you cannot update the app on Google Play.
keytool -genkey -v -keystore ~/my-release-key.jks -keyalg RSA \
-keysize 2048 -validity 10000 -alias my-key-alias
-keystore — where the .jks file is written.-keyalg RSA, -keysize 2048 — the signing algorithm and key length.-validity 10000 — validity in days (about 27 years).-alias — the name of the key inside the keystore.You are prompted for a keystore password, a key password and your organisation details.
Create android/key.properties (never commit this file):
storePassword=your-store-password keyPassword=your-key-password keyAlias=my-key-alias storeFile=/Users/yourusername/my-release-key.jks
Gradle reads this file at build time, so the keystore password never lives in the tracked
sources. Add android/key.properties and the .jks file itself to
.gitignore.
# Android App Bundle (required by Google Play) flutter build appbundle --release # Android APK (for direct distribution / testing) flutter build apk --release # iOS (macOS only) flutter build ipa --release
Outputs are written to build/app/outputs/ (Android) and build/ios/ipa/ (iOS).
.aab to a Production (or Internal Testing) release.version: in pubspec.yaml for every new upload — Play
rejects duplicate version codes..ipa with Transporter).Note: Apple requires Sign in with Apple on any iOS app that offers third-party sign-in such as Google. Enable the Apple provider in Firebase Authentication and add the capability in Xcode before submitting.
This Android build error means the google-services.json file is missing, in the wrong place,
or does not match the package name.
google-services.json must sit in
android/app/ — not in android/ and not in the project root.package_name inside the JSON must match the
applicationId in android/app/build.gradle. If you renamed the package,
register the new one in Firebase and download the file again.com.google.gms:google-services classpath in android/build.gradle is a
current version.flutter clean flutter pub get flutter run
The mobile apps read almost everything from Firebase, but a few things come from the web side. Before testing an app, make sure these are in place:
settings collection must exist
(Firestore Import / Export)./api/send-notification), emails (/api/send-email)
and account deletion (/api/delete-user), always with the user's Firebase ID token.All four web panels — Admin, Store, Provider and Website — are Laravel 13 applications and share the same server requirements. To run eMart smoothly your hosting must provide:
mod_rewrite) or NGINX.BCMath,
Ctype, cURL, DOM, Fileinfo, JSON,
Mbstring, OpenSSL, PCRE, PDO,
Tokenizer, XML, GD (or Imagick) and ZIP.proc_open, shell_exec and exec must not be
disabled — the Admin Panel's scheduled tasks start Node.js with them (see
Cron & Scheduled Tasks).Each panel needs its own domain or subdomain, for example:
https://yourdomain.com — Website (Customer) Panelhttps://admin.yourdomain.com — Admin Panelhttps://store.yourdomain.com — Store (Vendor) Panelhttps://provider.yourdomain.com — Provider Panel (On Demand add-on)The Admin Panel stores these three addresses under Settings → Global Settings → Version (User Panel URL, Store Panel URL, Provider Panel URL). The mobile apps and the service-account distribution use them, so fill them in as soon as the domains exist.
Node.js is needed for the Firebase CLI (indexes, rules and Cloud Functions), for the Firestore import/export utility, and for the scheduled scripts the Admin Panel executes.
Download the LTS installer from nodejs.org/en/download and run it. npm is installed alongside Node. Verify:
node -v npm -v
The Admin Panel needs the absolute path to the Node executable so its scheduled commands can run. On Linux/macOS:
which node
On Windows:
where node
The command prints something like /usr/local/bin/node. Copy that value into the
NODE_PATH variable of the Admin Panel's .env file:
NODE_PATH='/usr/local/bin/node'
On shared hosting Node is often installed through nvm; the path then looks like
/home/username/.nvm/versions/node/v20.19.5/bin/node.
npm install -g firebase-tools firebase login
firebase login opens a browser window; sign in with the Google account that owns your
Firebase project.
Firebase is the backend for the whole platform. Create one project and use it for the Admin Panel, the Store Panel, the Provider Panel, the Website Panel and every mobile app.
15.1. Go to firebase.google.com and click Go to console in the top-right corner.
15.2. Click Add project, enter a project name and click Continue. Choose whether to enable Google Analytics, select the default account for Firebase, then click Create project.
15.3. From the project overview, click the Web (</>)
icon to register a web app.
15.4. Enter an app nickname and click Register app. Scroll down to the
configuration snippet and copy the values — these are the FIREBASE_* credentials you
will paste into every panel's .env file.
The same values can be read again at any time from Project Settings → General → Your apps:
15.5. In the left sidebar open Firestore Database and click Create database. Pick a location close to your users and start in the mode you prefer — the rules are replaced in step 15.9.
15.6. Open Realtime Database and click Create Database. It is used for live driver and cab location tracking.
15.7. Open Storage and click Get started. Firebase Storage holds all uploaded images — store and product photos, banners, avatars and verification documents.
15.8. Open Authentication → Sign-in method and enable Email/Password, Phone, Google and, for iOS, Apple. Under Authentication → Settings → Authorized domains, add the domains of your Website, Store and Provider panels.
15.9. Security rules. Do not publish open rules
(allow read, write: if true) in the console. eMart ships its Firestore and
Storage rules as files inside the Cloud Functions package (firestore.rules,
firestore.rules.strict and storage.rules). They are deployed with the Firebase
CLI after the panels are installed and the service-account key is uploaded — see
Deploy Firebase Cloud Functions, section 18.6. Until then the
database may keep the rules the console created it with.
What the rules allow: the admin panel has full access; signed-in users (apps and
panels) may read and write the application data; settings that hold keys (payment gateways, SMTP,
push key) need a signed-in user and the OpenAI key is admin only; visitors may only read public data
(sections, stores, products, categories, banners, public settings). Storage: everyone may read files,
signed-in users may upload files up to 50 MB. firestore.rules.strict additionally hides
every secret setting from the apps — deploy it only after the mobile apps are updated to version
6.9 or later.
15.10. Upgrade the project to the Blaze (pay-as-you-go) plan. Cloud Functions and any outbound call to a payment gateway require it.
15.11. Generate the service account key. Open
Project Settings → Service accounts, choose Node.js and click
Generate new private key. A JSON file downloads — you will upload it once in the
Admin Panel (which installs it on every panel as
storage/app/firebase/credentials.json), and use it for the import/export utility.
Keep the service-account file private. It grants full administrative access to your
Firebase project. Never commit it to Git, never place it inside a web-accessible folder such as
public/, and never upload it to Firebase Storage or into a Firestore document.
The product ships with a demo dataset (settings, sections, categories, currencies, email templates, CMS pages and sample stores). Import it so the panels start with working defaults instead of empty screens.
16.1. Install Node.js if you have not already — see Installing Node.js & npm.
16.2. Unzip the source file named "Firebase Import Export Collections.zip".
16.3. Create your Firebase project first if you have not — see Create Firebase Project.
16.4. Replace credentials.json in the extracted folder with the
service account key you generated in step 15.11.
16.5. Open a terminal in the extracted folder. On Windows, hold Ctrl+Shift, right-click inside the folder and choose "Open PowerShell window here".
16.6. Run the import or export command:
# Import every collection into your Firestore npx -p node-firestore-import-export firestore-import -a credentials.json -b collections.json # Export every collection out of your Firestore npx -p node-firestore-import-export firestore-export -a credentials.json -b collections.json
The export writes a collections.json file you can keep as a backup.
Please note: Before running either command, make sure credentials.json
holds the service-account key of the correct Firebase project. Importing into the wrong
project, or importing twice, can overwrite existing documents.
Firestore needs a composite index for every query that filters and sorts on more than one field. eMart uses many of these (nearby stores, order lists, rides, reports), so deploy the supplied index definitions before going live — otherwise those screens fail with "The query requires an index".
17.1. Install Node.js — see Installing Node.js & npm.
17.2. Unzip the source file named "Firebase Indexing.zip".
17.3. Open a terminal in the extracted folder (Ctrl+Shift + right-click → "Open PowerShell window here" on Windows).
17.4. Log in to Firebase, if you have not already:
firebase login
17.5. Initialise Firestore configuration in the folder:
firebase init
17.6. Confirm with Y and press Enter.
17.7. Choose Firestore: Configure security rules and index files for Firestore.
Use the arrow keys to move between options and the space bar to select one, then press Enter to confirm.
17.8. Choose Use an existing project.
17.9. Select your eMart project.
17.10. Press Enter to accept the default rules file name
(firestore.rules).
17.11. Press Enter to accept the default index file name
(firestore.indexes.json).
17.12. Open the generated firestore.indexes.json, delete its contents, and
paste in everything from the supplied firestore_indexes.json file.
17.13. Deploy the indexes:
firebase deploy --only firestore:indexes
Building the indexes takes a few minutes. Watch the progress in Firebase Console → Firestore Database → Indexes and wait until every index shows Enabled.
The Cloud Functions eMart needs are already written — you only have to deploy them to your own Firebase project. The package deploys:
deliveryDispatch — a Firestore trigger on the vendor_orders
collection. It runs whenever a delivery order is written and drives the driver-assignment flow,
following the broadcast or sequential mode you chose under Settings → Driver Nearby.deleteUser — a callable function that removes a user from Firebase
Authentication when an account is deleted. Only the signed-in user themselves or an admin may call
it.paymentGateways) — see section 18.7.Without this package deployed, delivery orders are created but never dispatched to a driver and the apps cannot take online payments, so deploy it before going live. The same package also carries the Firestore and Storage security rules (section 18.6).
Before you deploy — enable the required Google Cloud APIs. Cloud Functions
(2nd generation) build on Cloud Build, store images in Artifact
Registry and run on Cloud Run using your project's default compute
service account. On a new Firebase project the Compute Engine API is usually not enabled
yet, so the deploy fails for most functions with
"Compute Engine API has not been used…" or
"Unknown service account". In
Google Cloud Console → APIs & Services → Enabled APIs & services,
make sure all of the following are enabled:
Or enable them all at once with the CLI, then wait 3–5 minutes for the change to propagate before deploying:
gcloud services enable compute.googleapis.com cloudbuild.googleapis.com \ artifactregistry.googleapis.com run.googleapis.com eventarc.googleapis.com \ cloudfunctions.googleapis.com --project=YOUR_PROJECT_ID
npm install -g firebase-tools
firebase login
A browser window opens; sign in with the Google account that owns your Firebase project.
Extract the supplied Cloud Functions package. It contains:
Cloud Function/
├── firebase.json deploy configuration: functions + the database the rules go to
├── .firebaserc which Firebase project to deploy to
├── firestore.rules Firestore security rules (deploy now)
├── firestore.rules.strict stricter rules for after the mobile apps are updated
├── storage.rules Storage security rules
├── README.md short deploy guide
└── functions/
├── .env which Firestore database the functions use
├── index.js the function list (one line per function)
├── products/delivery.js the delivery-order dispatch trigger
├── products/payments.js the payment functions for the apps
└── package.json dependencies (Node 22 runtime)
Step 1 — set the project. From the folder containing firebase.json:
firebase use YOUR_PROJECT_ID
This writes .firebaserc for you. Run firebase projects:list if you are unsure of
the exact project ID. You can also edit .firebaserc by hand:
{
"projects": {
"default": "YOUR_PROJECT_ID"
}
}
Step 2 — set the database. Open functions/.env and set
DATABASE to the Firestore database your panels use. Keep (default) unless you
deliberately created a named database:
DATABASE=(default)
If you use a named database, also change "database" in firebase.json so the
rules are deployed to the same one.
This value must match FIREBASE_PROJECT_DB in all four panels'
.env files. The dispatch trigger is a 2nd-generation function bound to one
named database, so if the panels write orders to (default) while the function listens
on a different one, the function deploys cleanly and then simply never fires — no error is
reported anywhere.
Step 3 — install the dependencies:
cd functions npm install cd ..
No service-account file is needed inside this package: the deployed functions run with your project's own Firebase identity.
Run this from the folder containing firebase.json — the root of the extracted
package, not the functions/ sub-folder:
firebase deploy --only functions
When the deploy finishes, open Firebase Console → Functions to confirm every function is listed. Each function has its own logs, which are the fastest way to debug a failing order or payment.
If some functions fail with "Quota exceeded for total allowable CPU per project per
region": a new project's Cloud Run CPU quota is small and the package deploys more than
thirty functions at once. Run the same deploy command again (it only retries the failed ones), or
deploy them in small groups, for example
firebase deploy --only "functions:cashfreeCreateLink,functions:cashfreeLinkStatus".
To remove the limit for good, request an increase of the Cloud Run Admin API → CPU
allocation quota for your region under IAM & Admin → Quotas;
it is free and usually approved within minutes.
The payment functions read the gateway keys from the settings you save in the Admin Panel, so rotating a
gateway key or enabling a new gateway never requires a redeploy. To remove a gateway from the package,
delete its lines in functions/index.js and deploy again.
Deploy the rules after the Admin, Store, Provider and Website panels are installed and the service-account key is uploaded (Admin Panel Setup, section 19.8). Panels older than version 6.9 do not work with these rules, so update the panels first.
firebase deploy --only firestore firebase deploy --only storage
In PowerShell, quote combined targets: firebase deploy --only "firestore,storage". The
Firestore rules go to the database named in firebase.json.
Once the mobile apps are updated to version 6.9 or later, rename firestore.rules.strict to
firestore.rules and deploy again. The strict rules keep every setting that holds keys
private to the server; apps from version 6.9 use the payment functions and the website API instead.
The mobile apps pay through these functions instead of calling the gateways directly. Each gateway has a
pair of callable functions in functions/products/payments.js: one creates the order, intent,
invoice or payment link on the server and returns only what the app's SDK or web view needs; the other
verifies the payment with the gateway. paymentGateways returns the on/off flag, the sandbox
flag and the public keys of every gateway for the payment-method list. All functions need a signed-in
Firebase user. The full list is in the package's README.md.
Please note: Cloud Functions require the Firebase Blaze (pay-as-you-go) plan — 2nd-generation functions build on Cloud Build and run on Cloud Run, neither of which is available on the free Spark plan.
The apps call these functions over HTTPS, so the Cloud Run service behind each callable function must
allow public access. Sign-in is still enforced: the function itself checks the Firebase user and
rejects anyone who is not logged in. The Firebase CLI sets this permission when it creates a function,
but on a large first deploy it sometimes fails for a few of them and prints Unable to set the
invoker for the IAM policy on the following functions. Deploying again does not repair it. The
apps then get [firebase_functions/unauthenticated] UNAUTHENTICATED for those gateways while
the other gateways work. To check and fix:
deleteuser must say Public access. Only deliverydispatch
(a Firestore trigger) stays on Require authentication.deliverydispatch),
click Permissions in the top bar, then Add principal.allUsers. Role: Cloud Run → Cloud Run Invoker.
Click Save and confirm Allow public access.
Nothing needs to be redeployed. The same can be done from the command line (service name = function name in lower case):
gcloud run services add-iam-policy-binding razorpaycreateorder --region us-central1 --member allUsers --role roles/run.invoker
Recurring tasks that do not need a Cloud Function run from the Laravel Admin Panel instead, so you can control their timing from the panel. The scripts live in:
root > storage > app > firebase
multivendorOrderAutoCancel.js — cancels multivendor orders that were never
accepted.multivendorScheduledOrderNotification.js — sends reminders for scheduled
orders.parcelOrderAutoCancel.js — cancels parcel orders that were never accepted.rentalOrderAutoCancel.js — cancels rental orders that were never accepted.onDemandOrderAutoCancel.js — cancels old on-demand bookings.cabScheduleRide.js — assigns cab rides to drivers (sequential or broadcast).storage/app/firebase/credentials.json.The Admin Panel is a Laravel 13 application. Make sure your server meets the requirements in Server Requirement, then upload the Admin Panel package to your domain or subdomain and extract it.
19.1.1. Connect over FTP/SFTP. Use a client such as FileZilla with your server IP, username and password — port 21 for FTP, port 22 for SFTP.
19.1.2. Transfer the ZIP file to the target path on the server, for example
/var/www/html.
19.1.3. Extract it from the server terminal, or with the cPanel File Manager:
unzip your-application.zip
19.1.4. Point the domain's document root at the project's public/
folder.
The admin panel uses MySQL only for panel authentication (users, roles, permissions), sessions and jobs
— every piece of platform data lives in Firestore. Create a database and user from your control
panel, then import the supplied .sql file into it (step 19.3.6).
Each panel needs its own database. The Admin, Store and Website panels ship with a
separate .sql file each (emart_admin_database.sql,
emart_store_database.sql, emart_website_database.sql) and the Provider
Panel add-on ships with its own, so create one database per panel — for example
emart_admin, emart_store, emart_provider and
emart_web — and import the matching file into each one. They all share the same
Firebase project; only MySQL is per-panel.
19.2.1. Open MySQL Databases in cPanel.
19.2.2. Enter a name and create the database.
19.2.3. Create a database user with a strong password.
19.2.4. Add the user to the database, grant ALL PRIVILEGES, and click Make Changes.
19.3.1. Install the dependencies and generate the application key:
composer install cp .env.example .env php artisan key:generate
19.3.2. Edit .env and set the database connection and your
Firebase web app credentials (copied in step 15.4):
APP_NAME=eMart APP_URL=https://admin.yourdomain.com DB_DATABASE=your_database DB_USERNAME=your_db_user DB_PASSWORD=your_db_password # Firestore named database — '(default)' unless you created a named one FIREBASE_PROJECT_DB=(default) FIREBASE_APIKEY= FIREBASE_AUTH_DOMAIN= FIREBASE_DATABASE_URL= FIREBASE_PROJECT_ID= FIREBASE_STORAGE_BUCKET= FIREBASE_MESSAAGING_SENDER_ID= FIREBASE_APP_ID= FIREBASE_MEASUREMENT_ID= # Absolute path to the Node binary — used by the scheduled scripts NODE_PATH='' # Timezone APP_TIMEZONE='Asia/Kolkata'
FIREBASE_PROJECT_DB must be identical in all four panels. Use
(default) unless you deliberately created a named Firestore database. A mismatch is the
most common cause of "data shows in one panel but not the other".
19.3.3. Install the Node modules the scheduled scripts need, from the panel root:
npm install
19.3.4. Set NODE_PATH in .env to the absolute path of your
Node binary — see Installing Node.js & npm.
19.3.5. The Firebase service account file
(storage/app/firebase/credentials.json) is installed later from the panel itself —
see section 19.8. It is required for server-side sign-in checks, push notifications and the scheduled
scripts.
19.3.6. Import the panel's database. Import emart_admin_database.sql from
the package into the database you created in step 19.2. Do not run
php artisan migrate; the supplied .sql file already contains the tables and
the default data.
Using phpMyAdmin / cPanel: open phpMyAdmin, select your database from
the left-hand list, open the Import tab, choose the .sql file and click
Go.
Using the command line:
mysql -u your_db_user -p your_database < emart_admin_database.sql
19.3.7. Set writable permissions on the runtime folders:
chmod -R 755 storage bootstrap/cache
The panel reads its configuration from Firestore, so before your first login import the supplied Firestore collections — see Firestore Database Collection Import / Export. They contain the settings documents, sections, currencies, email templates, CMS pages and the sample catalogue.
Two imports, two places. The .sql file (step 19.3.6) sets up MySQL
— the panel's login accounts, roles and permissions. The Firestore import sets up the platform
data the panel displays. Both are needed before the panel is usable.
Open the panel at your domain, for example https://admin.yourdomain.com, and sign in with
the default account that came with the imported .sql file:
Email: admin@emart.com Password: 12345678
Right after login the panel also signs you in to Firebase. Until the service-account key is installed (section 19.8) that step shows a message with a Continue anyway link — continue to Settings and finish the steps below.
Choose your map provider under General Settings → Map Tracking Options and paste your Google Maps API key — see Create Google Map API Key.
Google Maps is recommended for accurate location, search and distance results.
Open Settings → Global Settings → Version and fill the
User Panel URL, Store Panel URL and Provider Panel URL
with the addresses of your website, store and provider panels (for example
https://yourdomain.com, no trailing slash). Save. The mobile apps use the User Panel URL for
their server calls, and the next step uses all three.
Push notifications are delivered through Firebase Cloud Messaging (FCM). The same service-account key also lets every panel verify sign-ins on the server. Install it as follows:
1. Generate the Firebase credentials file
firebase-adminsdk-xxxxx.json).2. Upload it in the admin panel
storage/app/firebase/credentials.json and sent
over HTTPS to the Store, Provider and Website panels, which save it at the same path. The message
after the upload shows the result for each panel.
Keep the key only on your servers. Do not upload it to Firebase Storage and do not put it in any
Firestore document. If a copy exists there from an earlier setup, delete it, remove the
serviceJson field from settings/notification_setting if present, and
generate a new private key in Google Cloud → IAM → Service accounts.
3. Verify
Open Settings → AI Settings and paste your OpenAI API key.
With AI enabled, a product can be generated from its image plus a title and short description — the model returns an expanded description, specifications, variations and other attributes, which speeds up catalogue creation and keeps listings consistent.
The API secure key used by the mobile apps for AI features is set under Settings → Global Settings.
eMart runs six recurring jobs from the Admin Panel, all triggered by Laravel's scheduler:
app:multivendor-order-auto-cancel (every minute) — cancels multivendor orders that
were never accepted within the window you configure.app:multivendor-scheduled-order-notification (every minute) — sends reminders for
orders customers scheduled for later.app:parcel-order-auto-cancel (every 5 minutes) — cancels unaccepted parcel
orders.app:rental-order-auto-cancel (every 5 minutes) — cancels unaccepted rental
orders.app:ondemand-order-auto-cancel (daily) — cancels old on-demand bookings.app:cab-schedule-ride (every minute) — offers new cab rides to nearby drivers,
one at a time (sequential) or all at once (broadcast).All of them start the Node scripts in storage/app/firebase/, so they will not run until the
Node path is set and npm install has been run in the panel root.
Set NODE_PATH in the Admin Panel's .env to the absolute path of your Node
executable — for example /usr/local/bin/node on Linux, or
C:/Program Files/nodejs/node.exe on Windows. Find it with which node (see
Installing Node.js & npm).
NODE_PATH='/usr/local/bin/node'
Add a single cron entry that runs the scheduler every minute. Laravel then decides which of its commands are due.
* * * * * cd /path-to-your-admin-panel && php artisan schedule:run >> /dev/null 2>&1
In cPanel or hPanel, open Cron Jobs, choose Once Per Minute, and paste the command.
Please note: use the correct PHP binary path for your server
(/usr/local/bin/php is common but varies), point the command at your own admin-panel
directory, and make sure the panel's files are readable and storage/ is writable by
the cron user.
Open storage/logs/laravel.log in the Admin Panel folder. The scheduled tasks start Node.js
from PHP, and some hosts disable the PHP functions this needs. If the log shows
The Process class relies on proc_open, which is not available or
Call to undefined function shell_exec(), enable those functions in your hosting PHP
configuration: remove proc_open, shell_exec and exec from the
disable_functions list (in Hostinger hPanel: Advanced → PHP Configuration → PHP
options → disableFunctions), save, and wait a minute for the next cron run. The log
then shows lines such as Running command: … node … rentalOrderAutoCancel.js
followed by the script output.
If the host does not allow enabling them, run the scripts from cron directly instead of the Laravel scheduler, one line per script (use your Node path and admin panel path):
* * * * * /path/to/node /path/to/admin/storage/app/firebase/multivendorOrderAutoCancel.js * * * * * /path/to/node /path/to/admin/storage/app/firebase/multivendorScheduledOrderNotification.js */5 * * * * /path/to/node /path/to/admin/storage/app/firebase/parcelOrderAutoCancel.js */5 * * * * /path/to/node /path/to/admin/storage/app/firebase/rentalOrderAutoCancel.js 0 0 * * * /path/to/node /path/to/admin/storage/app/firebase/onDemandOrderAutoCancel.js * * * * * /path/to/node /path/to/admin/storage/app/firebase/cabScheduleRide.js
A line such as Notification skipped … device token is no longer registered in the output is normal: that customer's device token has expired, the order itself was still processed.
The cron entry only decides how often Laravel is asked. The actual timings come from the admin panel: the auto-cancellation windows under Settings, the reminder lead time under Settings → Schedule Order Notification, and the driver search radius and accept/reject time under Settings → Driver Nearby.
Customer payments, store and provider subscription payments, gift cards and wallet top-ups all run through the gateways you enable under Settings → Payment Methods in the admin panel. Credentials are stored in Firestore and used only on the server — by the Laravel panels and by the payment Cloud Functions the mobile apps call — so secret keys are never bundled into the apps or exposed to the browser. Each gateway has a sandbox/live toggle — test in sandbox before switching to live.
eMart integrates 16 online payment gateways, plus Cash on Delivery and the in-app Wallet:
Callback URLs. Gateways that redirect back to your site (PayFast, OrangePay, MTN MoMo and others) need their Return / Cancel / Notify URLs pointing at your live HTTPS domain, and the same URLs whitelisted in the provider's own dashboard. Payments will appear to "hang" on the gateway page if these do not match.
Gateways that use a secret key perform their sensitive operations — creating and verifying transactions — on the server: inside the Laravel panels for the website, store and provider checkouts, and inside the payment Cloud Functions for the mobile apps (see Deploy Firebase Cloud Functions, section 18.7). The browser and the apps send only non-sensitive data (amount, currency, reference) and receive only what the gateway's SDK or checkout page needs, so no secret key is ever shipped in the apps or exposed to the browser.
This is also why the payment callback URLs must point at your live HTTPS domain: the provider redirects back into the panel, which then verifies the transaction before the order is marked paid.
The Store (Vendor) Panel is the Laravel 13 application store owners and their
employees log into. Upload the package to its own domain or subdomain (for example
store.yourdomain.com) and extract it.
23.1.1. Connect over FTP/SFTP with FileZilla or a similar client — port 21 for FTP, port 22 for SFTP.
23.1.2. Transfer the ZIP file to the server, for example /var/www/html.
23.1.3. Extract it from the terminal or the cPanel File Manager:
unzip your-application.zip
23.1.4. Point the subdomain's document root at the project's public/
folder.
23.2.1. Install the dependencies and generate the application key:
composer install cp .env.example .env php artisan key:generate
23.2.2. Create a MySQL database for this panel and import
emart_store_database.sql from the package — through
phpMyAdmin → Import, or from the command line:
mysql -u your_db_user -p your_database < emart_store_database.sql
There is no php artisan migrate step; the .sql file already contains the
tables and default data.
23.2.3. Add the same Firebase credentials you used for the Admin Panel, including the same database name:
APP_NAME=eMart Store APP_URL=https://store.yourdomain.com DB_DATABASE=your_database DB_USERNAME=your_db_user DB_PASSWORD=your_db_password FIREBASE_PROJECT_DB=(default) FIREBASE_APIKEY= FIREBASE_AUTH_DOMAIN= FIREBASE_DATABASE_URL= FIREBASE_PROJECT_ID= FIREBASE_STORAGE_BUCKET= FIREBASE_MESSAAGING_SENDER_ID= FIREBASE_APP_ID= FIREBASE_MEASUREMENT_ID=
Note: use the same Firebase project and the same
FIREBASE_PROJECT_DB value for the Admin Panel, the Store Panel, the Provider Panel, the
Website Panel and the mobile apps — that is what keeps all clients on one live dataset.
23.2.4. Set writable permissions on storage/ and
bootstrap/cache/ (chmod -R 755).
23.2.5. The Firebase service-account key is installed by the Admin Panel when you upload
it there (Admin Panel Setup, section 19.8), provided the
Store Panel URL is filled in the admin panel's Global Settings. If the automatic copy
fails, copy the file to storage/app/firebase/credentials.json by FTP.
"Sign in with Google" uses the Google provider of your Firebase project. Enable it and authorise your domains:
https://yourdomain.comhttps://store.yourdomain.comhttps://provider.yourdomain.com/__/auth/handler under Authorized redirect
URIs, for example https://store.yourdomain.com/__/auth/handler.The panel is now ready at your chosen address, for example https://store.yourdomain.com/. Store owners register from this panel and then wait for admin approval, unless automatic approval is enabled in the Admin Panel settings. If document verification is switched on, the owner must upload the required documents before the rest of the menu unlocks.
The Provider Panel is the Laravel 13 application on-demand service providers log into to
manage their services, workers and bookings. It is part of the On Demand add-on. Upload the package to
its own domain or subdomain (for example provider.yourdomain.com) and extract it.
Follow the same steps as for the Store Panel:
public/.composer install cp .env.example .env php artisan key:generate
.sql file supplied with the
Provider Panel package (phpMyAdmin → Import, or
mysql -u your_db_user -p your_database < emart_provider_database.sql). There is no
php artisan migrate step..env: APP_URL, the database connection, and the same
FIREBASE_* credentials and FIREBASE_PROJECT_DB as the other
panels.storage/ and bootstrap/cache/.storage/app/firebase/credentials.json by FTP.https://provider.yourdomain.com for Google login exactly as described in
section 23.3.The panel is now ready at https://provider.yourdomain.com/. Providers register from this panel, choose a subscription plan when the subscription model is enabled, and then add their services and workers.
The Website Panel is the customer-facing site — a Laravel 13 application that reads and writes Firestore through the Firebase JS SDK and serves every section: Ecommerce, Multivendor, On Demand, Parcel, Cab and Rental. Upload it to your main domain (recommended) and extract it.
27.1.1. Connect over FTP/SFTP using your server IP, username and password — port 21 for FTP, port 22 for SFTP.
27.1.2. Transfer the ZIP file to the server, for example /var/www/html.
27.1.3. Extract it from the terminal or the cPanel File Manager:
unzip your-application.zip
27.1.4. Point the domain's document root at the project's public/
folder.
27.2.1. Install the dependencies and generate the application key:
composer install cp .env.example .env php artisan key:generate
27.2.2. Create a MySQL database for this panel and import
emart_website_database.sql from the package — through
phpMyAdmin → Import, or from the command line:
mysql -u your_db_user -p your_database < emart_website_database.sql
There is no php artisan migrate step; the .sql file already contains the
tables and default data.
27.2.3. Add the same Firebase credentials used by the other panels:
APP_NAME=eMart APP_URL=https://yourdomain.com DB_DATABASE=your_database DB_USERNAME=your_db_user DB_PASSWORD=your_db_password FIREBASE_PROJECT_DB=(default) FIREBASE_APIKEY= FIREBASE_AUTH_DOMAIN= FIREBASE_DATABASE_URL= FIREBASE_PROJECT_ID= FIREBASE_STORAGE_BUCKET= FIREBASE_MESSAAGING_SENDER_ID= FIREBASE_APP_ID= FIREBASE_MEASUREMENT_ID=
27.2.4. Set writable permissions on storage/ and
bootstrap/cache/.
27.2.5. Fill the User Panel URL in the Admin Panel (Global Settings
→ Version) with this domain. The service-account key is then installed here when it is uploaded in
the Admin Panel (section 19.8); if the automatic copy fails, copy it to
storage/app/firebase/credentials.json by FTP. The mobile apps also use this URL for push
notifications, emails and account deletion.
Enable the Google provider in Firebase and authorise your website domain exactly as described for the
Store Panel (section 23.3): add https://yourdomain.com to the OAuth client's
Authorized JavaScript origins, https://yourdomain.com/__/auth/handler to
the Authorized redirect URIs, and the domain under Firebase Authentication
→ Settings → Authorized domains.
Notes: use the same Firebase credentials here that you set for the
other panels, including FIREBASE_PROJECT_DB. All four panels and the mobile apps must
point at one Firebase project and one Firestore database.
The package also contains a Landing Panel: a static HTML marketing page
(index.html, css/, js/, img/). It needs no PHP or
database — edit the texts and links in index.html, then upload the folder to any
domain or sub-folder you like.
The website's own home page (the section chooser with the location picker) is editable from the Admin Panel under Settings → Home page template.
The site is now ready at your domain, for example https://yourdomain.com/. Its sections, banners, CMS pages and home page template are all driven from the Admin Panel — see Customizing Branding.
eMart uses Google Maps for store search, address selection, zone drawing, delivery-distance calculation, cab fares and live driver tracking. One key can serve the panels and the apps, but restricting it per platform is safer.
28.1. Go to the Google Maps Platform and click Get started.
28.2. Open the Google Cloud Console, go to Billing, and confirm your billing details are up to date — Google Maps returns a grey map or a watermark without an active billing account.
28.3. Go to APIs & Services → Credentials and select or create a project.
28.4. Click Create credentials → API key. Copy the key that is displayed.
28.5. Enable the APIs eMart uses under APIs & Services → Library:
28.6. Restrict the key to your domains (HTTP referrers) for web use, and to your package name + SHA-1 for Android, then save.
28.7. Add the key in the admin panel under General Settings → Map Tracking Options, and in each mobile app — see Google Maps API Key (Flutter).
All four panels follow the standard Laravel 13 layout. If you plan to customise the code, these are the folders that matter.
emart-admin/ (also emart-store/, emart-provider/ and emart-web/) ├── app/ Application code │ ├── Console/ Artisan commands + the scheduled tasks │ │ └── Commands/ the six auto-cancel, reminder and cab-dispatch commands (admin) │ ├── Helpers/ Shared helper functions (FirestoreHelper, …) │ ├── Http/ │ │ ├── Controllers/ Request handlers (thin — data is read from Firestore) │ │ └── Middleware/ Auth & the per-menu permission gate │ ├── Mail/ Mailables for the email templates │ ├── Models/ Eloquent models (panel auth: User, Role, Permission) │ ├── Providers/ Service providers │ └── Services/ Firebase services (ID-token verification, Auth admin, Firestore REST) ├── Modules/ │ └── AI/ The OpenAI product-listing module (admin & store panels) ├── bootstrap/ Framework bootstrap + cache ├── config/ Configuration files (app, database, …) ├── database/ │ ├── migrations/ MySQL schema reference (you import the shipped .sql) │ └── seeders/ Base data ├── public/ Web root — index.php, css/, js/, images/ ├── resources/ │ ├── views/ Blade templates (pages, layouts, partials) │ └── lang/ Translations (en/, ar/) ├── routes/ │ ├── web.php All web routes (route names double as permission keys) │ └── api.php API routes used by the mobile apps and the other panels ├── storage/ │ └── app/firebase/ credentials.json + the scheduled Node scripts (admin) ├── vendor/ Composer dependencies (generated — not edited) ├── .env Environment config (DB + Firebase credentials) ├── artisan Laravel command-line entry point └── composer.json PHP dependencies
Note: vendor/ and node_modules/ are generated by
composer install / npm install and should not be edited by hand. Your
configuration lives in .env; your Firebase service account lives in
storage/app/firebase/credentials.json. Neither should ever be committed to Git or
placed under public/.
This section maps the external services eMart integrates with and where each one is configured, so developers can extend or replace them. Every client — the mobile apps, the Admin Panel, the Store Panel, the Provider Panel and the Website Panel — talks to the same Google Firebase backend.
credentials.json) for privileged operations and
push notifications. The Admin Panel signs in to Firebase with an admin claim.deliveryDispatch trigger, the
deleteUser callable and the payment functions.There is no separate REST API layer to configure: Firestore is the API, and every client reads and writes the same collections in real time.
All platform data lives in Firestore. The main collections are:
users — customers, vendors, drivers, providers and workers, each with a role.sections — the service sections (Ecommerce, Multivendor, On Demand, Parcel, Cab,
Rental).vendors, vendor_categories, vendor_products,
vendor_attributes, vendor_filters, brands — stores and
their catalogue.vendor_orders, parcel_orders, rental_orders,
rides, provider_orders, booked_table,
order_transactions — orders, rides, bookings and payments per section.providers_services, provider_categories, providers_workers,
services — the On Demand catalogue.car_make, car_model, vehicle_type,
rental_vehicle_type, rental_packages, parcel_categories,
parcel_weight, popular_destinations — cab, rental and parcel
configuration.coupons, gift_cards, cashback, promos,
advertisements, story — promotions.subscription_plans, subscription_history, payouts,
driver_payouts, withdraw_method, wallet — money
movement.zone, tax, currencies, documents,
documents_verify — operational configuration.settings — every configurable option, one document per settings screen.chat, dynamic_notification, email_templates —
communication.cms_pages, banner_items, on_boarding — content.Configured by the FIREBASE_* keys in each panel's .env. Access is governed by
the security rules you deploy (see Deploy Firebase Cloud
Functions), and multi-field queries need composite indexes (see
Deploy Firestore Indexes).
Handles email/password, phone (OTP), Google and Apple sign-in for every client. Providers are enabled in the Firebase console; the web panels additionally need the domain listed under Authorized domains and a matching OAuth 2.0 client for Google login. The panels verify the Firebase ID token on the server before creating a session.
Holds every uploaded file — store and product images, banners, avatars and verification
documents. Upload quality is controlled by IMAGE_COMPRESSOR_QUALITY in the Admin and Store
panels' .env.
Delivers order, ride, chat and status notifications to customers, stores, drivers and providers.
Configured by uploading the service-account JSON and Sender ID under General Settings →
Notifications Settings; the notification text itself comes from Dynamic
Notifications. The mobile apps send their notifications through the website API
(POST /api/send-notification).
Used for live driver and cab location, which changes far more often than order state. It powers the customer's tracking map and the admin's live map.
16 gateways plus COD and the wallet. Public keys are read by the clients; secret-key operations run server-side in the Laravel panels and in the payment Cloud Functions, which read the credentials from the settings documents the Admin Panel manages. See Payment Gateway Setup.
The Website Panel exposes a small API the apps call with the user's Firebase ID token
(Authorization: Bearer <ID token>); the base address is the User Panel
URL from the Admin Panel:
POST /api/send-notification — push notification to a device token (60 per
minute).POST /api/send-email — transactional email through the panel's SMTP account (10
per minute).POST /api/delete-user — removes the website login of the signed-in user.POST /api/firebase-credentials (also on the Store and Provider panels) — receives
the service-account key from the Admin Panel; accepts only an admin ID token.Store search, address selection, zone drawing, delivery distance, cab fares and live tracking. One key, configured in General Settings → Map Tracking Options and in each mobile app.
The Modules/AI module in the Admin and Store panels. Given a product image, title and
short description it drafts the full listing — description, specifications, variations and
attributes. Configured under Settings → AI Settings; billed by OpenAI per
request.
Order receipts, password resets, vendor approvals and campaign mail. Set the SMTP host, port, username, password and encryption under General Settings → Email Settings in the Admin Panel; the message bodies come from Email Templates.
.env (each panel) — database, all FIREBASE_* keys,
FIREBASE_PROJECT_DB and NODE_PATH (admin).storage/app/firebase/credentials.json — the Firebase service
account, installed from the Admin Panel.routes/web.php wrapped in the
permission: middleware, add the entry to the layout menu, and grant the permission to
the roles that need it. Route names double as permission keys, so keep them stable.resources/lang/en to a new locale folder,
translate lang.php, and register the language under Languages in the
admin panel.SecurePaymentController), and its create/verify pair in
functions/products/payments.js for the apps.All four panels are Laravel applications and can run on shared hosting (cPanel / hPanel) or on a VPS/dedicated server. Choose the approach that matches your hosting.
Best for getting started quickly when you do not have SSH/root access.
public/ directory.composer install on your own machine
first and upload the project with its vendor/ folder already
installed..env (database + Firebase credentials).755) on storage/ and
bootstrap/cache/..sql file into its database through
phpMyAdmin → Import. No Artisan or shell access is needed for this step.Note: make sure your host runs PHP 8.3+ with the required
extensions, that mod_rewrite is enabled, and that proc_open,
shell_exec and exec are not in the PHP disable_functions list.
The Admin Panel's scheduled jobs need Node.js, which basic shared plans often lack
— choose a plan that offers it (or install it with nvm), or use a VPS.
Recommended for production — you get SSH access, Composer, Node.js and full control.
composer install (and npm install
for the Admin Panel)..env.example to .env, set the database and Firebase credentials, then
run php artisan key:generate..sql file:
mysql -u user -p database < panel.sql.public/ directory.storage/ and
bootstrap/cache/.* * * * * php /path/artisan schedule:run) — see
Cron & Scheduled Tasks.php artisan config:cache and php artisan route:cache,
and serve everything over HTTPS.mod_rewrite is disabled or AllowOverride is not All, so
Laravel's public/.htaccess is ignored.RewriteBase to
public/.htaccess, e.g. RewriteBase /emart/.public/. Point the
domain at public/, or add a root .htaccess that rewrites into it. Never
serve the project root — it makes .env and
storage/app/firebase/credentials.json reachable from the internet.php artisan storage:link (or
create the public/storage link manually if symlinks are blocked).755 on
storage/ and bootstrap/cache/, and confirm PHP is 8.3+.Options -MultiViews) to
.htaccess.APP_URL to your
https:// domain and force HTTPS in .htaccess.php artisan view:clear and php artisan optimize:clear after every
upload.Always serve all four panels over HTTPS. Firebase Authentication, payment-gateway callbacks and secure cookies all require it, and browsers block mixed content on pages that are not fully secure.
Shared hosting (cPanel). Most hosts issue a free certificate automatically. Open cPanel → Security → SSL/TLS Status (or Let's Encrypt / AutoSSL), select your domains, and click Run AutoSSL.
VPS / dedicated server. Install a free Let's Encrypt certificate with Certbot:
# Nginx sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d yourdomain.com -d admin.yourdomain.com -d store.yourdomain.com -d provider.yourdomain.com # Apache sudo apt install certbot python3-certbot-apache sudo certbot --apache -d yourdomain.com
Certbot installs the certificate and adds an automatic renewal timer.
Force HTTPS. Add this at the top of each panel's public/.htaccess, just
inside <IfModule mod_rewrite.c> and before Laravel's front-controller rules:
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
Then finish up:
APP_URL=https://… in every panel's .env, and the three panel
URLs in the Admin Panel.php artisan config:cache.This section walks through the platform from each side — customer, store, provider, driver and admin — so you can see how the pieces you configured fit together.
eMart is fully white-label — the application name, logos, favicon, colours and the website home page can all be changed from the Admin Panel without editing any code. Branding is stored in Firebase, so a change made once is reflected across the panels, the website and the mobile apps.
Log in to the Admin Panel and open Settings → Global Settings. From this screen you can update:
Click Save. The new logo and name appear as soon as the page reloads.
Note: use the same Firebase project for all panels and the mobile apps so branding changes propagate everywhere. Clear your browser cache if an updated logo or colour does not appear right away.
Some mobile branding is baked into the build rather than read from Firebase, so it is set separately in each app project:
Add or edit languages under Languages in the admin sidebar. English and Arabic (RTL) ship by
default; catalogue and content documents carry per-language translations that can be edited from their
own screens. New panel languages are added by copying resources/lang/en and translating
lang.php.
This section lists the errors most often seen while setting up eMart, with their causes and fixes. Also see the FAQ for the Flutter "Missing project_info object" error.
Firestore reads/writes are being blocked by the security rules.
FIREBASE_PROJECT_DB
below.A Firestore composite index is missing for a filter/sort query.
This almost always means the panels point at different Firestore databases.
FIREBASE_PROJECT_DB is identical in all four panels'
.env files and matches DATABASE in the Cloud Functions package —
(default) in a normal installation.FIREBASE_* credential belongs to the same Firebase project.The demo Firestore collections were never imported.
settings collection in particular must exist — without it the
panels have no configuration to read./set-location, choose a section and a location. If a stale
section cookie remains from an older version, clear the site cookies once.The sign-in provider you are using is not enabled. Enable Email/Password, Phone, Google (and Apple if used) under Authentication → Sign-in method.
storage/app/firebase/credentials.json on the panel that sends
the notification (the upload message tells you which panels received it).google-services.json / GoogleService-Info.plist are present
and match the package name.credentials.json to that panel's
storage/app/firebase/ folder by FTP.NODE_PATH in the Admin Panel's .env is empty or wrong. Run
which node and paste the absolute path.npm install was never run in the Admin Panel root, so the scripts have no dependencies.storage/logs/laravel.log shows proc_open is not available or Call to undefined
function shell_exec(): the hosting disables those PHP functions — see section 21.3.DATABASE in functions/.env
differs from the panels' FIREBASE_PROJECT_DB — see
Deploy Firebase Cloud Functions.storage/logs/laravel.log in the panel that started the payment; the provider's
rejection reason is recorded there. For the apps, read the payment function's log in the Firebase
console.upload_max_filesize and post_max_size.The google-services.json file is missing or in the wrong place. See the detailed fix in the
FAQ.
[firebase_functions/unauthenticated] UNAUTHENTICATED with no other
message, some gateways work and nothing appears in the function's log. The Cloud Run service of that
function is set to Require authentication, so the call is refused before the function runs.allUsers the Cloud Run
Invoker role on every payment function that is not Public access — see
Deploy Firebase Cloud Functions, section 18.7. No redeploy is
needed.A quick reference for the terms used throughout this documentation.
FIREBASE_PROJECT_DB — Firestore can host more than
one database per project. (default) is the standard one. Whatever you use, every panel and
the Cloud Functions package must target the same name.credentials.json — a private key file that lets the
server act on behalf of your Firebase project (verify tokens, send push, run scripts). Uploaded once in
the Admin Panel, kept in storage/app/firebase/ on every panel and never exposed
publicly.google-services.json / GoogleService-Info.plist — the
Firebase configuration files added to the Android and iOS apps respectively.composer install)..env — the environment configuration file holding database and
Firebase credentials for each panel.php artisan key:generate).NODE_PATH — the absolute path to the Node binary, used by those
scheduled scripts..jks) — the file holding your Android signing key. Losing
it means you can no longer update the app on Google Play.To update the Admin, Store, Provider and Website panels, upload the latest source package to the root directory of each respective panel and extract it.
If your project includes custom modifications, we strongly recommend updating with Git so your customisations are preserved while the latest changes are merged in.
Check for a database update first. Every panel package includes its own
.sql file. When a release adds or changes tables, that .sql file is
updated too — and the new code will not work against the old tables. Read the
Changelog for the version you are moving to:
.sql file from the new package into that panel's
database (phpMyAdmin → Import, or
mysql -u user -p database < panel.sql).There is no php artisan migrate step in eMart, on a fresh install or
an update — the .sql file is always the source of truth for MySQL.
.sql file if the release changed the database (see the note above)..env and storage/app/firebase/credentials.json — they
are not part of the package..env and credentials.json, then compare .env against
the new .env.example and add any new keys..sql file from the new package if the release changed the database.
Back up your existing database first — importing replaces the tables it contains.composer install php artisan config:clear php artisan cache:clear php artisan view:clear
Before you update: take a full backup of the panel folder, the MySQL database and your Firestore data (use the export command in Firestore Database Collection Import / Export). If a release adds new Firestore documents or indexes, re-run the import and index deployment afterwards.
Version 6.9 adds server-side payments, the updated Firebase Cloud Functions package and Firestore security rules. Follow this order:
composer install, then php artisan optimize:clear.php artisan schedule:run every minute
(section 21): cab ride dispatch runs from it.firestore.rules.strict; as a routine security measure, delete any copy of the key from
Firebase Storage, remove the serviceJson field from
settings/notification_setting if present, and generate a new private key.To update the Customer App, Store App, Delivery Boy / Driver App, Service Provider App or Worker App, download the latest source package and replace that app's project source. Each app updates independently, so you can ship one without rebuilding the others — but keep them on the same release when a version changes shared Firestore fields. As with the panels, Git is the safer route if you have customised the code.
google-services.json,
GoogleService-Info.plist, android/key.properties and release keystore
— none of them ship in the package.flutter clean flutter pub get flutter run
Then increment version: in pubspec.yaml and publish the new build — see
Signing, Building & Publishing the Apps. Update the version number
and store links under Settings → Global Settings → Version in the admin panel
so existing users are prompted to upgrade.
Apps older than 6.9 use the previous settings structure. They keep working with
firestore.rules but stop working once firestore.rules.strict is deployed, so
update the apps first. Apps from version 6.9 pay through the payment Cloud Functions (section 18.7),
send push notifications and emails through the website API (/api/send-notification,
/api/send-email with the user's Firebase ID token) and send the ID token when deleting an
account (/api/delete-user). The website address the apps use is the User Panel
URL from the admin panel's Global Settings → Version.
.env files from all Laravel panels and included .env.example files for improved security and deployment.resources/views/role/save.blade.php.