Skip to content
Back

CRM Loja

In productionRole: Lead developerFlutterRiverpodSupabaseKotlin

Flutter sales and pre-billing app for Grupo Coagro's sales team: customers, catalog, quotes, orders and targets, reading from the Winthor ERP — in production on Android and web.

CRM Loja

// Overview

Coagro's field CRM. The farm-supply seller looks up the customer, purchase history, credit limit and available products, builds quotes and orders, and follows pre-billing and targets — on the phone, at the farm, or in the store's browser.

// The challenge

The ERP records the order, not the conversation that leads to it: visit, crop diagnosis, proposal, negotiation. That lived in the seller's head and notebook — and went on vacation with them. The app also had to work on farm 4G, be updated across a fleet of devices with no app store, and could not duplicate data the Winthor ERP already owns.

// Constraints

Work on farm 4G, be updated across a fleet of devices with no app store, and never duplicate data the Winthor ERP already owns.

// Engineering decisions

One source of truth per record

Choice
what is already true in the ERP is read from Winthor; only what has not become an order yet lives in Supabase.
Why
the order is owned by the ERP — a copy in the app would drift from it.
Trade-off
two data sources for the app to reconcile, instead of a single database.

Updates without a store

Choice
a native Kotlin channel that downloads the APK in the background and checks its SHA-256 before installing.
Why
the company's device fleet does not go through an app store.
Trade-off
native Android code to maintain alongside Flutter.

// The solution

Flutter with Riverpod and feature-first Clean Architecture (domain, data, presentation), with layer rules checked by a script in CI. What is already true in the ERP is read from Winthor; what has not become an order yet lives in Supabase, with RLS, triggers and RPCs in Postgres. APK updates are handled by the app itself through a native Kotlin channel, with background download and SHA-256 verification; chat notifications arrive with the app closed, without Firebase, through an Android foreground service.

// Architecture

Architecture diagram of CRM Loja. The Flutter app (Android and web), with Riverpod and feature-first Clean Architecture split into domain, data and presentation, talks to two sources: it reads from the Winthor ERP what is already true there, and writes to Supabase (Postgres with RLS, triggers and RPCs) what has not become an order yet. On Android, a native Kotlin channel downloads the new APK in the background and checks its SHA-256, and a foreground service delivers chat notifications without Firebase. In CI, a script checks the layer rules.

My role

Lead developer (about 95% of commits): architecture, app, database (190+ migrations), native Android code, tests and release pipeline. A Grupo Coagro system, built in partnership with NWERP.

Tech stack

FlutterDartRiverpodgo_routerSupabasePostgreSQLKotlinGitHub Actions

// Screens

Home screen: today's sales, the day's recommended action and the monthly target
Placing an order: product table with promotions, stock per batch and branch
A product blocked for end consumers, out of stock and with several batches
Side menu: customers, products, chat, orders, management, prescriptions and approvals
Sales Portal login

// Outcome and evidence

In production with the sales team, on Android and web, with 260+ versions shipped through Release Please and 800+ test files (9,000+ cases) — the full suite runs nightly in CI. In 2026 it gained sales gamification (league, missions, achievements and rewards, which never blocks a sale) and a chat with native Kotlin push, with its own Supabase Realtime client and replies straight from the notification.

versions shipped
260+
releases via Release Please
test files
800+
the full suite runs nightly in CI
Supabase migrations
190+
of the commits
~95%

Looking for this kind of work?