The problem.
The owner runs a consultancy specialized in industrial real estate (warehouses, premises, offices, buildings, land). His team is seven brokers with very different track records: two reference partners, one consolidated senior, and four brokers building their book. Among them they handle three operation types — sale, rental, advisory — across five property classes.
The complexity wasn't volume — it was the compensation model. Three schemes coexist:
- Reference partners: distribute net profit at year-end with subjective adjustments based on contribution.
- Consolidated senior: fixed percentage on the operation, capped after threshold.
- Building brokers: escalating ladder by months tenure × cumulative volume × specific role.
And each operation gets distributed internally across six roles totaling 100% on the taxable base: Sourcing, Listing, Showings, Negotiation, Closing, and Collection. The same operation can have one person in two roles, or two people splitting one 50/50. On top, a commission only crystallizes when the Holded invoice goes to PAID — there are no partial payments, and if an invoice gets voided, it has to be adjusted forward.
What we built.
Role-based input webapp
Next.js + Supabase webapp where each operation is registered with: property, type (sale/rental/advisory), client, gross amount, taxable base, Holded invoice number, and the 6-role split. Each role has its own broker assigned and a percentage. The system validates that the 6 percentages add up to 100% and triggers the commission calculation.
Commission engine with 3 schemes
For each broker × operation combo, the engine knows which scheme applies and runs the right calculation. Output: net commission per broker, traceable to the rule and percentage applied. The owner sees pre-calculated splits the moment the operation is registered.
Bidirectional Holded integration
The webapp creates the invoice in Holded with the operation data, and listens via webhook for status changes (issued → paid → voided). When an invoice goes to PAID, the corresponding commissions become liquidable. When voided, they're reversed automatically. No double accounting.
Individual BI dashboard
Each broker logs into the webapp and sees their personal dashboard: closed operations, accrued commissions (paid invoices), pending commissions (issued not paid), and 12-month evolution. The owner has a master view with everyone, the team total, and aging of pending invoices.
I used to spend two afternoons every quarter calculating commissions. Now they're calculated automatically and each broker sees their own. We move from quarterly to monthly close without effort.
Stack used.
Next.js 14 · TypeScriptSupabasePostgreSQLn8nHoldedVercelTailwind