Vendor App Active
APP / 01 Included
27 Screen Classes

Dedicated vendor mobile portal with order fulfillment and catalog sync.

APP / 02 1.0.0+1
com.mono.vendor.app

Built for high-volume store owners on Android and iOS devices.

APP / 03 Real-time
Ably + FCM Push

Instant live chat with buyers and foreground order notification sounds.

APP / 04 Secure
Sanctum Token Gate

Scoped vendor token with granular withdrawal and product controls.

Vendor app documentationSetup · Build · Ship

Android · iOS

Mono Vendor. App documentation.

Complete setup, API, and release guide.

A corrected operations guide for the current mono_vendor Flutter project: 27 public *Screen classes plus MainVendorShell, the actual layered source tree, locked packages, local API wiring, Android push, and the release gaps still visible in the repository.

A / 01

Public screen classes

27 screens + MainVendorShell Included
A / 02

Application identity

com.mono.vendor.app 1.0.0+1
A / 03

Active API default

example.com / api / v1 Local LAN

Mono Vendor overview

mono_vendor is the checked-in Flutter application package. Its Dart description is “Mono Marketplace Vendor Management Application”, its declared version is 1.0.0+1, and the Dart-facing app name is Mono Vendor. This page documents the repository as it exists now, including its real branding mismatch, local API default, and unfinished release configuration.

DetailValueNotes
Dart packagemono_vendorpubspec.yaml
Version1.0.0+1pubspec.yaml
DescriptionMono Marketplace Vendor Management Applicationpubspec.yaml
Android namespace / application IDcom.mono.vendor.appandroid/app/build.gradle.kts
iOS bundle IDcom.mono.vendor.appios/Runner.xcodeproj/project.pbxproj
Top-level routes/, /login, /register, /dashboardlib/main.dart

What the application actually manages

The source-backed surface is a vendor commerce workspace: dashboard reporting, product catalog and bundles, taxonomy requests and custom definitions, orders, delivery requests and tracking, media, customer chat, followers, notifications, AI quota, package plans, settlements, withdrawals, and store settings.

Catalog

Products use a five-step form. Bundles use a separate four-step form. Categories, brands, attributes, FAQs, and the media library are independent screens in the shell.

Commerce

Order, delivery, wallet, package, AI-credit, and hosted-checkout workflows use repositories and API endpoints. A local Flutter package manager is not part of the app.

Workspace

Provider supplies state, Ably supplies server-authorized realtime sessions, and Android FCM is initialized only after the authenticated shell mounts.

Source boundary: there is no standalone business-listing module, payment-log screen, support-ticket workflow, map/geolocation package, commercial UI-suite dependency, or payment-gateway SDK in the current project. Hosted purchases run through flutter_inappwebview and backend status polling.

Route map and shell behavior

Only four routes are registered with Flutter’s named router. The remaining drawer destinations switch bodies inside MainVendorShell; the drawer is available on Overview, while sub-screens use a back-to-Overview bar.

MaterialApp(
  initialRoute: '/',
  routes: {
    '/':          SplashScreen,
    '/login':     VendorLoginScreen,
    '/register':  VendorRegisterScreen,
    '/dashboard': MainVendorShell,
  },
)

The layered source tree that exists now

lib/ is organized by technical layer and by feature folders inside screens/. Generated caches and IDE state are not part of the documented source architecture.

