DEV Community

Tochukwu Nwosa
Tochukwu Nwosa

Posted on • Edited on

I'm building a SaaS for Nigerian traders. Here's what broke me.

I started building MyTreda this month. Alone. Me and Claude Code.

MyTreda is a free inventory and debt management app for Nigerian traders — the kiosk owner, the one-shop guy, the woman selling at Balogun Market who's been tracking her stock in an exercise book for 15 years. That's my user. Not a startup founder. Not a tech bro. Someone who just needs to know what they have, who owes them money, and whether they made profit today.

I'm a frontend developer learning backend. NestJS, MongoDB, TypeScript. And I have to say — the tutorials will teach you how to build. They won't teach you what to build for.

Here's what I mean.


The monorepo broke me first

Before I could write a single line of real business logic, I spent what felt like forever just trying to set up the project structure. Monorepo, NestJS, MongoDB, shared types across packages.

Every tutorial assumes you already know the other thing. NestJS tutorials assume you know monorepos. Monorepo tutorials assume you know NestJS. MongoDB integration tutorials assume both. I was new to all of it.

The shared types were the worst part. You want your frontend and backend to speak the same language — same enums, same interfaces. In theory, clean. In practice, I was getting circular dependency errors I didn't understand, module resolution issues that made no sense, and TypeScript screaming at me for reasons I couldn't explain.

I'm not going to pretend I solved it elegantly. I broke it, fixed it, broke it again, Googled the same error four different ways, and eventually — it worked. I don't know exactly what made it click. That's just the honest version of the story.


WhatsApp isn't a feature. It's infrastructure.

When I was designing the registration flow, my instinct (from tutorials) was: email + password, maybe phone number as optional.

Then I thought about my actual user. The woman at Balogun. How does she contact customers who owe her money? WhatsApp. How does her supplier send the new price list? WhatsApp. How does she confirm delivery? WhatsApp.

Email is almost irrelevant. WhatsApp is the business phone line, the invoicing system, the customer relationship tool — all in one.

So I made WhatsApp number a core registration field. Not optional settings. Not "add later." Right there during onboarding.

@IsString()
@Matches(/^(\+234|0)[789]\d{9}$/, {
  message: 'Invalid Nigerian phone number format (e.g., +2348012345678 or 08012345678)',
})
whatsappNumber?: string;
Enter fullscreen mode Exit fullscreen mode

Nigerian numbers come in two formats — +2348012345678 or 08012345678. The regex handles both. Small thing. But if I'd copied a Western tutorial's phone validation, it would have rejected half my users at the door.


"Retail" is not a business type

Most SaaS apps let you pick: Retail. Services. E-commerce.

That's useless to me.

The guy selling motor parts in Ladipo Market has completely different inventory needs from the cosmetics seller in Balogun. Motor parts guy needs car model, part number, compatibility. Cosmetics girl needs shades, expiry dates, batch tracking. "Retail" covers both and helps neither.

So I built six specific business types:

export enum BusinessType {
  COSMETICS = "cosmetics",
  MOTOR_PARTS = "motorParts",
  BUILDING_MATERIALS = "buildingMaterials",
  FASHION = "fashion",
  ELECTRONICS = "electronics",
  FOODSTUFF = "foodstuff"
}
Enter fullscreen mode Exit fullscreen mode

Cosmetics, Motor Parts, Building Materials, Fashion, Electronics, Foodstuff. These are the six most common business types you'll see in Lagos markets. Not arbitrary. I walked through this in my head market by market.

The plan is that when you pick your business type, the product form adapts — Motor Parts gets part number and compatible car models, Cosmetics gets shade and expiry date. Not there yet. But the foundation is set.


Nigerian internet will humble you

Standard MongoDB setup from every tutorial:

MongooseModule.forRoot(uri)
Enter fullscreen mode Exit fullscreen mode

That's it. Connect and go.

Except Nigerian internet is... unpredictable. Even in Lagos. You'll get a 2-second drop in the middle of a transaction and suddenly your app can't talk to your database and you have no idea why.

So I added retry logic:

retryAttempts: 3,
retryDelay: 1000,
Enter fullscreen mode Exit fullscreen mode

And connection event logging:

connection.on('disconnected', () => {
  console.warn('[MongoDB] Disconnected');
});
connection.on('error', (error: Error) => {
  console.error('[MongoDB] Connection error:', error.message);
});
Enter fullscreen mode Exit fullscreen mode

When a user messages me "app not working," I want to know — was it a connection drop? A retry that failed? Did it recover? Without this, I'm debugging blind.

Performance optimization is a luxury. Connection resilience is a requirement.


Error messages should not require a CS degree

MongoDB throws this when there's a duplicate email:

E11000 duplicate key error collection: mytreda.users index: email_1 dup key: { email: "test@test.com" }
Enter fullscreen mode Exit fullscreen mode

My users are traders. Some of them don't own a laptop. That error message might as well be in Latin.

So I catch it and translate it:

private handleDuplicateKeyError(exception: any) {
  const field = Object.keys(exception.keyPattern || {})[0];
  const value = (exception.keyValue || {})[field];
  const message = field
    ? `${this.formatFieldName(field)} '${value}' already exists`
    : 'Duplicate entry detected';
  return { status: HttpStatus.CONFLICT, message };
}
Enter fullscreen mode Exit fullscreen mode

Now they see: "Email 'test@test.com' already exists."

Clear. Actionable. No jargon. That's the standard I hold every error message to.


One thing that frustrates me about building from Lagos

We give 100% to everything we build here. The Nigerian developer community is genuinely talented — I see it every day on Twitter, on GitHub, in communities. But because of where we're from, there's this ceiling. The country's reputation outside makes it feel like we have to work twice as hard just to be taken seriously.

I'm not building MyTreda to prove anything to anyone outside Nigeria. I'm building it because the woman at Balogun Market deserves software that was actually built for her — not adapted from something built for a Shopify merchant in Toronto.

That's enough reason for me.


Where MyTreda is right now

Auth is done. Products module is next.

The app is live and free at mytreda.com — works offline, runs on any Android or iPhone, no app download needed. If you know a Nigerian trader who's still using exercise books or scattered WhatsApp messages to track their business, send them the link.

I'm building this in public. If you're building something for African markets and you've hit walls the tutorials don't cover — I'd genuinely love to hear about it in the comments.


Find me here:

Top comments (0)