Last quarter, we shipped a client portal for a Lagos-based integrated marketing agency. The brief was clear: replace a patchwork of WhatsApp messages, emailed invoices, and manual project updates with a single system that clients could log into to see everything. Twelve weeks from brief to production. Here's what we built, what surprised us, and what we'd do differently.
The Architecture Decision
The first decision was whether to extend an existing tool like HubSpot or build custom. The agency had tried HubSpot and Zoho before — both had been abandoned within six months because the configuration complexity required to match their actual workflow was prohibitive for a team without dedicated ops staff. Custom was the right call.
We settled on a Next.js App Router frontend with a Node.js/Express API layer, PostgreSQL for the primary database, and Redis for session management and caching invoice states. The client portal itself runs on a separate subdomain from the agency's marketing site, with shared authentication via JWT tokens.
The Paystack Integration
Paystack's API is well-documented, but there are several integration patterns that aren't obvious from the docs alone. The most important one: Paystack's webhook system is the source of truth for payment states, not the redirect callback. We learned this the hard way in staging when a test payment succeeded on the Paystack side but the user's connection dropped before the redirect completed, leaving the invoice in an indeterminate state.
The correct pattern is to ignore the payment state in the redirect entirely and only update your database when you receive and verify the charge.success webhook event. This means payment confirmation can take a few seconds to propagate, which requires a thoughtful loading state in the UI — but it eliminates the race condition between user redirect and webhook delivery that causes reconciliation headaches.
We also implemented Paystack's recurring charges (subscriptions) for clients on monthly retainer arrangements. The subscription API is more complex than the single-charge API and has specific requirements around how you handle card declines, retries, and cancellations. Mapping those states to the agency's invoice workflow required about a week of careful implementation and testing.
Project Timeline Visualization
The project tracking component was the most design-intensive part of the build. The agency's projects have multiple phases (strategy, production, revision, delivery), multiple deliverables per phase, and multiple stakeholders with different visibility requirements — the client sees a simplified view, the project manager sees full detail, and the finance team sees a different subset focused on billing milestones.
We built a role-based data model where the same project record renders differently based on the authenticated user's role. This eliminated the need for separate data stores while allowing the UI to present each stakeholder with exactly the information they need without the noise of everything else.
What We'd Do Differently
The notification system was underspecified in the initial brief and became the most expensive part of the project. Email notifications, SMS via Termii (the dominant SMS API in Nigeria), and in-portal notifications all have different delivery requirements and different failure modes. We built them sequentially rather than in parallel, which added time. If we scoped this project again, we'd treat the notification layer as a first-class system component with its own requirements document rather than a feature that gets added along the way.
We'd also start the NDPR compliance documentation earlier. Our legal review at the end of the project surfaced requirements around data retention policies and cookie consent that required retroactive changes to the user registration flow. Two weeks of implementation time that would have been a few days if we'd addressed it in the design phase.
The Result
The portal launched with 23 client accounts migrated from the previous manual process. In the first month, the agency logged 340 invoice views, processed 18 payments totalling ₦4.2 million, and had zero support requests about payment status — compared to an average of 12 per month via WhatsApp previously. The ROI was immediate and measurable.