# BENMP Partner Platform

> The partner management platform an international organization runs on: admins at 117 hubs upload, clean, and manage partner records across 30+ countries.

Software Engineer (part-time) · Jul 2026 to now

Scale: 16,000+ partners · 117 hubs

## Results

- 16,000+ partners on the platform
- 30+ countries
- 117 regional hubs using it
- 26,000+ legacy records archived with zero loss

## The problem

BENMP's partners span 30+ countries, but their records lived in spreadsheets kept by hub leaders, with inconsistent names, phone formats, and church lists. The office could not reliably tell who had given, reach partners, or trust the legacy data.

## What I built

- The hub portal and a four-step Excel/CSV import wizard: pick columns so headers never matter, fix flagged rows in place, and keep an audit trail of the original file.
- Validation that runs identically in the browser and on the server: branch matching against each hub's approved list, country-aware WhatsApp parsing, and a name-and-number identity rule so nobody is overwritten on a name alone.
- A data-driven region model (region, hub, branch, partner): adding a country is a seed entry plus an idempotent SQL migration, with no deploy.
- Phone-based payment reconciliation, WhatsApp and SMS sending behind swappable provider adapters with preview and explicit confirm, and a read-only assistant where code computes every figure and the model only explains it.

## The hard part

Getting clean data from more than a hundred non-technical admins who type phone numbers the way people in their own country do. The first Malawi upload failed row after row because numbers were read as Ghanaian, so a local number could silently become a wrong +233 number. I made the hub's country drive phone parsing, accepted every shape Excel produces (stripped '+', dropped leading 0), and ran the exact same checks in the browser preview and on save, so admins fix rows in place and nothing invalid is ever written.

## How it fits together

- Hub spreadsheets -> Import wizard (upload)
- Import wizard -> Shared validation (check rows)
- Shared validation -> Partner database (clean rows)
- Partner database -> Office console (statements)
- Office console -> Messaging adapters (send)
- Partner database -> Read-only assistant (figures)

Parts David built: Import wizard, Shared validation, Office console, Messaging adapters, Read-only assistant.

Invariant: one set of rules decides what is valid, so the preview an admin sees is exactly what gets saved.

## Decisions

- Regions as data, not code: a new country is a seed entry and an idempotent SQL migration, so the platform grew from Ghana to 30+ countries without a deploy per country.
- A partner is matched on name and number together, never name alone, so two people with the same name can't overwrite each other.
- Sending goes through swappable provider adapters with a preview, an explicit confirm, and an allowlist, so switching WhatsApp providers never changes how a send is approved.

Tech: Next.js, TypeScript, Supabase, PostgreSQL. Links: [code](https://github.com/Alienware2000/benmp-prm)

Page: https://davidantwi.vercel.app/work/benmp-partner-platform
