Skip to content

Repository files navigation

🌾 AgroMarket β€” Agricultural E-Commerce & Supply Chain Platform

AgroMarket Banner

Node.js React TypeScript PostgreSQL Drizzle ORM Safaricom M-Pesa WebSockets License: MIT

A modern, mobile-first agricultural marketplace bridging smallholder farmers and commercial agricultural producers with individual buyers and bulk institutions.


πŸ“‘ Table of Contents


🌟 Overview

AgroMarket solves the traditional friction in agricultural commodity trading by establishing a direct, transparent pipeline between farmers and buyers. It eliminates exploitative intermediaries, provides real-time fair pricing, guarantees quality through admin product moderation, and provides instant mobile checkout with Safaricom M-Pesa STK push and real-time payment reconciliation.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    BUYER     β”‚         β”‚  AGROMARKET  β”‚         β”‚FARMER/SELLER β”‚
β”‚ ──────────── β”‚         β”‚ ──────────── β”‚         β”‚ ──────────── β”‚
β”‚ Browse Crops β”‚ ──────> β”‚ Marketplace  β”‚ <────── β”‚ List Produce β”‚
β”‚ STK Checkout β”‚ ──────> β”‚ Escrow/Order β”‚ ──────> β”‚ Bulk Orders  β”‚
β”‚ Live Trackingβ”‚ <────── β”‚ /ws Realtime β”‚ <────── β”‚ Chat / Payoutβ”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸš€ Key Features & Capabilities

1. Dual Purchase Modes (Small vs. Bulk)

  • Small Purchases (Retail / Household): Buy in standard retail units (e.g., kg, bunches, bags) with instant cart calculation and full settlement.
  • Bulk Purchases (B2B / Commercial / Institutional): Buy at discounted wholesale rates with minimum quantity thresholds.
  • Split Payment Workflow (Deposit & Balance):
    • Buyers can place bulk orders by paying a 50% commitment deposit upfront via M-Pesa STK Push.
    • The remaining 50% balance is settled upon delivery and physical inspection.

2. Safaricom Daraja M-Pesa STK Push Integration

Modeled after enterprise fintech standards:

  • OAuth 2.0 In-Memory Token Caching: Tokens are cached for ~55 minutes, preventing Daraja rate-limiting and optimizing latency.
  • Support for Paybill & Till Numbers:
    • CustomerPayBillOnline for Paybill business shortcodes.
    • CustomerBuyGoodsOnline for Till Numbers / Buy Goods.
  • Smart Phone Number Sanitization: Automatically normalizes standard Kenyan phone formats (07..., 01..., +254..., 254...).
  • Complete Audit Trail (stk_push_responses): Logs every initiated STK prompt with CheckoutRequestID, MerchantRequestID, amounts, raw callbacks, and result statuses.
  • Built-in Mock Simulation Mode: Automatic local fallback for offline development or testing without live Daraja credentials.

3. Real-Time WebSocket Architecture

Mounted on /ws with bi-directional JSON messaging:

  • Instant Payment Confirmation (payment.status): Immediately updates the buyer's checkout screen and order tracking timeline the exact millisecond Safaricom processes the M-Pesa PIN.
  • Live Order Status Broadcasting (order.status): Real-time notifications when orders transition between placed, approved, packed, shipped, and delivered.
  • Direct Peer-to-Peer Messaging: Real-time chat between buyers and farmers regarding crop conditions, custom bulk agreements, and delivery logistics.
  • Multi-Device Session Sync: Intelligently routes messages across multiple active browser tabs or mobile sessions for the same user.

4. Supplier Payout Engine

  • Automated Payout Splitting: When an order contains items from multiple farmers, the system splits and calculates each supplier's payout ledger automatically.
  • Payout Preferences: Farmers can configure preferred disbursement channels:
    • M-Pesa Mobile Money (Phone Number)
    • Bank Transfer (Bank Name & Account Number)
    • PayPal (Email Address)
  • Admin Clearance Portal: Dedicated administrator view to review, approve, and disburse pending supplier payouts.

5. Role-Based Access Control (RBAC)

  • Buyer: Marketplace exploration, advanced filters, cart management, checkout with M-Pesa STK/Stripe, live order tracking, chat with sellers.
  • Seller (Farmer): Product listing creation, harvest date scheduling, bulk pricing tiers, earnings analytics, order fulfillment, payout settings.
  • Admin: Quality control & product verification, user role governance, platform metrics, supplier payout approvals.

πŸ›  Tech Stack

Frontend Client

