The Challenge No One Warns You About
When you hear "World Bank project," you imagine well-funded teams with clear specifications. The reality of KISIP II was different. We needed to deploy a field data platform across seven of Nairobi's most densely populated informal settlements — Kibera, Mathare, Mukuru, Kayole, Dandora, Korogocho, and Kariobangi — with workers who had never used enterprise software.
The existing process was entirely paper-based. Field supervisors carried clipboards. Payment reconciliation took weeks. Nobody could answer the question: "How many tasks were completed today?"
Architecture Decisions That Mattered
Why a PWA, Not a Native App
The workers carried budget Android devices with intermittent connectivity. A native app would have meant Play Store deployment cycles, device fragmentation testing, and 50MB+ downloads over expensive mobile data. A Progressive Web App gave us:
- Offline-first architecture with service workers caching task queues
- Instant deployment — push updates hit all 282 workers simultaneously
- 2MB initial payload vs. 50MB+ for a comparable native app
- No app store gatekeeping — critical when you need to deploy on government timelines
The 76-Table PostgreSQL Schema
The schema wasn't complex because we wanted it to be. It was complex because the real world is complex. A single "task" — say, painting a road marking in Kibera — touches:
- Worker assignment (who was assigned, when, by which supervisor)
- Geospatial data (GPS coordinates, which settlement polygon, which ward)
- Verification chain (field photo, supervisor approval, QA check)
- Payment linkage (which payment cycle, M-Pesa disbursement status)
- Audit trail (every state change timestamped for World Bank compliance)
We used PostGIS extensions for spatial queries — finding all tasks within a settlement boundary, calculating coverage percentages, identifying gaps in surveyed areas.
ODK Central Integration
Field data collection ran through ODK Central with custom XLSForms. The key insight was treating ODK as a data collection layer, not a database. Submissions flowed through a webhook pipeline:
- Worker submits form on ODK Collect (works offline)
- ODK Central receives and validates
- Our middleware transforms and enriches with geospatial context
- PostgreSQL stores the canonical record
- Real-time dashboard updates via WebSocket
Scaling to 50,000+ Daily API Requests
When 282 workers start their shift at 7 AM, the system sees a traffic spike that would embarrass most startups. Every worker's device syncs cached offline data, pulls updated task assignments, and begins streaming GPS pings.
We handled this with:
- Connection pooling via PgBouncer — 20 persistent connections serving hundreds of concurrent users
- Materialized views for dashboard aggregations — pre-computed daily/weekly/monthly rollups refreshed every 15 minutes
- CDN-cached static assets — the PWA shell loads from cache while API calls fetch fresh data
- Request batching — the client queues individual task updates and sends them as a single batch POST every 30 seconds
The Payment Problem
Paying 282 workers accurately and on time through M-Pesa was the feature that made or broke trust. In previous projects, workers waited 2-3 weeks for manual reconciliation. We built an automated stipend engine:
- Worker completes verified tasks throughout the payment period
- System calculates earnings based on task type and completion quality
- Supervisor reviews and approves batch payment
- M-Pesa Business-to-Customer (B2C) API disburses funds
- Worker receives SMS confirmation within minutes of approval
This reduced payment cycles from weeks to hours and eliminated the manual spreadsheet reconciliation that previously consumed 3 full-time staff.
What I'd Do Differently
More aggressive caching. We played it safe with 15-minute materialized view refreshes. In hindsight, 5-minute refreshes with targeted invalidation would have given supervisors near-real-time dashboards without significant database load.
Better onboarding flows. We underestimated how much hand-holding field workers would need. The first week saw support tickets about basic navigation. Building an interactive tutorial into the PWA would have saved dozens of in-person training hours.
API versioning from day one. We shipped v1 and assumed we'd iterate. We did iterate — and coordinating breaking changes across 282 devices taught us that API versioning isn't optional infrastructure, it's survival infrastructure.
The Numbers
After 18 months in production:
- 1.7 million weekly tasks processed at peak
- 50,000+ daily API requests sustained
- 282 youth workers coordinated across 7 settlements
- 3 payment cycles reduced from weeks to hours
- Zero data breaches — Kenya Data Protection Act compliant throughout
The platform continues to operate today, managed by government staff trained during the handover phase. That's the real metric of success — building something that outlasts your involvement.