Back to BlogCase Study

When the MVP wasn't the product: a rapid-app platform for government departments

We were hired to ship a citizen bill-payment MVP. We delivered it in 45 days flat — and underneath it, built the rapid-application platform that's now waiting to host whatever government department comes next. This is the story of saying yes to scope expansion without losing the launch.

May 22, 202611 min read

The brief was a single product: a citizen-facing bill-payment portal. The partner had budget for an MVP, a launch deadline, and a small set of billers to support on day one. Standard government-sector engagement. We staffed it, scoped it tight, and started building.

Three weeks in, on a Tuesday, the partner's CTO asked a question that quietly rewrote the engagement: "If a different department wanted a portal like this next quarter, how long would it take?" The honest answer was 'about as long as this one'. That wasn't the answer they wanted. It also wasn't the answer we wanted. By the end of that week we'd redrawn the architecture. The bill-payment portal was no longer the product. The platform underneath it was.

The shape of the engagement

45 days

Kickoff to MVP live

13

CodeFellow team at peak

6

Platform primitives

0

Rebuilds per new department

Saying yes to scope expansion, responsibly

Mid-engagement scope expansion is usually how delivery teams get killed. The deadline doesn't move, the budget doesn't move, but suddenly the system has to do twice as much. We agreed to it on three conditions, written down on the same Tuesday:

  • The MVP ships on the original date. It must launch as a real product, not a platform demo. The MVP is the first tenant of the platform — not the platform with a portal stapled on.
  • The platform exposes primitives, not a low-code editor. We weren't going to ship a half-built version of Retool. Department teams build with us, in code, against a small surface — not in a drag-and-drop tool.
  • Escape hatches everywhere. Any department app can drop into raw Laravel for anything the platform doesn't model yet. We refused to build a prison.

Those three rules held through the rest of the engagement, through the MVP launch, and through every department app we modelled against the platform after.

What the platform actually is

Stripped of marketing, it's six things glued together with a thin Laravel surface: an identity primitive, a lookup primitive, a payment primitive, a workflow primitive, an audit primitive, and a tenant primitive. A 'department app' is a declarative composition of those, plus whatever raw Laravel the department actually needs.

// Defining a new department app — citizen bill payment.
// Same shape as every other app on the platform.

use Partner\RapidApp\Facades\App;
use Partner\RapidApp\{Identity, Lookup, Payment, Workflow, Audit};

App::register('citizen-bill-payment', [
    'tenant'    => 'utility-co',
    'identity'  => Identity::cnic()->withConsent('bill-payment-v1'),
    'lookup'    => Lookup::byConsumerNumber()->source('utility-backend'),
    'payment'   => Payment::onelink()->biller('utility-co-bills'),
    'workflow'  => Workflow::define('bill-pay')
        ->state('inquired')->on('paid')->to('settled')
        ->state('settled')->on('reconciled')->to('closed')
        ->state('*')->on('reversed')->to('refunded'),
    'audit'     => Audit::immutable()->capture(['consent', 'operator', 'txn_id']),
    'portal'    => Portal::citizen()->theme('utility-co'),
]);

// A different department app — vehicle challan portal.
// Different lookups, different biller, same primitives.

App::register('motor-vehicle-challan', [
    'tenant'    => 'province-mva',
    'identity'  => Identity::cnic()->withConsent('challan-v1'),
    'lookup'    => Lookup::byVehiclePlate()->source('mva-backend'),
    'payment'   => Payment::onelink()->biller('province-mva-challan'),
    'workflow'  => Workflow::define('challan-pay')
        ->state('issued')->on('paid')->to('cleared'),
    'audit'     => Audit::immutable()->capture(['consent', 'plate', 'txn_id']),
    'portal'    => Portal::citizen()->theme('province-mva'),
]);

That's not pseudocode. That's roughly the shape of what a department gives us when they want a new app. Identity, lookup, payment, workflow, audit, portal — composed in a single registration. The platform handles the rest: tenant isolation, queue and database boundaries, secret leasing for downstream rails (1LINK, NADRA Verisys, department backends), CI/CD, audit dashboards, and the citizen-facing portal scaffolding.

What the platform deliberately does not try to be: a workflow GUI, a form builder, a no-code DSL, or a runtime sandbox. Every department app is plain Laravel underneath. The platform is leverage, not jail.

What a department gets on day one

Six primitives, infinite apps

Each new department onboarding starts with the same six pieces — composed, configured, and audit-ready before the first sprint ends.

F

Identity

Citizen identity verification with consent capture, data-minimisation by default, and pluggable providers — NADRA Verisys today, more rails as they're approved.

Lookup