mono_vendor/
├─ .gitignore
├─ .metadata
├─ README.md
├─ analysis_options.yaml
├─ analyze_errors.txt
├─ analyze_out.log
├─ pubspec.yaml
├─ pubspec.lock
├─ assets/
│  ├─ logo.png
│  └─ icons/                 app icon, logo, drawer + UI SVGs
├─ lib/
│  ├─ main.dart
│  ├─ core/                   constants, logger, translations, formatting, RTL, presence
│  ├─ models/                 dashboard, AI, bundle, chat, delivery, FAQ, follower, media,
│  │                          notification, order, package tier, product, profile, taxonomy, wallet
│  ├─ providers/              AI quota, locale, theme, auth, dashboard, follower, notification,
│  │                          order, product, wallet
│  ├─ repositories/           translation, AI, auth, bundle, chat, dashboard, delivery, FAQ,
│  │                          follower, media, notification, order, package, product, settings,
│  │                          taxonomy, wallet
│  ├─ screens/                shell, splash, auth, and feature screen folders
│  ├─ services/               Ably chat, Ably notifications, API client, endpoints, FCM
│  ├─ theme/                  app_colors.dart, app_theme.dart
│  └─ widgets/                app bars, buttons, dialogs, drawer, fields, HTML, filters,
│                             search, status, empty, error, and shared UI
├─ android/
├─ ios/
├─ macos/
├─ web/
├─ windows/
└─ test/
LayerResponsibilityRepresentative files
CoreCross-cutting constants, logging, translations, formatting, RTL icon behavior, chat presenceapp_constants.dart, app_logger.dart, app_translations.dart
ModelsData shapes and JSON parsing used by providers and screensvendor_product.dart, vendor_order.dart, vendor_wallet.dart
ProvidersChangeNotifier state, loading, mutations, and refresh logicvendor_auth_provider.dart, vendor_dashboard_provider.dart
RepositoriesHTTP calls, endpoint use, parsing, and platform service accessvendor_auth_repository.dart, vendor_notification_repository.dart
ScreensPublic *Screen classes plus internal widgets and form sectionsdashboard_screen.dart, product_form/, delivery/
ServicesShared API, realtime, and push infrastructureapi_client.dart, ably_vendor_chat_service.dart, firebase_push_service.dart
Theme / widgetsColor constants, light/dark themes, and reusable presentation componentsapp_colors.dart, app_drawer.dart, empty_state.dart

Do not treat generated folders as architecture. .dart_tool/, .idea/, build/, Gradle caches, and generated local configuration are workspace byproducts, not the app’s source-layer design.

Twenty-seven public screens, plus the shell

The class count comes from public classes named *Screen in lib/screens/. Wizard sections, bundle steps, delivery tabs, dialogs, cards, and controllers are internal subviews; they are not additional public screens.

Drawer and internal destination map

Drawer groupDestinations
MainOverview, Orders, Inbox, Media, Followers
CatalogProducts, Product bundles, Categories, Brands, Attributes, FAQs
DeliveryRequests, History, Tracking
PayoutsSettlements, Withdrawals
ScalePackages, AI credits when AiQuotaProvider.aiEnabled is true
SystemSettings; the account dock also exposes settings and logout

Public screen classes

#Public classSource-backed workflow
01SplashScreenAnimated Mono logo, wordmark, and progress; routes an authenticated vendor to the dashboard.
02VendorLoginScreenEmail/password validation, sign-in, error banner, and a route into vendor registration.
03VendorRegisterScreenStore name, contact name, business email, phone, specialty, password, and confirmation; submits the registration payload.
04DashboardScreenStore status, 30-day sales/orders/AOV/live products, pending and out-of-stock summaries, fulfillment pipeline, fl_chart sales/orders toggle, recent orders, top products, low stock, conditional AI usage, and catalog actions.
05ProductListScreenSearch, status filters, product cards, and add/edit/delete entry points.
06ProductFormScreenFive internal steps: Description, Media, Details, Pricing, and Fulfillment. Includes AI copy/translation, media, taxonomy, status, price, stock, SKU, variations, and physical/digital delivery.
07BundleListScreenBundle statistics, search, status filters, and add/edit/delete entry points.
08BundleFormScreenFour internal steps: information, media, product builder, and pricing/SEO. Before the bundle can be saved, the form requires at least two selected products, and every selected product must still be published.
09CategoriesScreenAvailable categories and personal requests, search, request dialog, and request status/rejection metadata.
10BrandsScreenAll/custom/global filters, custom-brand editing, and read-only global brands.
11AttributesScreenAll/custom/global filters and custom attribute/value management.
12StoreFaqsScreenLanguage selector, FAQ add/edit/delete, and AI translation context.
13MediaLibraryScreenSearch, all/image/file filters, multi-image upload, details, copy URL, delete, and picker mode.
14OrderListScreenSearch plus all, pending, processing, shipped, delivered, and cancelled filters.
15OrderDetailScreenOrder, customer, items, notes, earnings, status timeline, and a conditional status update sheet.
16DeliveryScreenRequests, History, and Tracking tabs, request creation dialog, and tracking-detail entry.
17DeliveryTrackingDetailScreenRead-only order-level shipment timeline and shipment states.
18VendorChatListScreenUnified customer conversations, search, all/unread filters, unread count, and realtime updates.
19VendorChatThreadScreenCustomer/product context, Ably presence, history, image/file replies, delivered marking, and RTL bubbles.
20FollowersScreenPaginated infinite-scroll followers and entry into a customer conversation.
21NotificationsScreenAll, Orders, Chats, Wallet, and System tabs; date grouping, unread badges, read state, and deep links. The UI has no swipe-to-delete gesture.
22AiCreditsScreenCopy, translation, and image quota meters; purchase history and packs; hosted checkout.
23SettlementsScreenDate range, gross/commission/net totals, load more, CSV export, and order-detail links.
24WithdrawalRequestScreenAvailable balance, amount rules, backend-defined method and fields, and an optional note.
25PackagesScreenPackage/commission status, current and pending subscriptions, API-provided plan cards/limits, and hosted checkout.
26StoreSettingsScreenPause/resume, dark/light selection, backend language, profile/address, change-password dialog, and logout.
27VendorCheckoutWebviewScreenHosted purchase WebView, progress, status polling, backend return/custom mono:// handling, and close confirmation.