Backend Server

  • Runtime: Node.js 20+ (ES Modules)
  • Framework: Express.js with TypeScript
  • Database & ORM: PostgreSQL + Drizzle ORM
  • Real-Time Engine: ws (Native WebSocket Server)
  • Authentication: JWT (JSON Web Tokens) with OTP email verification
  • File Uploads: Multer with static disk storage

Payment & Third-Party Integrations


πŸ“‚ Project Architecture & Directory Structure

AgroMarket/
β”œβ”€β”€ client/                     # Frontend React SPA
β”‚   β”œβ”€β”€ public/                 # Static assets, logos, and uploads
β”‚   └── src/
β”‚       β”œβ”€β”€ components/         # Reusable UI components & dialogs
β”‚       β”‚   β”œβ”€β”€ ui/             # shadcn/ui base primitives (button, card, dialog, etc.)
β”‚       β”‚   β”œβ”€β”€ Header.tsx      # Navigation header with cart badge
β”‚       β”‚   β”œβ”€β”€ MobileNav.tsx   # Mobile responsive bottom navbar
β”‚       β”‚   └── OrderTrackingTimeline.tsx # Visual stepper for order stages
β”‚       β”œβ”€β”€ hooks/              # Custom React hooks
β”‚       β”‚   β”œβ”€β”€ useAuth.ts      # Authentication convenience hook
β”‚       β”‚   β”œβ”€β”€ usePaymentSocket.ts # Real-time M-Pesa & order WebSocket subscriber
β”‚       β”‚   └── use-toast.ts    # Interactive notification toast hook
β”‚       β”œβ”€β”€ lib/                # API client, axios interceptors, query client
β”‚       β”œβ”€β”€ pages/              # Application views / routes
β”‚       β”‚   β”œβ”€β”€ auth/           # Login, Register, VerifyOtp
β”‚       β”‚   β”œβ”€β”€ AdminDashboard.tsx  # Product approvals & payout clearance
β”‚       β”‚   β”œβ”€β”€ SellerDashboard.tsx # Farmer inventory, earnings, and listings
β”‚       β”‚   β”œβ”€β”€ Cart.tsx        # Shopping cart & STK push checkout modal
β”‚       β”‚   β”œβ”€β”€ OrderTracking.tsx   # Live order progress & receipt verification
β”‚       β”‚   β”œβ”€β”€ ProductDetail.tsx   # Single product with bulk pricing options
β”‚       β”‚   └── Chat.tsx        # Real-time WebSocket messaging interface
β”‚       β”œβ”€β”€ store/              # Zustand global state (authStore)
β”‚       └── App.tsx             # Root router & layout wrapper
β”‚
β”œβ”€β”€ server/                     # Backend Express API & WebSocket Server
β”‚   β”œβ”€β”€ services/
β”‚   β”‚   └── mpesa.ts            # Enterprise MpesaService (Daraja STK push & callbacks)
β”‚   β”œβ”€β”€ db.ts                   # PostgreSQL Drizzle database connection
β”‚   β”œβ”€β”€ index.ts                # HTTP and WebSocket server entry point
β”‚   β”œβ”€β”€ routes.ts               # REST API endpoints & webhook controllers
β”‚   β”œβ”€β”€ socket.ts               # WebSocket connection registry & event broadcasting
β”‚   β”œβ”€β”€ storage.ts              # Database repository / access layer
β”‚   └── vite.ts                 # Development Vite SSR / proxy integration
β”‚
β”œβ”€β”€ shared/
β”‚   └── schema.ts               # Drizzle database tables, relations, and Zod schemas
β”‚
β”œβ”€β”€ scripts/
β”‚   └── seed_admin.ts           # Admin user database seeder
β”‚
β”œβ”€β”€ drizzle.config.ts           # Drizzle Kit migration configuration
β”œβ”€β”€ package.json                # Dependencies and project scripts
β”œβ”€β”€ tailwind.config.ts          # Tailwind CSS design system tokens
└── tsconfig.json               # TypeScript compiler configuration

βš™οΈ Environment Configuration (.env)

Create a .env file in the root directory:

# ==============================================================================
# DATABASE CONFIGURATION
# ==============================================================================
DATABASE_URL=postgres://appuser:apppassword@localhost:5432/agromarket?sslmode=disable

# ==============================================================================
# SERVER & SECURITY
# ==============================================================================
PORT=8010
JWT_SECRET=agro-market-super-secret-key-1234
NODE_ENV=development
STANDALONE_API=true

