DEV Community

Ian Ochieng
Ian Ochieng

Posted on

Building SemaKazi Part 1: Shipping a Backend the Way Real Teams Do It

Kenya has one of the youngest populations in the world, and most of that workforce works in the informal sector — electricians, carpenters, mechanics, tailors, the people we call "fundis." The problem is simple: there's no digital way for a skilled fundi to prove they're actually skilled. Clients hire based on word-of-mouth alone, which caps good workers to their existing network and lets anyone claim expertise they don't have.

That's the problem SemaKazi is solving — a platform where fundis build a verifiable reputation through proof-of-work uploads, client ratings, and peer-endorsed skill badges.

Today was Phase 1: the backend foundation. Here's what actually went into it.

The stack

Node.js + Express, SQLite (via better-sqlite3) for the database, JWT + bcrypt for auth. Nothing exotic — the goal was a clean, working API, not a tech showcase.

What got built

  • Data models: users (fundis and clients), proof-of-work entries, reviews, and skill badges — with foreign keys and indexes where the queries actually need them
  • Auth: register/login with hashed passwords, JWT middleware to protect routes, and an ownership check so users can only edit their own data
  • Core endpoints: profile search/view, proof-of-work CRUD, review submission, and badge endorsements

Doing it like a real project, not a script

The part I actually wanted to practice wasn't the code — it was the workflow around it:

  • A proper README and PRD before any code, with an explicit out-of-scope section (no payments, no in-app chat, no admin dashboard in this version — deliberately)
  • One feature branch per unit of work, merged via pull requests with real descriptions (summary, why, testing notes, known gaps)
  • GitHub Issues tied to a project board, closed out as each feature merged
  • A tagged release (v0.1.0-phase1) marking the milestone on main

The bug that actually taught me something

Everything worked in my Codespace. Then I pulled the same repo onto my local machine and got:

Error: Cannot find module './routes/profiles'
Enter fullscreen mode Exit fullscreen mode

Turned out one route file was named profile.js (singular) while the code that required it expected profiles.js (plural). It had worked by accident in one environment and failed correctly in another — a good reminder that "it runs on my machine" isn't the same as "it's actually correct." Renamed the file, committed the fix, moved on.

What's next

Phase 2 is the frontend — wiring up the UI to these endpoints and adding real media upload for proof-of-work. Phase 1 is tagged, merged, and done.


Following along? The repo's public — feel free to poke through the commit history to see how the branches came together.

Top comments (0)