Subview accounting: the product form contributes five steps, the bundle form four steps, and delivery three tabs. Dialogs, dashboard cards, list cards, form sections, and controllers remain implementation details inside their owning public screen.

Actual Android capture set

These are the current app captures, not generated mockups. They show the native splash and the current login/registration UI reached on a connected Android device.

Toolchain and target requirements

The lockfile and platform projects define the supported toolchain floor. Both application packages and toolchain constraints have been upgraded to Flutter 3.47.7 and Dart 3.13.5.

TargetRequirementWhere it lives
Dart^3.13.5 in pubspec.yamlLock SDK floor: >=3.13.5 <4.0.0
Flutter>=3.47.7pubspec.lock
Androidcompile SDK 37; minimum runtime is maxOf(flutter.minSdkVersion, 23); Java/Kotlin 17android/app/build.gradle.kts
Android build pluginsAGP 9.1.0; Kotlin 2.4.0; Gradle 9.3.1; Google services 4.4.2android/settings.gradle.kts, wrapper properties
iOSdeployment target 15.0; bundle com.mono.vendor.appios/Runner.xcodeproj/project.pbxproj
macOSdeployment target 12.0; bundle com.mono.monoVendormacos/Runner.xcodeproj/project.pbxproj
Web / WindowsTarget folders exist, but mobile-only dart:io imports mean the app targets Android and iOS only.lib/ plus platform folders

Before the first run

  • Use Flutter 3.47.7 or newer and a Dart SDK (3.13.5+) compatible with the project constraint.
  • For Android, run on an API 23+ device or emulator and configure a reachable API URL.
  • For iOS, open the generated Runner.xcworkspace on macOS; no signing team is checked in.
  • Do not assume web or Windows parity: the current Dart source contains dart:io dependencies.

Install and launch from the repository

The project is a standard Flutter application rooted at mono_vendor/. Resolve packages from the checked-in lockfile, choose a visible target, and run normally.

Official App Tutorial Flutter • 18:26 Full Setup Backend • Mobile Sync

Complete Guide to Setting Up the Mono Market Flutter App with the Backend

Step-by-step setup tutorial by ClotCode walking through connecting the Mono Market vendor & customer Flutter mobile apps to your live or local backend: setting API base URLs, Android cleartext network security, Firebase push notifications (FCM), toolchain requirements (Flutter 3.47.7 & Dart 3.13.5), resolving dependencies, and testing real-time synchronization on Android emulators and devices.

cd mono_vendor
flutter pub get
flutter devices
flutter run -d <device-id>

Run sequence

  1. Open the mono_vendor project folder in Android Studio or another Flutter-enabled editor.
  2. Run flutter pub get; the lockfile resolves 187 packages, including transitives.
  3. Confirm the selected device in flutter devices.
  4. Run flutter run -d <device-id>. Android Studio can perform the same launch through its Flutter run configuration.
  5. Expect SplashScreen, then login or registration when no valid token is restored.

