// case-study.md

Brokerage Commission System
Real-estate brokerage operations on Vue + Laravel

A full-stack platform that runs a real-estate brokerage end-to-end — sales pipeline, multi-tier commission engine with approver workflow, multi-OU RBAC, expenses, and HR-lite — replacing a tangle of spreadsheets with one auditable source of truth.

client Confidential · under NDA
last touched
role Full-Stack Developer
period 2023 — Present
status In production
repos api · ui
Vue.js Laravel MySQL REST Sanctum RBAC
// receipts · tl;dr
domain models
52
migrations
~100
combined commits
~640
multi-OU RBAC
// outcome · what changed
BEFORE

Excel-based commission splits across multiple operating units; reconciliation by hand each period.

AFTER

52-model platform with 5-tier automated payouts; reconciliation is a query.

BEFORE

Each ops team kept its own spreadsheet; visibility ended at the team boundary.

AFTER

One platform with scoped multi-OU RBAC; managers see across teams without seeing across boundaries.

BEFORE

Migration history was a pile of timestamps; tracing a column change took grep + memory.

AFTER

~100 migrations + ~640 commits browsable by feature; schema history is auditable.

What it is

A platform that runs the day-to-day operations of a real-estate brokerage: property catalog, sales pipeline, multi-tier commission engine with approver workflow, multi-OU (multiple branches / sister brokerages) role-based access, plus expenses, cash advances, and HR-lite for payslips and memos.

Built as a Vue.js admin frontend on the Velzon theme, talking to a Laravel REST API with Sanctum auth. Around 50+ Eloquent models, ~100 migrations, and ~640 combined commits across ~22 months of iteration with the operations team.

The bottleneck

Real-estate brokerage commissions are unusually messy. A single sale can split payouts across multiple agents, sales teams, and the brokerage itself, with releases happening over many periods as the buyer pays installments — and the client operates several organizational units (OUs) that need their own data boundaries while sharing the same platform.

The operations team needed one platform that owns sales, commissions, releases, collections, expenses, and HR-lite, with per-OU role-based access and an auditable approval workflow on the releases that actually move money.

How I broke it down

What I built

Domain modules:

Commission Release approval flow — anonymized share-distribution table with 5-tier seller hierarchy, approver chain stepper, and per-tier release status.
MOCKRelease RL-04-2026 detail · 4-step approver stepper, summary tiles, and per-tier commission-share table (Director → Manager → Unit Mgr → Team Lead → Seller). Payee names anonymized.

Example: commission share computation — the heart of the engine, because rules vary by sale agreement, agent tier, and OU policy:

~/app/Services/CommissionShareService.php
class CommissionShareService
{
    public function distribute(SalesRecord $sale): Collection
    {
        return $sale->commissionTransactions
            ->flatMap(fn (CommissionTransaction $tx) => $tx->shares
                ->map(fn (CommissionShare $s) => [
                    'payee_id' => $s->payee_id,
                    'ou_code'  => $s->ou_code,
                    'amount'   => round($tx->amount * $s->percent / 100, 2),
                    'period'   => $tx->period,
                    'release_id' => null, // set when approver releases
                ]));
    }
}
Release approval flow + agent payout view redacted captures coming with the next writeup pass

Tech

Results

domain models
52
migrations
~100
combined commits
~640
multi-OU

The brokerage replaced its multi-workbook commission process with a single platform where a sale, its installments, its approver chain, and its agent payouts all live in one auditable ledger — with role-based views per organizational unit. Cash advances now reconcile against upcoming releases automatically. Expenses, payslips, leaves, and memos run on the same backbone instead of parallel spreadsheets.

Specific business figures stay with the client; happy to discuss specifics on request.

What I’d do again — and differently

Worked well:

Would tighten: