All Projects
Beta2025AI/ML · Community Finance · SaaS

StokvelOS

The First AI-Native Stokvel Platform — Serving 11M South Africans

AI-powered stokvel management platform digitalising South Africa's R50 billion informal savings economy. Automated contribution tracking, AI fraud detection, plain-English governance reports for committee chairs.

Serving

11M South Africans in stokvels

Market

R50B+ informal stokvel economy

Problem

95% of stokvels operate on paper

Result

AI fraud detection caught 2 discrepancies in beta

The Problem

What needed solving

R50 billion moves through SA stokvels annually — 95% managed on paper. WhatsApp messages, hand-written registers, and trust. The disputes, fraud, and financial loss that follow fall hardest on communities that can least afford it.

The Solution

How I built it

Full-stack stokvel management with automated contribution tracking, Z-score anomaly detection for fraud signals, and AI-generated plain-English governance reports after every contribution cycle. Built with Ubuntu as architecture: collective ownership in RLS policies.

Build Journey

The trigger for StokvelOS was a specific incident: a chairperson of a 20-member teachers' stokvel lost R4,200 because two members paid to an old account, records weren't reconciled, and by the time the discrepancy was found 3 months had passed. No audit trail. The core insight: a stokvel is not a bank. It's a trust community with rules. Fix the transparency, and most fraud, disputes, and misunderstandings dissolve before they become crises. The most consequential architectural decision was "Extract Once, Enforce Forever." A naive implementation would call Claude for every late payment check, every loan eligibility check, every compliance update. At scale across 30+ member stokvels paying monthly, that's thousands of unnecessary AI calls per month. Instead, Claude reads the stokvel's constitution exactly once on setup, extracts 18 structured fields (contribution_due_day, late_grace_days, late_penalty_percent, loan_eligibility_min_compliance, quorum_percent, chairperson_co_sign_above) into a typed JSONB blob stored in Supabase. All runtime enforcement runs as pure TypeScript — zero AI cost per transaction. The WhatsApp agent's prompt caching is split into two blocks: a static cached block (constitution summary, extracted rules, monthly amount, payout type — identical for all messages from the same stokvel, cache hit after the first call) and a dynamic block (per-member: name, role, compliance %, this month's status). This reduces prompt tokens by ~70% after the first message per stokvel per hour. The dispute mediation agent runs a 7-state machine: open → investigating → awaiting_complainant_proof → awaiting_respondent_proof → reviewing → resolved | escalated. Auto-resolves if records can settle it. If not, enters conversation mode with a hard escalation at 5 turns — chairperson notified via WhatsApp. The system prompt instruction: "You are not on anyone's side. You protect the community's trust and harmony."

Extract Once Enforce Forever — constitution compliance architecture
typescript
// "Extract Once, Enforce Forever" — constitution parsing architecture
// Claude extracts 18 fields once on setup; all runtime enforcement is pure TS (free)

// Step 1: ONE Claude call per stokvel (on setup or constitution update)
const extracted = await anthropic.messages.create({
  model: 'claude-sonnet-4-6',
  max_tokens: 400,
  messages: [{
    role: 'user',
    content: `Extract ONLY explicitly stated rules. Return JSON. Do not infer. Null for unstated fields.

${constitutionText}`,
  }],
});

const rules = mergeWithDefaults(JSON.parse(extracted.content[0].text));
// Store extracted rules — this is now the source of truth for all enforcement
await supabase.from('stokvels')
  .update({ extracted_rules: rules, rules_extracted_at: new Date() })
  .eq('id', stokvelId);

// Step 2: All runtime enforcement — pure TypeScript, zero AI cost
export function checkLatePaymentPenalty(
  contribution: Contribution,
  rules: ExtractedRules
): number {
  const daysLate = differenceInDays(new Date(), parseISO(contribution.due_date));
  if (daysLate <= (rules.late_grace_days ?? 7)) return 0;
  return Math.round(contribution.amount * ((rules.late_penalty_percent ?? 10) / 100));
}

export function checkLoanEligibility(
  member: StokvelMember,
  rules: ExtractedRules
): { eligible: boolean; reason: string } {
  const compliance = member.compliance_rate ?? 0;
  const required = rules.loan_eligibility_min_compliance ?? 0.8;
  if (compliance < required) {
    return { eligible: false, reason: `Compliance ${Math.round(compliance*100)}% below required ${Math.round(required*100)}%` };
  }
  return { eligible: true, reason: 'Meets constitution requirements' };
}

What This Taught Me

  1. 1

    "Extract Once, Enforce Forever": use AI for rule extraction, pure code for rule enforcement — the constitution is read once, TS enforces it every transaction

  2. 2

    Ubuntu as architecture: stokvel RLS policies must reflect collective ownership — members see group data, never each other's private balances

  3. 3

    Split prompt caching: static stokvel context cached, per-member context dynamic — 70% token reduction after first message per stokvel per hour

  4. 4

    Dispute mediation needs a hard escalation ceiling — 5 turns max before human (chairperson) intervenes; AI cannot mediate indefinitely

  5. 5

    Deploying to Vercel jnb1 (Johannesburg) + Supabase Africa (Cape Town) puts compute and data on the continent — sub-100ms round trips for SA users

Tech Stack & Decision Rationale
01

Next.js

App Router for SSR + fast mobile loads

02

TypeScript

Type safety for financial data

03

Supabase

RLS: members see group data, not each other's private balances

04

Claude API

Plain-English AI governance reports for committee chairs

05

PayFast

ZAR contribution processing

README.md — stokvel-os
📄 README.md
# StokvelOS
> The First AI-Native Stokvel Platform — Serving 11M South Africans

## Project Context
**Category:** AI/ML · Community Finance · SaaS
**Status:** Beta · 2025
**Author:** Nandawula Regine Kabali-Kagwa — East London, South Africa
**Company:** Mirembe Muse (Pty) Ltd · Reg: 2026-005658

## Stack
```
Next.js                        # App Router for SSR + fast mobile loads
TypeScript                     # Type safety for financial data
Supabase                       # RLS: members see group data, not each other's private balances
Claude API                     # Plain-English AI governance reports for committee chairs
PayFast                        # ZAR contribution processing
```

## Architecture Notes
- All data mutations validated server-side via Next.js API routes
- Row-Level Security enforced at database level (Supabase)
- Mobile-first, PWA-ready, offline-tolerant where connectivity is unreliable
- PayFast integration for ZAR-native payments (no USD conversion)
- SEO-optimised: metadata, JSON-LD, canonical URLs, sitemap
- POPIA compliant — data minimisation + user consent by design

## Environment Variables
```env
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=
ANTHROPIC_API_KEY=
NEXT_PUBLIC_PAYFAST_MERCHANT_ID=
NEXT_PUBLIC_PAYFAST_MERCHANT_KEY=
PAYFAST_PASSPHRASE=
RESEND_API_KEY=
```

## Links
- Live:   Coming soon — domain propagating
- GitHub: Private repository
- Portfolio: https://creativelynanda.co.za/projects/stokvel-os

---
Built from East London, South Africa · Nine months · Zero to production

Interested in similar work?

Let's discuss how I can build something like this for your business.

Let's Talk