The Brief
A federal agency approached us with a problem that sounded simple on paper: "We want all procurement requests to go through one system." In practice, this meant unifying 14 ministries, each running different legacy workflows — some on paper, some on spreadsheets, one on a 2003-era Windows application — into a single, auditable, real-time platform.
The stakes were high. Public funds. Regulatory scrutiny. A press that would notice any failure.
Why Custom, Not Off-the-Shelf
We evaluated four COTS (Commercial Off-The-Shelf) procurement systems. Each failed on at least one critical criterion:
- Multi-tenancy with ministry-level isolation — most products treated the entire organisation as a flat hierarchy.
- Audit trail depth — government compliance required field-level change logs, not just row-level.
- Offline fallback — field procurement officers in rural states cannot rely on stable connectivity.
- Integration with existing IPPIS and GIFMIS — no vendor supported this without six-figure customisation fees.
We built from scratch.
Architecture Decisions
Multi-Tenant Postgres Schema
Each ministry gets its own Postgres schema within a shared database cluster. This gives us data isolation without the operational overhead of 14 separate databases. Cross-ministry queries (for the central dashboard) run via views with row-level security policies.
Event-Driven Audit Log
Every state change — from a procurement request being raised to a director's approval — emits an event to a dedicated audit log service. The log is append-only, signed with HMAC, and stored separately from the main application database. Tampering is detectable.
Offline-First Field Client
Ministry field officers use a PWA with IndexedDB local storage. Procurement requests are drafted offline and synced when connectivity is restored. Conflicts are resolved server-side using operational transformation — similar to how collaborative document editors work.
Role Hierarchy
We implemented RBAC with 9 distinct roles across 3 hierarchy levels: Ministry (Director, Procurement Officer, Requestor), Agency (Coordinator, Reviewer), and Central (Auditor, Finance Controller, Approver, Super Admin). Each role has a precise permission matrix stored in a configuration table, not hardcoded in application logic.
What We Got Wrong (And Fixed)
File uploads. We initially streamed files directly to S3 from the browser. This caused issues when ministry offices had slow connections — large tender documents (PDFs, sometimes 50MB+) would time out halfway. We replaced this with a resumable upload flow using TUS protocol. Uploads now survive connection drops.
Notification fatigue. Early user feedback showed that procurement officers were getting 20–30 email notifications per day. We rebuilt the notification system to use digest batching and urgency tiers. Critical items (approaching deadlines, rejected approvals) go immediately; status updates batch into a daily digest.
Session management in shared offices. Many ministry computers are shared between multiple officers on shift rotations. A 30-minute session timeout wasn't enough in some contexts, too long in others. We added device-bound sessions with explicit "sign out for next user" flows.
Results
- ₦4.2 billion in procurement value processed in the first year
- Average approval cycle time dropped from 34 days to 9 days
- Zero audit findings in the first regulatory review
- 98.7% uptime in year one
What We'd Do Differently
We'd push harder for a dedicated staging environment that mirrors production from day one. Early in the project, we tested against a scaled-down environment and missed a performance issue that only appeared at full ministry data volumes. It cost us two weeks of production debugging.
We'd also invest earlier in an internal admin panel. Support queries ("why was my request rejected?") consumed significant time because we had to query the database directly. A proper admin panel with pre-built views would have paid for itself in the first month.
Conclusion
E-government platforms are not just web applications. They are public infrastructure. Every architectural decision carries accountability: to the officers using the system daily, to the citizens whose money flows through it, and to the regulators who audit it.
Building this system taught us that simplicity in the user interface demands significant complexity underneath — and that complexity must be engineered deliberately, not accrued accidentally.
If your institution is planning a procurement or financial management system, reach out. We've learned the hard lessons already.