Kennedy Wambua
← All work Case study · Radi Digital · 2024–now

Tija eProcurement

Procurement software for organisations. A purchase moves from request through approvals to an order, delivery, invoice and payment, checked at every step against budgets and the organisation's own rules.

Role
Software engineer, one of three core engineers
Stack
NestJS, PostgreSQL, Prisma, Redis, Next.js
Team
Radi Digital
Links
tija360.com ↗
Tija settings page for vendor score weights in a demo organisation
Tija's buyer app, vendor scoring settings (demo organisation)
The problem

Organisations buy through long chains of people. Someone requests, managers approve, finance checks the budget, a vendor delivers and someone pays. Every organisation draws that chain differently.

Get it wrong and money is spent without approval, or the same budget is promised to two requests at once.

My part

Tija is a team product. I worked mostly on the backend: the approval engine, budgets, licensing, and the first version of the Nia assistant. Teammates built much of the rest, including the current version of Nia.

What I built

Problems I solved, and how

  1. Approval flows each organisation can design

    Problem
    Hard-coded approval chains don't fit real organisations. One needs two managers for anything over a threshold, another routes by department, and both change their minds.
    Approach
    I replaced an ad hoc rules evaluator with json-rules-engine, tried Temporal for orchestration, and then built a lighter node-based engine of our own. Organisations build flows from trigger, condition, approval, notification and end steps, a flow only takes effect once it is published, and each document type plugs in through a strategy class. It runs across eight kinds of records.
  2. Not promising the same budget twice

    Problem
    Two requests could each see enough money left on a budget line, get approved, and together overspend it.
    Approach
    Each budget line keeps a separate reserved balance. Submitting a request reserves the money, approval turns the reservation into spending, and rejecting or cancelling gives it back. Every movement writes a history row, so finance can see where the money went. The team has since hardened this further.
  3. Licensing that bends instead of breaking

    Problem
    The product needed plan-based user limits and trial licences, without a bad order taking someone's account down.
    Approach
    I created the licensing module with plan-based user limits and a cap on trial licences. An oversized trial order is trimmed to the cap and returns a warning instead of failing.
  4. AINia, version one

    Problem
    Let people get answers like "which orders are waiting on me?" without learning the reports.
    Approach
    Users ask in plain English and an LLM, through LangChain, writes SQL against an allowlisted set of tables. I also built inventory insights with Google Gemini, and stock-transfer suggestions that rank stores by travel distance. A teammate has since rebuilt Nia as a fuller agent.

What I took away: in enterprise software the rules belong to the customer. Building an engine they configure meant new approval rules became configuration, not code changes.

More work
← Back to all work Get in touch →