Case study 03 · Real-estate brokerage platform

Comtrak + Cubed

A two-tier commission and financial operations platform for a Philippine real-estate brokerage: Comtrak, the Laravel back-office and API of record — and Cubed, the Next.js app agents live in on their phones.

Sole architect & engineer, both tiers Mar 2025 – Jul 2026
Laravel 12.50 PHP 8.3 Filament v5.2 Sanctum laravel/ai Scribe Pest 3.8 Next.js 16 React 19 Zustand 5 SWR Storybook 10 Playwright · Vitest
~41.7k backend LOC
48 models · 133 migrations
104 frontend components
308 commits, both repos
21 AI tools · 4 personas
88 backend test files

The problem

A single property sale in the Philippines can owe money to a producing agent, a unit manager, a team leader, and an external referral partner — each a different share, computed after VAT is stripped from the contract price and withholding tax is deducted. Most brokerages run this in spreadsheets.

Comtrak replaces the spreadsheet — and Cubed gives the agents themselves live visibility into earnings, leads, listings, and payouts, instead of waiting for someone to email them a figure.

The system

One engineer designed the schema, wrote the commission mathematics, exposed the versioned API, generated its documentation, built the design system, and shipped the client that consumes it — then layered an AI agent on top.

Cubed — agent app (Next.js 16 · React 19)earnings · leads · listings · payout visibility · 104 components in strict Atomic Design · own token layer & design system
REST API v1 — passwordless email-code auth → Sanctum token · Scribe-generated docs · SWR hook family on an ApiRequest builder
Realty panelsales lifecycle · unit inventory · vouchers & collections · disbursements · lead inbox · cash-flow reporting
BackOffice panelsystem administration · 15 resources
Comtrak domain — 48 models · 133 migrations · 11 observers · commission engine · ComtrakAgent with 21 role-scoped AI tools

Engineering deep-dives

The case for end-to-end product capability, not just backend depth.

01

The commission engine

Every sale’s earnings compute the moment it is recorded. The pipeline strips VAT from the total contract price to reach true selling price, applies commission and incentive rates, deducts withholding tax, then splits across every party on the deal — including special-case rules where a marketing-partner deal is shared only between the partner and the supervising team leader. It recalculates when rates or prices change, so figures never drift.

The architectural decision worth explaining: this lives in 11 observers — on disbursements, vouchers, pricing versions, units, leads, and sale requirements — rather than in the callers, because the financial consequence of an operational action must not be something a future developer can forget to trigger.

Observer-driven money is harder to step through than a linear service call; the counterweight is a test suite that asserts the ledger, not the path.

02

An AI agent with role-scoped tools

ComtrakAgent, built on laravel/ai, answers natural-language questions about the business through 21 tools partitioned by who is asking. An Agent gets EstimateCommission, GetEarningsOverview, GetCollectionStatus, GetPerformanceTrend; a Leader gets FindAgent and ListMarketingPartners; a Manager gets GetSalesLeaderboard, GetTeamSalesSummary, GetInactiveAgents; a Marketing Partner gets only their own earnings and sales.

The insight: authorization is enforced by which tools the agent can even see, not by filtering the model’s output. The LLM cannot leak another agent’s commissions because it was never given a tool that could fetch them.

Scoping at the tool surface means more tools to maintain than one generic query tool — a cost taken deliberately, because a prompt cannot jailbreak a capability that does not exist.

03

Designing the API and its client together

A versioned REST API (v1) with passwordless authentication — request a 6-digit code by email, verify, receive a Sanctum token — documented automatically via Scribe. Cubed mirrors it with a hand-built data layer: an ApiRequest builder, a central endpoints registry, and a family of SWR hooks (useSWRRecord, useSWRPagination, useSWRInfiniteRecords) that feature hooks compose.

Two decisions worth noting: dashboard metrics are pre-calculated server-side rather than assembled in the browser, and the auth guard waits on Zustand’s persist hydration before deciding a user is logged out — closing the class of bug where a refresh briefly bounces an authenticated user to the login screen.

Owning both sides removes the usual API-contract friction — and removes the usual excuse: every mismatch is yours.

04

A design system built, not installed

Cubed defines its own token layer — CUBED_COLORS and CUBED_TOKENS feeding the Tailwind theme — over surface, ink, border, accent, and status roles, with dark mode driven by both a class and a data-theme attribute. The brand is built on the Philippine flag palette: blue #0047AB, gold #FCD116, red #CE1126.

Components are strictly layered atoms → molecules → organisms — 104 files — documented in Storybook with the accessibility addon in the loop, mobile-first from 375px with tables that become cards.

A bespoke system costs more upfront than installing a component library; it buys a brand the library could not express and tokens the whole app actually obeys.

Other subsystems

Unit inventory for condominium (tower / floor / unit) and housing (phase / block / lot) projects with automatic numbering, versioned pricing, and double-booking prevention · sales lifecycle draft → pending → approved → paid with bulk submit and approve · developer voucher and collection tracking · agent disbursements with line items and payments · tranched incentives with payment schedules · lead inbox with SLA-breach and dormancy detection, activity timeline, and single-transaction conversion to a sale · cash-flow reporting.

Stack & practices

Outcome

The brokerage’s commissions, collections, and payouts now compute the moment a sale is recorded and recompute when anything changes — figures never drift from the spreadsheet because there is no spreadsheet. Agents see their own numbers in Cubed instead of asking for them.

Dashboard metrics are pre-calculated server-side by design — a performance goal the architecture was built toward rather than an independently benchmarked figure.