devsnack
Documentation

GreenCart documentation

Run it, point it at your own accounts, ship it under your own brand. Written against version 1.0.0 of the download you get on CodeCanyon.

$19 on CodeCanyon
  • Version v1.0.0
  • Updated Jun 2026
  • Platform Flutter
  • Stack Flutter · Next.js
On this page
01

Overview

A multi-vendor organic & local grocery delivery marketplace — three Flutter apps (customer + rider + vendor) plus one Next.js project that is the public storefront, the /vendor portal, the /admin panel, and the sole backend.

Live demo: https://greencart.devsnack.dev

GreenCart Market is a multi-vendor organic & local grocery delivery marketplace, sold as a 6-surface bundle:

  • Customer Flutter app — shoppers browse vendors, build a multi-vendor cart, check out, and track deliveries.
  • Rider Flutter app — delivery riders accept jobs, navigate, and capture proof of delivery.
  • Vendor Flutter app — vendors run the store from a phone: incoming orders and status transitions, stock, earnings, reviews.
  • One Next.js project — the public SSR storefront at /, the vendor portal at /vendor, the super-admin panel at /admin, and the only backend (every /api/* route). No second server exists.

It is a vertical marketplace for organic / local / farm-to-table grocers, built on a modern TypeScript stack (Next.js 16 + PostgreSQL + Drizzle ORM) rather than the PHP/Laravel platforms that dominate this category. Two differentiators the incumbents lack:

  • Subscription produce boxes — recurring weekly/biweekly grocery boxes with skip/pause.
  • Product provenance / sourcing — every product carries a farm/origin “provenance card.”

Portable by design: deploy to Vercel + Neon (the easy path) or to any Node host / VPS + any Postgres (the portable path). The only platform-specific dependency is Vercel Cron, which degrades to any scheduler hitting the CRON_SECRET-guarded routes.

Note
Canonical references. Full spec lives in PRD.md (schema, API, screens), the build contract in CLAUDE.md, the design system in DESIGN.md, and the production deploy walkthrough in docs/DEPLOY_VERCEL.md. This document does not duplicate them — it points to them.
02

What’s included

  • Full source for all four apps — three Flutter apps (customer_app/, rider_app/, vendor_app/) + one Next.js project/backend (web/).
  • Complete Drizzle schema + SQL migrations (web/src/db/).
  • The “Modern Agrarian” design system — Tailwind v4 CSS-first theme + matching Flutter ThemeData.
  • Branding pipeline — a single SVG mark in brand/ regenerates every web favicon/icon/OG image and both Flutter launcher icons.
  • Buyer docs (this file), a 20-minute quick-start, and the Vercel + Neon deploy guide.
  • Vitest backend integration suites + Flutter unit/widget tests.
  • 6 months Item Support (per the Envato Item Support Policy) and free future updates.
Note
No demo seed. The package ships with an empty database — a deliberate clean-package choice (no bundled credentials, nothing for a reviewer to flag). You create your own data and promote your first account to admin; see Database setup.
03

Features

Customer Flutter app

Discover
Email/password auth (JWT), home with a “local stores near you” vendor rail, featured grid, and a subscription promo. Vendor directory + per-vendor storefronts.
Browse & search
Filters for organic / local / seasonal, product detail with the provenance card, reviews, and write-a-review (purchase-gated).
Multi-vendor cart
Cart grouped by vendor, coupon entry, and AI recipe ideas from the cart contents.
Checkout
Per-vendor split, COD / Stripe PaymentSheet / PayPal webview. The app charges exactly what the server quote returns — no money math on the device.
Orders & tracking
Orders list + a live tracking map that polls /track for rider position and status.
Subscriptions & more
Subscription boxes (pause/skip/resume/cancel), favorites, notifications, addresses CRUD, profile + avatar upload, optional AdMob banner (gated by app settings).

Rider Flutter app

Dashboard
Online toggle, today’s deliveries, and earnings at a glance.
Deliveries
Assigned deliveries by slot; detail screen with pickup (vendor) and drop (customer).
Navigation
Embedded Google Maps turn-by-turn navigation with a throttled location ping back to the backend.
Proof & cash
Proof-of-delivery photo upload and a COD “cash collected” action that flips the order to paid.
Earnings & history
Earnings (today / week / all-time), delivery history, profile.

Vendor Flutter app

Dashboard
Today / this month sales, open orders, active products, low stock, payout balance and rating, plus a 14-day sales sparkline and recent orders.
Orders
This vendor’s sub-orders with status filter chips; detail shows line items, customer, rider and the commission/payout split. The status-advance button mirrors the server’s allowed transitions — the client never invents one.
Products
Catalogue with search, an inline stock stepper and publish toggle, plus a full create/edit form with category picker, provenance, SEO and R2 image upload.
Earnings
Unsettled payout balance, closed payout history, and the underlying ledger entries.
Reviews & store
Reviews on this vendor’s products with a hide action (admin moderation stays authoritative), notifications, and store profile / hours / delivery radius.
Onboarding state
A vendor whose application isn’t approved signs in and lands on an application-pending screen rather than an error wall — every other endpoint refuses them by design.

Uses no Maps or payment SDKs — API_BASE_URL is the only dart-define it needs. Tenant-isolated server-side: a vendor can only ever read or write its own rows. Coupons and subscription boxes remain web-only in /vendor.

Storefront (web, /)

SSR/SEO marketplace — home, vendors directory + indexable vendor storefronts (/vendors/[slug]), shop/catalog, product detail (provenance + JSON-LD), search, cart, checkout split, subscription boxes, account + my orders (live tracking) + manage subscription, auth, sitemap/robots/OG.

Vendor portal (web, /vendor)

Onboarding/apply, dashboard (KPIs, payout balance, low-stock), products CRUD (+ R2 image upload, provenance, SEO), this vendor’s sub-orders + status transitions, subscriptions, vendor coupons, payouts (earnings/commission/history), store settings, reviews, notifications. Tenant-isolated — a vendor only ever sees its own rows.

Admin panel (web, /admin)

KPI dashboard (GMV, commission, charts); Vendors (approve/suspend/set commission); Orders (all + filters + real Stripe/PayPal refunds); Riders (CRUD + assign); Customers; Payouts (generate per period + mark paid); Categories; Coupons (platform + vendor); Subscriptions; Reviews (moderation); Settings (appSettings); Reports (sales, commission, GMV/commission trend chart, top vendors/products, churn, CSV export).

Backend (Next.js API)

REST under /api/* — auth, catalog/discovery, server cart, checkout (quote/intent/orders split + commission ledger), orders + /track, subscriptions, vendor/*, admin/*, rider/*, uploads/sign (R2), devices/fcm-token, public settings, the vendor/* REST surface the vendor app consumes (15 endpoints — profile, dashboard, orders + status, products + stock/active, categories, payouts, reviews, notifications, settings), webhooks/{stripe,paypal}, ai/{recipes,seasonal}, and two Vercel Cron jobscron/subscriptions (generate box orders + advance cycles) and cron/payout-run (close vendor payout periods). Both are CRON_SECRET-guarded and idempotent.

04

Architecture

green-cart/
green-cart/
  customer_app/   Flutter customer (Riverpod 3 + GoRouter + Dio + freezed)
  rider_app/      Flutter rider (same stack)
  vendor_app/     Flutter vendor (same stack, no Maps/payment SDKs)
  web/            Next.js 16 — storefront + /vendor + /admin + the backend
    src/app/(storefront)/   public SSR marketplace at /
    src/app/vendor/         vendor portal
    src/app/admin/          super-admin panel
    src/app/api/            the backend (all routes)
    src/db/                 Drizzle schema + migrations
    src/lib/                auth (JWT), payments, r2, ai, cron helpers
  brand/          SVG logo sources (single source of truth)
  docs/           DEPLOY_VERCEL.md, codecanyon/
AreaMobile (Flutter)Web + Backend (Next.js)
Core
Flutter 3.x / Dart 3
Next.js 16 · React 19 · TypeScript
State / routing / models
Riverpod 3.x · GoRouter · freezed + json_serializable
UI
Material
Tailwind v4 · shadcn/ui · recharts
Data
dio (typed client)
Drizzle ORM → Neon Postgres
Auth
flutter_secure_storage (JWT)
JWT (jose HS256) + argon2 · requireUser(roles)
Payments
flutter_stripe · webview_flutter (PayPal) · COD
Stripe + PayPal (platform-collected) + commission ledger + real refunds
Files
Cloudflare R2 (S3-compatible)
Maps / push / AI
google_maps_flutter · firebase_messaging (push only)
Vercel Cron · optional OpenAI / Gemini

Invariants (do not violate)

  • Single backend, single DB. Only the Next.js app touches Postgres. No client ever gets DB credentials.
  • Mobile apps are thin JWT clients. Flutter calls typed HTTP endpoints for everything — no business logic or money math on the device.
  • Multi-vendor cart → order split. Checkout always splits one cart into one order + N subOrders (one per vendor), each independently fulfilled, tracked, settled.
  • Commission ledger + payouts. The platform collects the whole payment; each sub-order records commission fields and ledgerEntries accrue to a vendor payout balance.
  • Real-time via polling through the backend — never client→DB listeners (SSE is the documented upgrade path).
  • Config in the DB — a single appSettings row (theme, commission, feature flags, currency, tax).
  • Firebase is push-only — no Firestore, no Firebase Auth, no Cloud Functions.
05

Quick setup

The fastest path from the downloaded zip to all three surfaces running locally (≈20 minutes). The apps run fully on COD with just API_BASE_URL set — payment/maps/AI keys are optional.

Prerequisites

Node 20+, Flutter 3.x (Dart 3), Xcode and/or Android Studio for a simulator/emulator, and a Postgres URL (Neon’s free tier works).

  1. 01

    Bootstrap the backend

    terminal
    cd web && npm install
    cp .env.example .env   # fill DATABASE_URL, DATABASE_URL_UNPOOLED,
                           # JWT_ACCESS_SECRET, JWT_REFRESH_SECRET, CRON_SECRET
    npm run db:migrate
    npm run dev            # → http://localhost:3000

    Register a user in the browser, then in a second terminal run npm run db:studio and set that user’s role to admin — reload /admin and the panel unlocks.

  2. 02

    Run the Flutter apps

    terminal
    cd ../customer_app && flutter pub get
    cp dart_defines.example.json dart_defines.json   # set API_BASE_URL
    flutter run --dart-define-from-file=dart_defines.json
    
    # same three steps in ../rider_app and ../vendor_app

    Use http://10.0.2.2:3000 as API_BASE_URL on the Android emulator and http://localhost:3000 on the iOS simulator (no trailing /api). For the rider flow, create a rider user and set its role to rider in db:studio, then assign it a sub-order from /admin.

Build commands

terminal
npm run build                                                       # Next.js production build (web/)
flutter build appbundle --release --dart-define-from-file=dart_defines.json   # Android
flutter build ipa --release --dart-define-from-file=dart_defines.json         # iOS

For a production deployment (Vercel + Neon, env checklist, migrations, crons, webhooks, smoke test), see docs/DEPLOY_VERCEL.md.

Note
Packaging note. There is no root README.md yet. Before listing, add one (or rely on this docs/codecanyon/ set) so buyers landing in the repo root find the setup path immediately.
06

Database setup

  1. 01
    Create a Postgres database. Neon (free tier) is recommended; any Postgres works.
  2. 02
    Set DATABASE_URL (the pooled connection) and DATABASE_URL_UNPOOLED (the direct connection, used by migrations) in web/.env.
  3. 03

    Run migrations against the unpooled URL:

    terminal
    cd web
    DATABASE_URL="<neon-unpooled-url>" npm run db:migrate

Open the GUI any time with npm run db:studio.

Note
There is no seed. The DB ships empty. Register your first account through the app or storefront, then in db:studio set that user’s role to admin (or vendor / rider) to unlock the corresponding panel.
07

Optional integrations

Every integration gracefully no-ops when unconfigured — payment intents return 503, R2 presign checks isConfigured(), AI falls back to a safe mock, FCM just stores tokens. COD works with zero payment configuration.

IntegrationUnlocksEnv varsWhere to get keys
Stripe
Card checkout + refunds
STRIPE_SECRET_KEY, STRIPE_WEBHOOK_SECRET, NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY
dashboard.stripe.com
PayPal
PayPal checkout + refunds
PAYPAL_CLIENT_ID, PAYPAL_SECRET, PAYPAL_ENV, PAYPAL_RETURN_URL, PAYPAL_CANCEL_URL, NEXT_PUBLIC_PAYPAL_CLIENT_ID
developer.paypal.com
Cloudflare R2
Product / avatar / proof images
R2_ACCOUNT_ID, R2_ACCESS_KEY_ID, R2_SECRET_ACCESS_KEY, R2_BUCKET, R2_PUBLIC_BASE_URL, NEXT_PUBLIC_R2_PUBLIC_BASE_URL
dash.cloudflare.com → R2
Firebase / FCM
Device-token storage Push send = roadmap
FCM_SERVICE_ACCOUNT
console.firebase.google.com
OpenAI or Gemini
AI recipes / seasonal picks
OPENAI_API_KEY or GEMINI_API_KEY
platform.openai.com / aistudio.google.com
Google Maps
Rider nav + storefront maps + tracking
NEXT_PUBLIC_GOOGLE_MAPS_BROWSER_KEY + per-app native keys (see Google Maps key setup)
console.cloud.google.com

To extend the platform with a new optional integration, mirror the existing probe pattern: a server-side isConfigured() check that returns a graceful fallback (a 503 or a mock) when the env var is unset, so a fresh install never crashes on a missing key.

08

AI provider setup

Two endpoints power the AI features: /api/ai/recipes (recipe ideas from cart contents) and /api/ai/seasonal (seasonal produce picks). Both call web/src/lib/ai/ server-side only.

  • Set OPENAI_API_KEY or GEMINI_API_KEY in the server env — never in a Flutter build.
  • Both routes are daily rate-limited per user via a Postgres counter, so a buyer can’t run up a bill before noticing.
  • When no key is set, the endpoints return a safe mock so the screens still render.
  • Toggle and cap via appSettings featureAiEnabled and aiDailyCapPerUser.
Warning
Reviewer note. AI keys must never reach a client bundle. A grep for OPENAI_API_KEY / GEMINI_API_KEY under customer_app/ or rider_app/ returns zero matches — keep it that way.
09

Payments setup

Stripe

  1. 01
    Create a Stripe account; get STRIPE_SECRET_KEY + NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY.
  2. 02
    Dashboard → Webhooks → add https://<deploy>/api/webhooks/stripe listening to payment_intent.succeeded (+ charge.succeeded); paste the signing secret as STRIPE_WEBHOOK_SECRET.
  3. 03
    The customer app uses flutter_stripe PaymentSheet on the returned clientSecret. If STRIPE_PUBLISHABLE_KEY isn’t passed as a dart-define, the app hides the Card option (COD + PayPal still work).

PayPal

  1. 01
    Set PAYPAL_CLIENT_ID + PAYPAL_SECRET + PAYPAL_ENV (sandbox|live).
  2. 02
    Set PAYPAL_RETURN_URL / PAYPAL_CANCEL_URL. The customer app’s --dart-define=PAYPAL_RETURN_URL must match the server value — the webview detects completion by watching for that URL (there is no deep-link scheme).
  3. 03
    Webhook at /api/webhooks/paypal; the authoritative paid signal is the synchronous capture inside POST /api/orders.

Cash on delivery

Works out of the box with zero config. The rider collects cash and taps “cash collected” to flip the order to paid.

Note
Refunds are real. An admin refund issues the actual Stripe/PayPal refund and reverses the commission ledger via adjustment entries (idempotent). Stripe Connect auto-payouts are a documented roadmap path — the shipped flow is manual payout settlement via cron/payout-run + admin “mark paid.”
10

Push notifications and live tracking

Push notifications (FCM)

  1. 01
    Create a Firebase project, add an iOS and an Android app, and run flutterfire configure in each Flutter app. The native config files are gitignored, and Firebase init is wrapped in try/catch so a missing config is a soft no-op.
  2. 02
    Paste the full service-account JSON (single line) into FCM_SERVICE_ACCOUNT in the server env.
  3. 03
    iOS: in Xcode enable Push Notifications + Background Modes.
Note
Roadmap. Today the backend stores device tokens (/api/devices/fcm-token); server-side push send is on the roadmap. In-app notifications are fully wired. Stated plainly so you don’t open a ticket asking where push sends are.

Live tracking (polling)

Order status and rider location update via short-interval polling through the backend GET /api/orders/[id]/track, fed by the rider app’s throttled POST /api/rider/location ping. There is no Pusher and no client→DB listener; an SSE upgrade is the documented path if you need lower latency.

11

Google Maps key setup

Enable Maps SDK for Android, Maps SDK for iOS, and Directions API (the rider app calls Directions directly). Keys go into both the native config and the dart-define:

iOS native
customer_app/ios/Flutter/Secrets.xcconfig + rider_app/ios/Flutter/Secrets.xcconfig (gitignored; copy the .example) → substituted into Info.plist GMSApiKey
Android native
GOOGLE_MAPS_ANDROID_KEY in */android/local.properties (or an env var) → manifest placeholder
Dart (Directions)
GOOGLE_MAPS_ANDROID_KEY / GOOGLE_MAPS_IOS_KEY in each dart_defines.json
Warning
Restriction caveat. The same key that makes the Directions web-service call cannot be application-restricted (Google rejects app-restricted keys on web-service APIs). Leave it API-restricted/unrestricted, or use a second key for Directions.
12

Branding and customization

Source of truth — brand/*.svg

Edit mark.svg, icon-customer.svg, icon-rider.svg, the foreground SVGs, and og.svg, then regenerate:

terminal
cd web && npm run gen:brand          # web favicon/icons/OG + Flutter master PNGs
cd ../customer_app && dart run flutter_launcher_icons
cd ../rider_app && dart run flutter_launcher_icons
cd ../vendor_app && dart run flutter_launcher_icons

Theme tokens

  • Web — web/src/app/globals.css (CSS custom properties, Tailwind v4).
  • Flutter — customer_app/lib/core/theme/, rider_app/lib/core/theme/ + vendor_app/lib/core/theme/.
  • Runtime white-label — appSettings.themePrimaryHex / themeAccentHex.

App name and ids

Edit each pubspec.yaml, android/app/build.gradle.kts (applicationId), AndroidManifest.xml (android:label), and ios/Runner/Info.plist (CFBundleDisplayName). Defaults:

AppAndroid idiOS idDisplay name
Customer
market.greencart.customer_app
market.greencart.customerApp
GreenCart
Rider
market.greencart.rider_app
market.greencart.riderApp
GreenCart Rider
Vendor
market.greencart.vendor_app
market.greencart.vendorApp
GreenCart Vendor
Note
Multi-language / RTL is not wired today — it’s on the roadmap, not a shipped feature.
13

App signing (Android and iOS)

Store builds must be signed with your own credentials. The package ships with Flutter’s default debug signing (android/app/build.gradle.kts uses signingConfigs.getByName("debug")), so set up release signing once per app before your first upload.

Android — upload keystore

  1. 01

    Generate a keystore (back it up — you cannot update the app on Play without it):

    terminal
    keytool -genkey -v -keystore ~/upload-keystore.jks \
      -keyalg RSA -keysize 2048 -validity 10000 -alias upload
  2. 02

    Create customer_app/android/key.properties (and the rider equivalent). It is already gitignored (key.properties, *.jks, *.keystore) — never commit it:

    key.properties
    storePassword=...
    keyPassword=...
    keyAlias=upload
    storeFile=/absolute/path/to/upload-keystore.jks
  3. 03
    Wire it into android/app/build.gradle.kts: load key.properties, add a signingConfigs { create("release") { ... } } block, and point buildTypes { release { signingConfig = signingConfigs.getByName("release") } } at it (replacing the current debug reference).
  4. 04

    Build the signed bundle and upload build/app/outputs/bundle/release/app-release.aab to the Play Console:

    terminal
    flutter build appbundle --release --dart-define-from-file=dart_defines.json

iOS — certificates and provisioning

  1. 01
    Enroll in the Apple Developer Program.
  2. 02
    In App Store Connect, register each App ID / bundle id (market.greencart.customerApp, market.greencart.riderApp) and create the app records.
  3. 03
    Open ios/Runner.xcworkspace in Xcode → Signing & Capabilities → pick your Team and enable Automatically manage signing (Xcode provisions the signing certificate + profile). Add Push Notifications + Background Modes here if you use FCM.
  4. 04

    Archive and upload via Xcode → Organizer (or Transporter):

    terminal
    flutter build ipa --release --dart-define-from-file=dart_defines.json
Warning
Keep signing secrets out of git. The Android keystore, key.properties, and any iOS .p12 / .mobileprovision files must never be committed. Store them in a password manager — losing the Android upload key means you can no longer update that app.
14

Production checklist

  1. 01
    Branding: edit brand/*.svg npm run gen:brand dart run flutter_launcher_icons in each Flutter app.
  2. 02
    Theme tokens: web/src/app/globals.css + the three Flutter apps’ lib/core/theme/.
  3. 03
    App names + ids in the Flutter pubspecs + native config.
  4. 04
    Provision Postgres (Neon recommended).
  5. 05
    cd web && npm install, then npm run db:migrate against the unpooled URL. No seed step — create your first account via the app, promote to admin in db:studio.
  6. 06
    Set required env (DATABASE_URL, DATABASE_URL_UNPOOLED, JWT_ACCESS_SECRET, JWT_REFRESH_SECRET, CRON_SECRET) + any optional integrations.
  7. 07
    Vercel → import repo → Root Directory = web → add env → deploy. The two cron jobs in web/vercel.json run automatically (CRON_SECRET).
  8. 08
    Stripe Dashboard → add webhook → paste STRIPE_WEBHOOK_SECRET. PayPal → set PAYPAL_* + return/cancel URLs.
  9. 09
    R2 → bucket + token → R2_* + NEXT_PUBLIC_R2_PUBLIC_BASE_URL (must be build-available for next/image).
  10. 10
    Firebase → service-account JSON → FCM_SERVICE_ACCOUNT; flutterfire configure in each app. iOS: enable Push + Background Modes in Xcode.
  11. 11
    Maps keySecrets.xcconfig (iOS) + local.properties (Android) + dart_defines.json for each app.
  12. 12
    Set up release signing for each app — Android upload keystore + key.properties, iOS Team + provisioning (see App signing).
  13. 13
    Build Flutter releases with --dart-define-from-file=dart_defines.json: iOS flutter build ipa --release (upload via Xcode Organizer); Android flutter build appbundle --release (Play Console).
  14. 14
    Promote your admin: in db:studio, set the user row’s role = 'admin'.
15

Changelog

Every version published so far. Updates are free for the life of the item.

v1.0.0 · Jun 2026
Initial release.

Version 1.1.0 · 2026-08-12

  • New: vendor Flutter app (vendor_app/) — dashboard with a 14-day sales sparkline, orders with server-driven status transitions, products with inline stock/publish toggles and image upload, earnings + payout ledger, reviews, notifications, store settings, and an application-pending state.
  • Backed by a new /api/vendor/* REST surface (15 endpoints).
  • Hardened the vendor tenant-isolation and error contract: scoped writes now refuse instead of silently no-opping, and validation / ownership / server faults map to distinct status codes.
  • Backend suite 157 → 202 tests.

Version 1.0.0 · 2026-06-16

  • Initial release — customer app, rider app, storefront + vendor portal + admin panel + backend; multi-vendor order split + commission ledger + payouts; subscription boxes; provenance; Stripe + PayPal + COD with real refunds; 2 AI features; live tracking via polling.
16

Support and licensing

6 months of Item Support is bundled per the CodeCanyon standard. You supply your own Postgres / Stripe / PayPal / Firebase / R2 accounts — we provide the setup walkthroughs, not the accounts or the hosting.

Live demo: greencart.devsnack.dev

Warning
Third-party service costs — please read: This item is sold as source code only. It integrates optional third-party services that you connect using your own accounts, and the buyer is solely responsible for any and all costs, fees, or charges incurred by these third-party services — including OpenAI, Gemini (Google AI), Stripe, PayPal, Google Maps, and Firebase (as well as Cloudflare R2 and your Postgres/hosting provider). These may include API, usage, transaction, subscription, and hosting fees, and are not included in and are entirely separate from the one-time purchase price of this item. This item does not provide, cover, or reimburse any third-party subscription, API credits, or processing fees.

Sold under the Envato Regular & Extended License.

What support covers

  • Six months of support from purchase, extendable at checkout
  • Support covers bugs in the template and questions about how it is put together
  • It does not cover custom feature work, third-party API changes or store review outcomes
  • The Regular licence covers one free end product. Charging users for the app itself needs the Extended licence