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
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.
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.
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 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
"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
Ubuntu as architecture: stokvel RLS policies must reflect collective ownership — members see group data, never each other's private balances
- 3
Split prompt caching: static stokvel context cached, per-member context dynamic — 70% token reduction after first message per stokvel per hour
- 4
Dispute mediation needs a hard escalation ceiling — 5 turns max before human (chairperson) intervenes; AI cannot mediate indefinitely
- 5
Deploying to Vercel jnb1 (Johannesburg) + Supabase Africa (Cape Town) puts compute and data on the continent — sub-100ms round trips for SA users
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
# 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