Configuring the API Base URL: Point the application to your backend server URL (e.g. https://example.com/api/v1). Update lib/services/api_client.dart or pass --dart-define=API_URL=https://example.com/api/v1 on launch.

Local HTTP Cleartext Traffic: If testing against an unencrypted local HTTP server, ensure android:usesCleartextTraffic="true" is present in android/app/src/main/AndroidManifest.xml under the <application> tag.

Android Studio evidence

The hero capture is the full-HD project view from the current source. It shows the layered lib/ tree and the active API constant in api_client.dart; use the lightbox to inspect it at full size.

Exact direct declarations and locked versions

pubspec.lock contains 187 packages in total. All direct core packages have been verified and upgraded for Flutter 3.47.7 & Dart 3.13.5.

PackageDeclared constraintLocked versionRole in current source
cupertino_icons^1.0.91.0.9Declared direct icon package; no current lib/ import.
provider^6.1.5+16.1.5+1Application state and dependency injection across providers and screens.
dio^5.11.15.11.1HTTP client, interceptors, auth headers, errors, and request logging.
ably_flutter^1.2.441.2.44Server-authorized realtime customer chat and notification channels.
dart_quill_delta^10.8.310.8.3Rich-content delta model in the editor and HTML conversion path.
flutter_quill^11.6.011.6.0Rich text editing controls for product and bundle content.
html^0.15.60.15.7HTML parsing/rendering for server-provided rich content.
vsc_quill_delta_to_html^1.0.51.0.5Quill delta conversion for the rich-content path.
firebase_core^5.0.05.0.0Android Firebase initialization in the push service.
firebase_analytics^12.6.012.6.0Declared direct package; no current lib/ import.
firebase_messaging^17.0.017.0.0FCM listeners, permission, token refresh, and notification routing.
flutter_local_notifications^22.3.222.3.2Android channel, permission plumbing, foreground tray notifications, and taps.
flutter_cache_manager^3.4.53.4.5Cached remote media and notification big-picture images.
flutter_secure_storage^11.2.011.2.0Auth token and stable notification device ID storage.
shared_preferences^2.5.52.5.5Theme, locale, cached base URL, and related client preferences.
flutter_svg^2.3.02.3.0Drawer, app bar, and UI SVG assets.
cached_network_image^4.0.04.0.0Cached backend media across product, bundle, order, and media screens.
fl_chart^1.2.01.2.0Dashboard sales and order chart. No chart license key is referenced.
intl^0.20.30.20.3Date, number, and locale-aware formatting.
image_picker^1.2.31.2.3Local media selection for upload workflows.
logger^2.8.02.8.0Structured application and network logging.
url_launcher^6.3.26.3.2External links from vendor-facing workflows.
flutter_inappwebview^6.1.56.1.5Hosted package and AI-credit checkout with return handling.
share_plus^13.3.013.3.0Platform sharing actions in the current app.
flutter_lints dev^6.0.06.0.0Dart/Flutter static lint rules.
flutter_launcher_icons dev^0.14.40.14.4Generates Android, iOS, and web launcher icons.
flutter, flutter_localizationsSDKSDK-providedFramework and localization delegates.
flutter_test devSDKSDK-providedWidget and unit test runner.

Capability boundary: the current chart implementation is fl_chart. The project declares no map/geolocation dependency and no payment-gateway SDK; checkout remains a hosted WebView workflow.

The API client is fixed to a local development default

lib/services/api_client.dart owns the global Dio client. The active default is the same local LAN HTTP URL shown in the Android Studio capture.

https://example.com/api/v1
MONO_VENDOR / lib/services/api_client.dart FLUTTER
Full-screen Android Studio capture of the Mono Vendor project showing the layered lib tree and the active API base URL in api_client.dart.
Active file api_client.dart Base URL example.com / api / v1 Capture 1920 × 1080 / Android Studio Transport HTTP / LAN

Current client behavior

  • Adds Authorization: Bearer <token> when a token is available.
  • Adds X-Locale and Accept-Language from the vendor language preference, defaulting to en.
  • Uses a 15-second connect timeout and a 30-second receive timeout. No explicit sendTimeout is configured in the current client.
  • Redacts credentials and tokens from request logs and truncates long bodies.
  • Resolves relative media paths against the active API base.
  • On HTTP 401, clears the token and invokes the logout/redirect callback registered in main.dart.
  • Restores vendor_api_base_url from SharedPreferences when present.

Endpoint registry groups

Registry groupPaths / behavior
Auth & account/vendor/auth/login, /vendor/auth/register, /vendor/auth/logout, profile GET/PUT, change password, pause/resume
Dashboard/vendor/dashboard
Products & catalogProducts, categories, brands, attributes, vendor languages, category requests, custom brand/attribute stores
BundlesProduct bundles, candidates, bundle detail
OrdersOrders, order detail, status update, digital delivery
DeliveryRequests, cancel request, history, tracking, order tracking
MediaMedia list, upload, media detail
Chat & followersUnified messages, start conversation, token request, conversation, reply, poll, delivered, followers
NotificationsInbox, unread count, register/unregister token, read-all, bulk mark/delete, per-item read/delete
AIQuota, copy, image, translation, credits, and credit-pack checkout
FAQs & packagesStore FAQs, package list, package checkout
WalletWallet, settlements, withdrawals
SettingsSettings, payout details, notification settings

Authentication and translations

Login and registration post credentials or the registration payload to the vendor auth endpoints. Profile updates use PUT /vendor/profile. Language discovery uses GET /languages?scope=mobile; translation bundles use GET /translations/{code} in TranslationRepository.

Do not publish this URL as a production default. It is plain HTTP on a private LAN address. The app source also enables cleartext traffic on Android and arbitrary loads on iOS; production hardening must be decided and implemented outside this documentation-only change.

No hidden environment-variable base URL

The repository has no --dart-define path, no environment-file loader, and no current UI caller for ApiClient.setBaseUrl. Store Settings does not expose a server URL.

How the active URL is selected

  1. ApiClient starts with defaultBaseUrl.
  2. After initialization, a non-empty vendor_api_base_url value in SharedPreferences overrides it.
  3. Otherwise the compiled-in local LAN default remains active.
static const defaultBaseUrl =
    'https://example.com/api/v1';

Current change paths: update the constant in source, call setBaseUrl from code, or pre-seed the SharedPreferences key. A documented settings screen or dart-define override would be a future source change, not a current capability.

Transport security flags

Platform fileCurrent settingImplication
android/app/src/main/AndroidManifest.xmlandroid:usesCleartextTraffic="true"Allows the current HTTP LAN URL on Android.
ios/Runner/Info.plistNSAllowsArbitraryLoads = trueAllows arbitrary network loads on iOS.

Branding, palette, launcher assets, and settings

The app’s real display labels are not identical. Preserve that distinction when changing store metadata, launcher output, screenshots, or documentation.

SurfaceCurrent value
Dart app titleMono Vendor from AppConstants.appName
Android launcher labelMono V from AndroidManifest.xml
iOS display nameMono Vendor from Info.plist
Android / iOS IDcom.mono.vendor.app
Dark / light controlInside StoreSettingsScreen, not the navigation drawer

Primary theme colors

Slate#0F172A
Emerald#059669
Emerald light#34D399
Sapphire#2563EB
Amber#F59E0B
Purple#8B5CF6
Teal#14B8A6
Sky#0EA5E9
Danger#EF4444

pubspec.yaml declares no font family or bundled font assets. The app uses Flutter theme typography and a small number of explicit monospace contexts.

Launcher icon configuration

flutter_launcher_icons uses assets/icons/app_icon.png and app_icon_foreground.png, with an adaptive background of #059669. Its generation setting says min_sdk_android: 21; the actual Android app currently builds with maxOf(flutter.minSdkVersion, 23). These values serve different purposes and are not interchangeable.

Android FCM is lazy; realtime uses server-issued Ably tokens

main.dart initializes API, theme, locale, and auth providers, but it does not initialize Firebase. Authenticated MainVendorShell binds the notification store, connects Ably notifications, then starts FCM in the background.

main()
  └─ MonoVendorApp
      └─ authenticated MainVendorShell
          ├─ bind VendorNotificationStore
          ├─ connect Ably notification channel
          └─ FirebasePushService.initialize()
              ├─ Android guard
              ├─ high_importance_channel
              ├─ request notification permission
              ├─ register foreground/open/refresh listeners
              └─ register device token

Set up your own Firebase project, step by step

The repository ships with a working google-services.json so the app runs immediately, but that file points at a shared Firebase project. Create your own before you publish. The whole process takes about ten minutes and needs only a free Google account.

  1. Create the project. Open console.firebase.google.com, click Add project, give it a name such as mono-vendor, and disable Google Analytics unless you want it. The project finishes creating after you confirm the analytics choice.
  2. Add the Android app. On the project overview click the Android icon. Enter the package name — it must match your applicationId character for character, so use com.mono.vendor.app if you have not renamed it yet. Give the app a nickname and download google-services.json.
  3. Place the config file. Copy it to android/app/google-services.json, replacing the bundled one. Both the filename and the folder are required by the Google Services Gradle plugin; a wrong path builds fine but throws Default FirebaseApp is not initialized at runtime.
  4. Enable Cloud Messaging. In the left sidebar open Build → Cloud Messaging. The Send test message button confirms the project can deliver notifications. Nothing else is required for FCM to work.
  5. Leave the channel to the app. The app creates an Android notification channel named high_importance_channel (“Orders and Updates”) at runtime. Do not create a matching channel in the console — the app owns it, and a duplicate console channel is ignored.
  6. Rebuild rather than hot reload. Changing google-services.json needs a full rebuild. Stop the app and run flutter run -d <android-device-id> again, adding flutter clean first if the old configuration appears to be cached.

Finding your values. Project settings → Your apps shows the registered package name and the API key. Never commit a service-account key or a private key file. The API key inside google-services.json identifies the project but is not a secret by itself — access is governed by Firebase security rules.

Android push facts

  • android/app/google-services.json is tracked and contains the com.mono.vendor.app client. Replace the placeholder values with your own Firebase credentials.
  • The Android channel is high_importance_channel, labeled “Orders and Updates”.
  • Token registration posts to /vendor/notifications/register-token; logout unregisters through /vendor/notifications/unregister-token.
  • A stable vendor_notification_device_id is created and kept in secure storage.
  • FirebasePushService.initialize() returns without work on non-Android targets.

Ably chat and notifications

ably_vendor_chat_service.dart and ably_vendor_notification_service.dart request token requests from the backend chat-token endpoint and use Ably auth callbacks. No hard-coded Ably API key is present in the current Dart source.

iOS provisioning is developer-supplied. Generated plugin registration can include Firebase plugins, but Apple signing, APNs credentials, the Firebase plist, and the iOS Dart initialization path must be configured by the developer. Follow the iOS setup section below to complete the integration.

iOS setup: signing, Firebase, and push notifications

Complete the setup below to take the generated iOS target from local development to a signed build with APNs and Firebase Cloud Messaging. The Flutter shell and bundle identifier are present in the repository; Apple credentials, APNs credentials, and the Firebase iOS configuration are supplied through Xcode, Firebase, and the Apple Developer portal.

Before you begin: use macOS with Xcode, Flutter 3.44.0 or newer, CocoaPods, an Apple Developer team, and access to the Firebase project. Keep the APNs .p8 key, signing assets, and private credentials outside source control.

Setup areaRequired configuration
WorkspaceOpen ios/Runner.xcworkspace after resolving Flutter packages and CocoaPods.
Bundle / targetUse com.mono.vendor.app with an iOS 15.0 deployment target.
Apple signingSelect the organization’s development team in Xcode and use automatic signing for development and distribution.
Firebase iOS appRegister com.mono.vendor.app in Firebase and add its GoogleService-Info.plist to the Runner target.
Push notificationsEnable Push Notifications and the Remote notifications background mode in the Runner target.
Dart initializationUpdate the Android-only guard in lib/services/firebase_push_service.dart so iOS initialization and token registration are allowed.

1. Prepare Apple and Firebase access

  • In the Apple Developer portal, create or select an App ID for com.mono.vendor.app and enable App Push Notifications.
  • Create an APNs authentication key and save the .p8 file securely. Record its Key ID and Apple Team ID; do not paste the key or private material into this guide.
  • In the Firebase project used by this app, register an iOS app with the exact bundle ID com.mono.vendor.app, then download GoogleService-Info.plist.

2. Resolve Flutter and CocoaPods

flutter pub get
cd ios
pod install
cd ..
open Runner.xcworkspace

The repository does not check in a Podfile. If CocoaPods reports that the file is missing, restore the standard Flutter iOS Podfile for the installed Flutter SDK, review it, and then run pod install. Always open the workspace, not the bare Runner.xcodeproj.

3. Configure signing in Xcode

  1. Open ios/Runner.xcworkspace and select the Runner project.
  2. Open Signing & Capabilities for the Runner target.
  3. Enable Automatically manage signing, select the organization’s Apple Developer team, and confirm the bundle identifier is com.mono.vendor.app.
  4. Keep the deployment target at iOS 15.0 or higher, choose a physical iPhone for notification testing, and resolve any signing errors before continuing.

4. Add the Firebase iOS configuration

  1. Drag GoogleService-Info.plist into the ios/Runner directory.
  2. In Xcode, open the file’s inspector and confirm Target Membership includes Runner.
  3. Do not add API keys, APNs private keys, or signing credentials to documentation, source comments, or screenshots.

5. Enable APNs and background delivery

  1. In Signing & Capabilities, add the Push Notifications capability to the Runner target.
  2. Add Background Modes and enable Remote notifications.
  3. In Firebase Console, open Project settings → Cloud Messaging → iOS, upload the APNs .p8 key, and enter its Key ID and Apple Team ID.
  4. Build and run on a physical iPhone, allow notifications when prompted, and confirm the app receives a foreground and background test message.

6. Enable the Dart-side iOS path

The current FirebasePushService.initialize() returns immediately unless the platform is Android. For iOS push, change that guard so both Android and iOS continue through the existing Firebase initialization, permission request, foreground handling, and token registration flow. Keep the authenticated lazy initialization in MainVendorShell; do not initialize a second unrelated notification service.

final supportedPlatform = Platform.isAndroid || Platform.isIOS;
if (!supportedPlatform) return;

await Firebase.initializeApp();
// Keep the existing permission, listener, and token flow below.

After the app signs in, verify that the device token is sent to /vendor/notifications/register-token and that logout calls /vendor/notifications/unregister-token. Confirm that the existing high_importance_channel behavior remains unchanged for Android.

7. Build, test, and release

flutter run -d <ios-device-id>
flutter build ios --no-codesign
flutter build ipa --release
  • Use flutter build ios --no-codesign as a compile/configuration check before enabling distribution.
  • Test login, notification permission, foreground delivery, background delivery, deep links, and logout unregistration on a physical device.
  • For TestFlight or the App Store, select the correct team and distribution profile in Xcode, increment the build number, archive the Runner scheme, and validate the IPA before upload.

Build commands and expected targets

Use the normal Flutter commands after package resolution. Select a real device ID rather than assuming an emulator name.

Android debug run

flutter pub get
flutter run -d <android-device-id>
flutter build apk --debug

Android application ID and namespace are both com.mono.vendor.app. The debug build can use the bundled Google services client and the local HTTP development URL.

Change the application ID before you publish

Both platforms ship with the identifier com.mono.vendor.app, which is a real reverse-domain identifier and builds fine. Google Play and the App Store each require the identifier to belong to the account publishing the app, so replace it with your own before your first upload. Pick a domain you own — for example com.yourcompany.mono.vendor.

PlatformFileWhat to change
Android namespaceandroid/app/build.gradle.ktsnamespace = "com.yourcompany.mono.vendor"
Android application IDandroid/app/build.gradle.ktsapplicationId = "com.yourcompany.mono.vendor"
iOS bundle IDios/Runner.xcodeproj/project.pbxprojPRODUCT_BUNDLE_IDENTIFIER for the Runner target (leave the .RunnerTests entries alone unless you rename them too)
Firebase Android appFirebase consoleRe-register the app under the new package name and download a fresh google-services.json

Renaming the Android package also means moving the Kotlin sources to match: android/app/src/main/kotlin/com/mono/vendor/app/MainActivity.kt becomes android/app/src/main/kotlin/com/yourcompany/mono/vendor/app/MainActivity.kt, and its package line must change too. Forget this and the build fails with a Namespace 'com.mono.vendor.app' is not a valid namespace error pointing at the manifest.

Android SDK levels are pinned deliberately

android/app/build.gradle.kts sets compileSdk = 37 and pins targetSdk = 36 as an explicit integer rather than flutter.targetSdkVersion. The Flutter value resolves to 35 on Flutter 3.29 and newer, which is below the current Google Play submission requirement, so the explicit number keeps your uploads accepted as you upgrade Flutter. minSdk stays at maxOf(flutter.minSdkVersion, 23) because Firebase Messaging and flutter_local_notifications need a modern minimum.

iOS run

open ios/Runner.xcworkspace

On macOS, open the workspace, select a development team and runnable signing configuration in Xcode, then complete the iOS setup section before testing notifications.

Other generated targets

macOS declares deployment target 12.0. Web and Windows folders are generated Flutter targets, but mobile-only imports mean the current source does not verify web support. Treat any such build as an engineering task, not an existing guarantee.

Release blockers visible in source

The repository is runnable source, but it does not contain production signing or production transport configuration. A release build command can still be issued, yet that is not the same as a store-ready artifact.

BlockerSource evidenceRequired decision
Android release uses debug signingandroid/app/build.gradle.kts assigns signingConfigs.getByName("debug") to release.Create and manage a real release keystore outside source control, then configure the release build securely.
No signing materialNo key.properties, JKS, or upload keystore is checked in.Provision the organization’s signing material and recovery process.
Local HTTP APIDefault is http://example.com/....Choose and implement a production API transport and base URL.
Cleartext / arbitrary loadsAndroid and iOS flags currently permit unencrypted transport.Tighten transport policy for the release platform.
iOS signing and pushApple team, profile, APNs capability, and Firebase plist are environment-specific.Follow the iOS setup section to provision signing, APNs, Firebase, and the Dart initialization path.

Release status: Android release signing is currently a debug-key placeholder. Do not present the current release build as suitable for store distribution.

Add work along the project’s actual layers

Mono Vendor uses repositories behind providers, with public screens selected by the shell. Extend the current layers rather than introducing a second navigation or state system.

Source-backed extension sequence

  1. Add or update the data shape under lib/models/.
  2. Add the server path to lib/services/api_endpoints.dart when a new endpoint is required.
  3. Implement request, response parsing, and error behavior in the matching lib/repositories/ class.
  4. Expose loading, mutation, and refresh state through a ChangeNotifier in lib/providers/.
  5. Register a persistent provider in the MultiProvider list in lib/main.dart when its lifetime is app-wide.
  6. Build the public UI under the appropriate lib/screens/ feature folder and reuse lib/widgets/ components.
  7. For a shell destination, add an AppConstants key, drawer selection, title mapping, and _buildActiveBody() case in MainVendorShell.
  8. Add focused tests under test/ for parsing, provider behavior, or widget output.
Screen
  └─ Provider<ChangeNotifier>
      └─ Repository
          ├─ ApiEndpoints path
          ├─ ApiClient / service
          └─ Model parsing

Worked example: add a wishlist feature module

Here is the sequence above applied to one concrete feature, so you can copy the shape rather than infer it. The example adds a vendor wishlist backed by a GET /vendor/wishlist endpoint.

  1. Model — lib/models/vendor_wishlist_item.dart. A plain data class with fromJson, matching the field names the endpoint returns.
  2. Endpoint — lib/services/api_endpoints.dart. Add a static path constant alongside the existing vendor routes; never inline a URL in a repository.
  3. Repository — lib/repositories/wishlist_repository.dart. Takes an ApiClient, calls the endpoint, maps the response into the model, and returns typed data or throws — no widget types.
  4. Provider — lib/providers/wishlist_provider.dart. A ChangeNotifier holding items, isLoading, and error, with load() and toggle(item). Register it in the MultiProvider list in lib/main.dart if it should survive navigation.
  5. Screen — lib/screens/wishlist/wishlist_screen.dart. A public *Screen class that watches the provider and renders loading, empty, error, and populated states. Reuse existing lib/widgets/ cards instead of restyling.
  6. Navigation. Push the screen with Navigator.push from an existing entry point. Only touch MainVendorShell if the feature is a new permanent drawer destination, in which case add the AppConstants key, the drawer item, the title mapping, and the _buildActiveBody() case together.
lib/
├─ models/vendor_wishlist_item.dart        ← new
├─ services/api_endpoints.dart             ← add wishlist path
├─ repositories/wishlist_repository.dart   ← new
├─ providers/wishlist_provider.dart        ← new
├─ screens/wishlist/wishlist_screen.dart   ← new
└─ widgets/wishlist_tile.dart              ← new, if reused

main.dart                                  ← register provider (if app-wide)

Test the boundary, not the pixels. A repository test that asserts fromJson handles a missing optional field, and a provider test that asserts load() sets error on failure, cover the parts most likely to break. Widget tests are worth adding when a screen has a non-trivial empty or error state.

Keep navigation truthful. The shell drawer belongs on Overview. Internal subviews should remain inside their owning screen unless a new public *Screen class is deliberately added and counted in the inventory.

Communication exists; a support-ticket system does not

Mono Vendor communicates with customers through the unified chat list/thread, follower conversation entry, notifications, and server-authorized Ably sessions. Store Settings exposes account and logout actions. These are the source-backed communication paths.

Checked itemSource result
Customer communicationUnified chat, thread replies, presence, followers, and notifications are implemented.
Support-ticket endpointNo support-ticket endpoint or repository exists.
Support contactNo email address, phone number, or external support contact is defined in this repository.
PaymentsSettlements, withdrawals, and hosted checkout exist; there is no payment-log screen.
MapsNo map/geolocation package is declared.
Screen count27 public *Screen classes plus MainVendorShell.

Known source limitations

  • The active API is a local cleartext LAN URL.
  • Android release mode is debug-signed.
  • iOS requires developer-provided Apple signing, APNs, Firebase plist, and Dart push initialization; the setup steps are documented above.
  • The app targets Android and iOS; mobile-only dart:io imports prevent a web build.
  • No source-backed support-ticket workflow or support contact exists.

Add your own credentials, signing keys, and production API base URL before you publish. They are intentionally left out of the source package so your keys stay private.