# ==============================================================================
# SAFARICOM DARAJA M-PESA CONFIGURATION
# ==============================================================================
MPESA_ENV=sandbox                     # 'sandbox' or 'production'
MPESA_ACCOUNT_TYPE=till               # 'till' (Buy Goods) or 'paybill'
MPESA_CONSUMER_KEY=your_consumer_key
MPESA_CONSUMER_SECRET=your_consumer_secret
MPESA_SHORTCODE=174379                # Business Shortcode (or 174379 for Sandbox)
MPESA_TILL_NUMBER=174379              # Online Till Number (used when ACCOUNT_TYPE=till)
MPESA_PASSKEY=bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919
MPESA_CALLBACK_URL=https://your-domain.ngrok-free.app/api/payments/mpesa/callback
MPESA_MOCK_MODE=false                 # Set to 'true' to force mock mode in dev

# ==============================================================================
# STRIPE PAYMENTS (CARD CHECKOUT)
# ==============================================================================
STRIPE_PUBLISHABLE_KEY=pk_test_placeholder
STRIPE_SECRET_KEY=sk_test_placeholder
STRIPE_WEBHOOK_SECRET=whsec_placeholder

# ==============================================================================
# SMS & NOTIFICATIONS (OPTIONAL)
# ==============================================================================
TWILIO_ACCOUNT_SID=placeholder_sid
TWILIO_AUTH_TOKEN=placeholder_token
TWILIO_PHONE_NUMBER=placeholder_phone
AFRICAS_TALKING_USERNAME=sandbox
AFRICAS_TALKING_API_KEY=placeholder_api_key

πŸš€ Getting Started & Local Development

1. Prerequisites

  • Node.js: v20.x or higher installed (Download Node.js)
  • PostgreSQL: v14+ running locally or a hosted instance (Neon, Supabase, AWS RDS)
  • Git

2. Installation

Clone the repository and install all dependencies:

git clone https://github.com/Timothy970/AgroMarket.git
cd AgroMarket
npm install

3. Database Setup & Migrations

Ensure PostgreSQL is running and your DATABASE_URL is set in .env.

To push schema changes directly to your PostgreSQL database:

npm run db:push

Or generate and execute formal migration files:

npm run db:migrate

4. Seed Initial Admin Account

Seed default admin and test records into the database:

npm run db:seed-admin

5. Run Development Servers

Start both the Express Backend API (Port 8010) and Vite Frontend Dev Server (Port 5173) concurrently:

npm run dev

Open your browser and navigate to: πŸ‘‰ http://localhost:5173


πŸ“² M-Pesa STK Push Setup & Testing

Sandbox Configuration

  1. Register for an account on the Safaricom Developer Portal (Daraja).
  2. Create a new Sandbox App and enable Lipa Na M-Pesa Online.
  3. Copy your Consumer Key and Consumer Secret to .env.
  4. The default sandbox shortcode is 174379 with the official sandbox passkey:
    bfb279f9aa9bdbcf158e97dd71a467cd2e0c893059b10f78e6b72ada1ed2c919
    

Local Webhook Forwarding (Ngrok)

Because Safaricom Daraja needs a publicly reachable HTTPS endpoint to deliver callback webhooks:

  1. Start an ngrok tunnel pointing to your backend port:
    ngrok http 8010
  2. Copy the generated forwarding HTTPS URL and update .env:
    MPESA_CALLBACK_URL=https://abc123.ngrok-free.app/api/payments/mpesa/callback

Offline Simulation / Mock Mode

If you do not have live Daraja credentials configured (or leave placeholders in .env), the system automatically activates Mock Mode:

  • You can enter any Safaricom phone number in checkout.
  • The server will acknowledge the request with simulated IDs.
  • After 3 seconds, a realistic Safaricom callback will execute automatically, triggering database reconciliation and broadcasting real-time WebSocket confirmation.

πŸ”Œ WebSocket Protocol & Event Reference

AgroMarket exposes a unified WebSocket server at ws://localhost:8010/ws (or wss://<domain>/ws).

Client Authentication & Subscription

Upon connecting, clients send an auth frame:

{
  "type": "auth",
  "token": "<JWT_ACCESS_TOKEN>"
}

To subscribe to a specific order's live updates:

{
  "type": "subscribe_order",
  "orderId": "3b29c0b1-1234-4567-8901-abcdef012345"
}

Server-to-Client Broadcast Events

1. Payment Status Event (payment.status)

Emitted as soon as an M-Pesa STK callback arrives or is simulated:

