Mortise
← Selected Work

Field-service dispatch platform

Primeline Flow

A dispatch platform that runs a plumbing business, from the first customer call to final payment, in one system the owner controls.

Visit the live site ↗
Role
Solo build
Scope
Design, code, and infrastructure
Category
Field-service dispatch platform
Year
2025
Primeline Flow customer booking page with live job tracking on a phone screen

01 / The brief

Primeline is a licensed-plumbing business in Sydney. The work was to replace a patchwork of phone calls, spreadsheets, and disconnected third-party tools with one system the business owns end to end: customer intake, job dispatch, field updates, and payment.

Because it moves money and coordinates people on live jobs, the bar was correctness rather than a good demo. A dispatch board that shows the wrong status, or a payment captured at the wrong moment, breaks the real business, not only the demo. It had to be right the first time.

Five-step job intake modal capturing job type and problem description

02 / How it was built

This is where the method mattered most. The build was not one long free-running session. It ran as a team of subagents against a written plan, and each milestone was planned, built, tested, and reviewed before the next one started.

On a system that moves money, that structure is not overhead. The same four roles below carried the whole build, with payments, auth, and tenancy kept behind explicit boundaries the entire way through.

01

Planner

Turns the brief into a written plan, milestone by milestone, with explicit “done = X” criteria and named boundaries on sensitive paths, all before any code is written.

02

Coder

Implements one milestone at a time in small, reviewable commits. It never touches a protected path such as payments, auth, or data without a recorded decision.

03

Tester

Exercises each milestone end to end, covering types, build, and the real user flow, then reports what actually happened. Failures get reported, not smoothed over.

04

Reviewer

Reads the diff critically, checking whether anything touches money, identity, or data access the plan did not authorize. It signs off milestone by milestone and leaves that record behind.

03 / The hard parts

01

Manual-capture payments, the main protected path

Stripe authorizes payment at booking and captures it by hand only once a job is verified complete. Every state change, from authorized to captured to released or refunded, is a protected step: explicit, logged, and never touched by an agent without a recorded decision.

02

Multi-role auth and RLS tenancy

Owner, dispatcher, and field tradesperson each see only what they should. Access is enforced in the database with Supabase Postgres row-level security, rather than hidden in the client where it cannot be trusted.

03

Real-time dispatch

Jobs move from intake to a dispatcher’s board to a tradesperson’s phone and back, with status staying consistent for everyone watching the same job at once.

04

Twilio field notifications via n8n

SMS to customers and field staff runs through n8n, so the messaging logic lives in one auditable place rather than scattered through the application code.

04 / Stack

Next.js
App UI and server routes, the part the business owns
Supabase (Postgres · RLS · multi-role)
Data, tenancy, and database-enforced access
n8n
Automation and messaging orchestration
Twilio SMS
Customer and field-staff notifications
Stripe (manual capture)
Authorize at booking, capture on completion

TODO: real, cleared-to-publish numbers go here (active tradespeople, jobs dispatched, uptime). Left blank on purpose rather than invented.

05 / Inside the product

Primeline Flow customer booking page with live job tracking on a phone screen
Customer intake and live job tracking, from entering a suburb to watching the tradesperson’s ETA.
Five-step job intake modal, step one of five, capturing job type and problem description
The intake form behind the booking button: a five-step wizard capturing job type and details before dispatch.
Owner’s ops dashboard showing booking totals and job status counts
The owner’s ops dashboard, pulling live booking and job counts straight from Supabase and Stripe.
n8n workflow editor showing the dispatch and notification automation
The n8n automation underneath: dispatch logic and Twilio notifications running as auditable workflows, not scattered through application code.
Recruiting page for plumbers, alongside a tradesperson’s own job list and messages
The recruiting side: the pitch to tradespeople, plus their own day view with jobs, messages, and gate codes.
A tradesperson’s own dashboard with today’s jobs, a map, and earnings
Each tradesperson’s own dashboard: today’s jobs, active jobs, weekly earnings, and Stripe payout status.
Team mode roster showing members, active jobs, and completions
Team mode: multi-tradesperson accounts with per-member job counts and roster management.
In-app feedback panel with a star rating, category, and message field
In-app feedback capture, wired directly into the product instead of a separate form.

Building something that has to be correct?

Same method, and the same boundaries on anything that moves money or data. Let’s scope it.

Book a discovery call