From f04fc15fb9de43a85a79ef13998b9ffd09d60da8 Mon Sep 17 00:00:00 2001 From: Vusa Date: Wed, 1 Jul 2026 13:46:52 +0200 Subject: [PATCH] improving error message on batch item processing --- docs/PRODUCT_SPEC.md | 317 ++++++++++++++++++ .../groups/models/group_batch_model.dart | 4 + .../groups/models/group_batch_model.g.dart | 4 + .../groups/screens/batch_detail_screen.dart | 2 + 4 files changed, 327 insertions(+) create mode 100644 docs/PRODUCT_SPEC.md diff --git a/docs/PRODUCT_SPEC.md b/docs/PRODUCT_SPEC.md new file mode 100644 index 0000000..11f45a2 --- /dev/null +++ b/docs/PRODUCT_SPEC.md @@ -0,0 +1,317 @@ +# Velocity Pay — Product Specification + +**Version:** 1.0.1 +**Last Updated:** January 2026 +**Product Owner:** Velocity Africa (Qantra) + +--- + +## 1. Executive Summary + +Velocity Pay is a multi-platform bill-payment application that enables individuals and businesses in Zimbabwe to pay utilities, purchase airtime, and send batch payments through a single, streamlined experience. The application supports EcoCash, Mastercard/Visa (MPGS), and wallet-based payment processors, and is available across Android, iOS, and the web. + +Built with Flutter, Velocity Pay delivers a consistent, high-quality user experience on mobile devices and desktop browsers alike. It is designed from the ground up to support multi-workspace / multi-tenant scenarios, making it suitable for both individual consumers and organisations that manage multiple business entities. + +--- + +## 2. Target Audience + +| Segment | Description | +|---------|-------------| +| **Individual consumers** | Pay utility bills (ZESA electricity, water), purchase airtime (Econet, NetOne, Telecel), and top up mobile wallets. | +| **Small businesses** | Manage payments across a single workspace with history tracking and repeat transactions. | +| **Enterprises / NGOs** | Use batch payments via recipient **Groups** to disburse funds to many recipients at once (e.g. payroll, beneficiary disbursements). | +| **Developers / Integrators** | Organisations that need to embed payment functionality into their own systems can reference Velocity Pay's gateway integration patterns. | + +--- + +## 3. Supported Platforms + +| Platform | Status | Notes | +|----------|--------|-------| +| **Android** | GA | Native APK / App Bundle distribution via Google Play. | +| **iOS** | GA | Native IPA distribution via the App Store. | +| **Web** | GA | Progressive Web App (PWA) served via Nginx. Works on all modern browsers (Chrome, Firefox, Safari, Edge). | +| **Linux / macOS / Windows** | Beta | Desktop builds available for internal/admin use. | + +--- + +## 4. Core Feature Set + +### 4.1 Onboarding & Authentication + +- **Phone number sign-in:** Users enter their mobile number, receive an OTP verification code, and authenticate. +- **Google Sign-In:** OAuth-based authentication for web users (desktop and mobile web). +- **Persisted sessions:** Tokens are stored securely on-device so users remain signed in across cold starts. +- **Splash animation:** A branded loading animation plays on cold start before the app routes to the appropriate screen. + +### 4.2 Workspaces + +- After authentication, users are presented with a workspace selector if they belong to multiple organisations. +- A workspace bundles a user's billing accounts, transaction history, and groups under one organisational context. +- Single-workspace users are auto-routed directly to the home screen. +- Guest (unauthenticated) users receive a transient workspace UUID so they can still make one-off payments. + +### 4.3 Home Dashboard + +- **Account balance widget:** Displays the current balance for the authenticated user's workspace. Includes a currency selector (USD, ZWG, etc.). +- **Bill provider directory:** A dynamic, API-driven grid of available billers (Econet, NetOne, ZESA, Telecel, etc.). Each card shows the provider's logo, name, and description. +- **Recent activity feed:** A chronological list of the user's most recent transactions with status chips (Success / Pending / Failed). Each transaction includes a **Repeat** action that pre-fills the payment flow with the same details. +- **Pull-to-refresh:** Manually reload balances, providers, and transactions. +- **Responsive layout:** On mobile the UI uses a full-bleed SliverAppBar and bottom NavigationBar; on tablets and desktop it uses a side NavigationRail. + +### 4.4 Payment Flow + +The payment flow is a multi-step wizard with the following stages: + +| Step | Screen | Description | +|------|--------|-------------| +| 1 | **Home → Provider Select** | User taps a bill provider (e.g. Econet, ZESA). | +| 2 | **Recipients** | Choose a saved contact, enter a phone number manually, or pick from the device's native contacts. | +| 3 | **Product Selection** (conditional) | If the provider offers multiple products (e.g. airtime bundles, electricity tokens), the user picks the specific product and amount. | +| 4 | **Pay** | Enter payment amount (when not fixed by product), select the payment processor (EcoCash / MPGS / Wallet), enter the debit phone number, and optionally record the recipient's name and email for a receipt. | +| 5 | **Confirm** | Review all transaction details before submission. The user sees a line-item breakdown: amount, charge, gateway charge, tax, and total. | +| 6 | **Gateway** | The app opens the payment processor's checkout page (hosted WebView for Mastercard, or redirect for mobile wallets). The user completes payment authorisation. | +| 7 | **Polling** | The app polls the backend for the transaction result for up to 30 attempts (~90 seconds). Progress is indicated by a step counter and status text. | +| 8 | **Integration** | On success, the backend posts the payment to the billing provider (e.g. credits the electricity meter). A loading indicator shows this progress. | +| 9 | **Receipt** | A full transaction receipt is displayed with share capabilities (image export via `share_plus`). The receipt includes transaction ID, date, amount, charges, provider, and status. | + +**Error handling at every step:** Network errors, failed payments, and integration failures are surfaced with human-readable messages and a **Retry** button. Users can cancel polling at any time. + +### 4.5 Payment Processors + +| Processor | Label | Description | +|-----------|-------|-------------| +| **EcoCash** | `ECOCASH` | Zimbabwe's mobile money wallet. Authorisation via USSD push or in-app prompt. | +| **Mastercard Payment Gateway Services** | `MPGS` | Card payments (Visa, Mastercard). Hosted checkout page in a WebView. | +| **Wallet** | `WALLET` | In-app wallet balance (available only to authenticated users with a funded workspace wallet). | + +### 4.6 Transaction History + +- Full, searchable history of all past transactions for the current workspace. +- Each transaction item displays: provider icon, provider name, amount, date (relative time), and a coloured status chip. +- **Repeat transaction:** One-tap repeat that pre-fills the payment flow with the same provider, product, amount, and payment processor. +- **Receipt view:** Tap any historical transaction to view its full receipt. + +### 4.7 Groups & Batch Payments + +Groups allow users to organise recipients and send batch payments efficiently. + +- **Group creation:** + - **Manual form:** Enter a group name, description, and add recipients one at a time. + - **CSV file import:** Upload a CSV file containing recipient names, phone numbers, amounts, and email addresses. A sample CSV template is provided. +- **Group management:** View all groups, search by name, select multiple groups for bulk deletion. +- **Batch creation:** Within a group, create a payment batch that processes all recipients. Each batch is a discrete payment run with its own status. +- **Batch detail:** View the status of each item (recipient) in a batch. Individual batch items can be inspected for success/failure details. + +### 4.8 Users & Permissions + +- Authenticated workspace admins can view and manage the list of users associated with their workspace (accessible from the **More** menu). +- User listing is available at `/users` and is protected behind an auth guard. + +### 4.9 Uptime & Service Status + +- A real-time service status dashboard showing the operational state of every integrated bill provider and payment processor. +- Each service displays: + - Service name and icon (EcoCash, Econet, ZESA, etc.) + - Up/Down status indicator (green/red chip) + - Last-checked timestamp (relative time) +- Summary bar shows total counts of Up vs Down services. +- Data is fetched on-screen load and supports pull-to-refresh. + +### 4.10 Profile & Account Management + +- **Profile:** View account details (accessible from `/profile`). +- **Change Workspace:** Switch to a different workspace without logging out. +- **Logout:** Clears local session and returns to the landing screen. +- **Account Deletion:** GDPR/Play Store compliant account deletion request flow at `/delete-account`. + +### 4.11 Contact & Support + +- Dedicated contact screen accessible from the **More** menu. +- Footer links in the web navigation rail provide quick access to About, FAQs, Privacy Policy, and Terms of Service on the Velocity Africa website. + +--- + +## 5. Architecture & Technology + +| Layer | Technology | +|-------|-----------| +| **Framework** | Flutter (Dart 3.9+) | +| **State Management** | Provider + ChangeNotifier (with Freezed immutable models) | +| **Routing** | GoRouter (declarative, path-based, with auth guards) | +| **HTTP Client** | Dio | +| **Code Generation** | Freezed + json_serializable + build_runner | +| **Local Storage** | SharedPreferences (token, workspace ID, user preferences) | +| **Backend** | Velocity Pay API (`payapi.velocityafrica.net/api`) | +| **Auth** | OAuth 2.0 (Google) + Phone OTP | +| **Payment Gateway** | Mastercard MPGS (hosted checkout via WebView + JavaScript) | +| **Push Notifications** | Firebase Cloud Messaging | +| **Analytics** | Firebase | +| **Deployment** | Docker + Nginx (web), Google Play (Android), App Store (iOS) | + +--- + +## 6. Environment Configuration + +Velocity Pay supports compile-time environment switching via `--dart-define` flags: + +| Flag | Values | Description | +|------|--------|-------------| +| `APP_ENV` | `test`, `live` | Selects the runtime environment. Defaults to `test`. | +| `BASE_URL` | Any URL | Overrides the backend API base URL. | +| `CLIENTID` | String | Google OAuth web client ID. | +| `SIMULATE_PAYMENT_SUCCESS` | `true`, `false` | When `true`, the gateway flow returns a simulated success (development only). | +| `GATEWAY_SCRIPT_URL` | URL | Mastercard checkout JavaScript bundle URL. | + +**Pre-release checklist:** +- `assets/.env.live` points to the live API. +- `SIMULATE_PAYMENT_SUCCESS` is set to `false`. +- `GATEWAY_SCRIPT_URL` uses the production Mastercard script. + +--- + +## 7. Navigation Structure + +### Authenticated Shell (with nav bar / nav rail) + +``` +/home → Home dashboard (providers + recent activity) +/groups → Group listing +/groups/create → Create group (manual form) +/groups/create-from-file → Create group (CSV upload) +/groups/:groupId → Group detail +/groups/:groupId/batches/create → Create batch for group +/groups/batches/:batchId → Batch detail +/history → Full transaction history +/more → More menu (workspace switch, users, uptime, contact, logout) +/users → User management +/uptime → Service uptime status +/profile → User profile +/contact → Contact support +/workspace → Workspace selector +``` + +### Payment Flow (no nav in shell — full-screen wizard) + +``` +/recipients → Recipient selection +/make-payment → Payment form (amount, processor) +/confirm → Transaction confirmation +/gateway → Payment gateway (native WebView) +/gateway-web → Payment gateway (web) +/gateway-redirect → Gateway redirect handler +/poll → Transaction status polling +/poll/:id → Poll for specific transaction +/integration → Post-payment billing integration +/receipt → Transaction receipt +/receipt/:transactionId → Receipt for specific transaction +``` + +### Onboarding (full-screen, no shell) + +``` +/onboarding/landing → Welcome landing page +/onboarding/phone → Phone number entry +/onboarding/verify → OTP verification +/onboarding/login → Sign-in (Google OAuth for web) +/onboarding/complete → Onboarding complete / redirect +``` + +### Public + +``` +/splash → Animated splash screen +/delete-account → GDPR account deletion request +``` + +--- + +## 8. Key User Journeys + +### 8.1 First-Time User — Pay Airtime + +1. Opens app → splash animation plays. +2. (Guest) Assigned a transient workspace → lands on Home. +3. Taps **Econet** from the provider grid. +4. Enters recipient's Econet phone number. +5. Selects an airtime bundle product (e.g. $5 Airtime). +6. Chooses **EcoCash** as the payment processor. +7. Enters their own EcoCash number (the debit phone). +8. Reviews the confirmation screen: amount, charges, total. +9. Confirms → Gateway opens → approves the EcoCash prompt. +10. App polls for status → "Success". +11. Billing integration updates the airtime → Receipt displayed. +12. Taps **Share** to send receipt via WhatsApp. + +### 8.2 Returning User — Repeat Transaction + +1. Opens app → session is persisted → lands on Home. +2. Scrolls to **Recent Activity**. +3. Finds a past Econet airtime transaction, taps **Repeat**. +4. All fields are pre-filled → confirms without re-entering data. +5. Completes the gateway flow → Receipt shown. + +### 8.3 Business User — Batch Payment + +1. Signs in with Google → selects their organisation workspace. +2. Navigates to **Groups** via the nav bar. +3. Taps **+** → **Create from File** → uploads a CSV of 50 recipients. +4. Opens the group → taps **Create Batch**. +5. Reviews the batch summary (50 items, total amount). +6. Confirms → batch is submitted → each item processed individually. +7. Monitors batch progress on the batch detail screen. +8. All successes / failures are visible per item. + +--- + +## 9. Responsive Design & Accessibility + +- **Mobile (< 768px):** Bottom NavigationBar, single-column layout, SliverAppBar with the Velocity logo. +- **Tablet / Desktop (≥ 768px):** Side NavigationRail (256px wide, always visible), constrained content width (600px max), footer links with About/FAQs/Privacy/Terms. +- All interactive elements meet minimum touch target sizes (48×48dp). +- Skeleton loading placeholders are used during data fetches to reduce perceived latency. + +--- + +## 10. Security & Compliance + +- All API communication is over HTTPS. +- Auth tokens are persisted in platform-secure local storage. +- The Google OAuth client ID is a public value — no secrets are embedded in client bundles. +- Payment gateway integration uses Mastercard's hosted checkout; Velocity Pay never handles raw card numbers. +- GDPR compliance: Users can request account deletion via a dedicated in-app flow. +- Environment configuration uses compile-time flags rather than runtime `.env` files, preventing secrets from leaking into web bundles. + +--- + +## 11. Upcoming / Roadmap + +| Feature | Status | Target | +|---------|--------|--------| +| Push notifications for transaction status | Planned | Q2 2026 | +| Dark mode support | Planned | Q2 2026 | +| Multi-currency wallet top-up | Planned | Q3 2026 | +| Desktop app distribution (App Store / Microsoft Store) | Planned | Q3 2026 | +| Offline transaction queuing | Under Review | TBD | +| ZWL (ZiG) full currency support | In Progress | Q2 2026 | + +--- + +## 12. Glossary + +| Term | Definition | +|------|-----------| +| **Bill Provider** | A utility company or service provider whose bills can be paid via Velocity Pay (e.g. ZESA, Econet). | +| **Payment Processor** | The financial rail used to move funds (EcoCash mobile money, Mastercard/Visa card, in-app Wallet). | +| **Workspace** | An organisational context that groups billing accounts, transaction history, and recipient groups. | +| **Group** | A collection of recipients for batch payment processing. | +| **Batch** | A discrete payment run executed against a group of recipients. | +| **Gateway** | The Mastercard-hosted payment checkout page where card details are entered. | +| **Polling** | The process of repeatedly checking the backend for a transaction's final status after gateway authorisation. | +| **Integration** | The backend step that posts a confirmed payment to the bill provider's system (e.g. crediting a meter). | +| **MPGS** | Mastercard Payment Gateway Services — the card payment processor. | + +--- + +*For technical setup instructions, environment configuration, and build commands, refer to the project's [README.md](../README.md).* \ No newline at end of file diff --git a/lib/screens/groups/models/group_batch_model.dart b/lib/screens/groups/models/group_batch_model.dart index a62c289..a00bbc4 100644 --- a/lib/screens/groups/models/group_batch_model.dart +++ b/lib/screens/groups/models/group_batch_model.dart @@ -57,6 +57,8 @@ class GroupBatchItem { final String? status; final String? transactionId; final String? errorMessage; + final String? confirmError; + final String? integrationError; final String? createdAt; final String? billName; final String? billProductName; @@ -80,6 +82,8 @@ class GroupBatchItem { this.providerLabel, this.providerImage, this.creditAddress, + this.confirmError, + this.integrationError, }); factory GroupBatchItem.fromJson(Map json) => diff --git a/lib/screens/groups/models/group_batch_model.g.dart b/lib/screens/groups/models/group_batch_model.g.dart index d018201..0b338ac 100644 --- a/lib/screens/groups/models/group_batch_model.g.dart +++ b/lib/screens/groups/models/group_batch_model.g.dart @@ -62,6 +62,8 @@ GroupBatchItem _$GroupBatchItemFromJson(Map json) => providerLabel: json['providerLabel'] as String?, providerImage: json['providerImage'] as String?, creditAddress: json['creditAddress'] as String?, + confirmError: json['confirmError'] as String?, + integrationError: json['integrationError'] as String?, ); Map _$GroupBatchItemToJson(GroupBatchItem instance) => @@ -75,6 +77,8 @@ Map _$GroupBatchItemToJson(GroupBatchItem instance) => 'status': instance.status, 'transactionId': instance.transactionId, 'errorMessage': instance.errorMessage, + 'confirmError': instance.confirmError, + 'integrationError': instance.integrationError, 'createdAt': instance.createdAt, 'billName': instance.billName, 'billProductName': instance.billProductName, diff --git a/lib/screens/groups/screens/batch_detail_screen.dart b/lib/screens/groups/screens/batch_detail_screen.dart index b6f3143..f701232 100644 --- a/lib/screens/groups/screens/batch_detail_screen.dart +++ b/lib/screens/groups/screens/batch_detail_screen.dart @@ -2994,6 +2994,8 @@ class _BatchDetailScreenState extends State ], ), Text(item.creditAddress ?? ''), + Text(item.confirmError ?? ''), + Text(item.integrationError ?? ''), ], ), ),