Department-backend lookups (consumer number, vehicle plate, NTN, case ID) with cache, retry, and circuit-breaker baked in. Each department wires their backend; the platform handles the rest.

B

Payment

1LINK 1BILL out of the box — the same battle-tested package from our switch-integration practice. Add new payment rails as adapters; existing apps inherit them automatically.

Workflow

A declarative state machine: states, transitions, role gates, retryable side-effects, and an audit-grade transition log. Boring on purpose; survives audit on purpose.

F

Audit

Immutable, append-only audit log scoped per tenant. Each app declares what it captures — never what it leaks. Defaults are paranoid; opt-out is conscious.

B

Tenant

Per-department isolation at the database, queue, secret, and dashboard layer. Adding a tenant is configuration. Cross-tenant access requires a signed reason. No accidents.

Building rapid app dev without building a low-code prison

The graveyard of internal platforms is full of well-intentioned low-code tools that solve eighty percent of the problem and then become a wall the team can't climb. We were terrified of that outcome. Three architectural decisions kept us out of the trap:

  • Every primitive is Laravel underneath. The Identity facade is a Laravel package. The Workflow facade is a Laravel package. A department engineer who hits the limits of the platform reads the source — and writes a Laravel controller. No new runtime to learn.
  • Configuration is PHP, not YAML. App definitions live in real code, version-controlled, type-checked, refactorable. We resisted the temptation to invent a domain-specific language. There's an editor that already understands the one we picked.
  • Multi-tenancy is a primitive, not a feature flag. Database, queue, secret, audit — each tenant gets its own. Retrofitting tenant isolation onto a single-tenant codebase is the single largest cause of platform rewrites we've ever seen. We refused to spend that bill later.
Lessons

Five things the MVP-to-platform pivot taught us

Most platform engagements end in regret. This one didn’t — and the reasons are unglamorous on purpose.

C

Ship the MVP first, the platform second

We never let the platform delay the bill-payment launch. The MVP shipped on the original date as a real product. The platform was extracted from it, not bolted onto it.

D

Escape hatches are the platform

Every department app can drop into raw Laravel for anything the platform doesn't model. That single decision is the difference between adoption and revolt.

B

Multi-tenancy is non-negotiable on day one

Tenant isolation cannot be retrofitted. Bake it into the database schema, the queue topology, the secret store, and the audit log from the first commit, or you'll rebuild later.

Don’t invent a DSL

App definitions are PHP. Editors understand PHP. Type-checkers understand PHP. Engineers understand PHP. Every minute spent designing a custom syntax is a minute not spent on the actual primitives.

A platform team is a real team

At peak we had thirteen people — engineering, design, mobile, PM, architecture. Platform work eats people in ways product work doesn’t; staffing it like a product team and not a side-project is what made it real.

What it cost, what it left behind

The bill-payment MVP went live 45 days after kickoff. That alone was the win the partner had hired us for. The thing the partner — and we — left the engagement with was bigger: a working rapid-application platform, hardened against the six primitives, ready to host the next government department app at a fraction of the MVP cost.

We don't talk publicly about which partner or which department. We do talk about the shape of the work — because we'd build this same platform for any government that needs to ship citizen-facing apps faster than the bespoke-build cycle allows. Identity, lookup, payment, workflow, audit, tenant. The next launch is configuration, not a project.

What the team said

From the people who shipped it

The hardest part wasn't the platform. It was telling the partner team — and ourselves — that the MVP and the platform were two products, and that we had to ship both honestly. The week we wrote that down was the week the engagement worked.

JA

Junaid Ashraf

CTO · CodeFellow

Coordinating thirteen people across mobile, design, backend and architecture while the scope was being rewritten under us — that was the job. We kept the MVP launch date the whole way. Nothing slipped.

A

Amna

Project Manager · CodeFellow

The six primitives took weeks to design and minutes to defend. Identity, lookup, payment, workflow, audit, tenant. Every department app we modelled against them fit. That's the closest a platform gets to feeling right.

AF

Ahmad Faryab Kokab

Architect · CodeFellow

On the mobile side, every department app on this platform is a re-skin of the same scaffold — not a rebuild. Same primitives, same payment rails, different branding and copy. That's the difference between a platform and a coincidence.

M

Moiz

iOS / Android Developer · CodeFellow

Designing a citizen portal that has to feel native to a dozen different government departments — without becoming generic — was the design problem. The platform gave us themes and slot-based portals; the rest was patience.

R

Rafaey

Designer · CodeFellow

Need a rapid-app platformfor your government?

If you're a government department, a software partner, or a ministry programme office staring at six bespoke citizen apps you need to ship next year — talk to us. We've done it once. We can do it again, faster.

NDAs welcome. First call is on us.

Back to Blog