{
  "type": "payment.status",
  "event": "payment.status",
  "channel": "payments.user-uuid",
  "data": {
    "orderId": "order-uuid",
    "checkoutRequestId": "ws_CO_123456789",
    "status": "success",
    "message": "Payment received successfully via M-Pesa",
    "amount": 2500,
    "receipt": "NL29X8YZ01",
    "phoneNumber": "254712345678",
    "timestamp": "2026-09-11T12:00:00.000Z"
  }
}

2. Order Status Event (order.status)

Emitted when an order stage updates:

{
  "type": "order.status",
  "event": "order.status",
  "orderId": "order-uuid",
  "data": {
    "orderId": "order-uuid",
    "status": "approved",
    "message": "Order payment confirmed",
    "timestamp": "2026-09-11T12:00:00.000Z"
  }
}

3. Chat Message (message)

{
  "type": "message",
  "message": {
    "id": "msg-uuid",
    "senderId": "user-1",
    "receiverId": "user-2",
    "productId": "product-uuid",
    "content": "Hello, is the harvest ready for pickup?",
    "createdAt": "2026-09-11T12:00:00.000Z"
  }
}

πŸ“‘ REST API Endpoints Reference

Authentication

  • POST /api/auth/register β€” Request OTP for user registration.
  • POST /api/auth/login β€” Request OTP for login.
  • POST /api/auth/verify β€” Verify OTP and receive JWT access token.
  • GET /api/auth/me β€” Retrieve current authenticated user profile.
  • PUT /api/auth/profile β€” Update user profile & payout preferences.

Products & Categories

  • GET /api/categories β€” List all active product categories.
  • POST /api/categories β€” Create category (Admin).
  • GET /api/products β€” Browse approved products with filters (category, search, minPrice, maxPrice, location).
  • GET /api/products/:id β€” Get product detail with bulk tiers.
  • POST /api/products β€” Create new product listing (Seller).
  • PUT /api/products/:id β€” Update listing (Seller).
  • DELETE /api/products/:id β€” Remove listing (Seller).
  • GET /api/products/seller/mine β€” Get seller's own products.
  • PATCH /api/products/:id/approval β€” Moderate/Approve product (Admin).

Shopping Cart

  • GET /api/cart β€” Get user's cart items with pricing & totals breakdown.
  • POST /api/cart β€” Add product to cart with purchase mode (small or bulk).
  • PUT /api/cart/:id β€” Update cart item quantity.
  • DELETE /api/cart/:id β€” Remove single item from cart.
  • DELETE /api/cart β€” Clear entire cart.

Orders & Tracking

  • POST /api/orders β€” Create new order with item snapshots.
  • GET /api/orders β€” List user's order history.
  • GET /api/orders/:id β€” Get detailed order summary & tracking timeline.
  • PATCH /api/orders/:id/status β€” Update status (approved, shipped, delivered).
  • PATCH /api/orders/:id/payment β€” Update payment flags (depositPaid, balancePaid).

Payments (M-Pesa & Stripe)

  • POST /api/payments/mpesa/stkpush β€” Initiate Lipa Na M-Pesa STK Push.
  • POST /api/payments/mpesa/callback β€” Daraja STK webhook receiver.
  • GET /api/payments/mpesa/query/:checkoutRequestId β€” Query Daraja STK transaction status.
  • POST /api/payments/stripe/create-checkout-session β€” Create Stripe card checkout session.
  • POST /api/payments/stripe/webhook β€” Stripe webhook receiver.

Supplier Payouts

  • GET /api/supplier-payouts β€” View supplier payout ledger (Admin / Seller).
  • PATCH /api/supplier-payouts/:id/approve β€” Approve payout amount (Admin).
  • POST /api/supplier-payouts/:id/pay β€” Mark payout as disbursed (Admin).

Messaging & Chat

  • GET /api/chat/conversations β€” List active user chat conversations.
  • GET /api/chat/messages/:receiverId β€” Fetch chat history with specific user.

πŸ“¦ Production Deployment

1. Build the Production Bundle

npm run build

This compiles the Vite frontend into dist/public and bundles the Express server into dist/index.js.

2. Run Database Migrations in Production

npm run db:migrate

3. Start Production Server

npm start

The server will bind to process.env.PORT (default 8010) and serve both the REST API and the static React production client.


πŸ“„ License

This project is licensed under the MIT License β€” see the LICENSE file for details.

About

AgroMarket is a mobile-first agricultural e-commerce platform connecting farmers (sellers) with buyers. The platform features dual purchase modes (small unit purchases and bulk orders with tiered pricing), role-based authentication, admin-approved product listings, seller payout preferences, and comprehensive order management with tracking.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages