Case study

Brown Harris Stevens: Agent and Client Tools

Brown Harris Stevens is a New York luxury real estate brokerage. I was a core developer on agent and client tools for that business: the software agents use to work a listing and the software clients use to follow a search or a deal. The public site is bhsusa.com. This page explains the engineering problem and the shape of the solution, without turning a brokerage's internal tools into a feature tour they did not ask me to publish.

Problem

A luxury brokerage is not a single CRUD screen with a logo on it. Agents need tools that keep pace with a listing: the people involved, the documents, the follow-up, the version of the truth a client was shown. Clients need a narrower door into the same story, without seeing the agent's entire desk. When those tools grow inside one admin application, every new request shares a database user, a deploy, and a failure domain. A slow report for leadership becomes a slow afternoon for an agent on a showing.

The data is sensitive in a practical way. A client list, a price discussion, and an agent's pipeline are not content for a public API. Access has to follow the brokerage, the team, and the individual, and it has to be obvious in the code which of those three a query used. A single shared admin password, or a frontend that hides unauthorized buttons but still returns the records, is not a design. It is an incident that has not happened yet.

There was also a delivery problem. Brokerage software that ships twice a year trains the business to route around it with spreadsheets. The tools had to be separable so a client-facing change could go out without retesting every agent workflow, and so a defect in one area did not roll back the others.

My role

I joined this work as a core developer, writing Laravel and JavaScript for the agent and client tools and for the services behind them. I was not a slide-only advisor. The day-to-day was endpoints, the data those endpoints were allowed to return, and the UI that called them. I worked with the people who knew the brokerage process so the service boundaries followed the work, not a generic microservice diagram.

My responsibility included saying no to a shared table when two tools only looked similar. Agent operations and client views can share a listing identifier without sharing a codebase or a permission model. I pushed for that split, then implemented the pieces I owned so the split was real in the repository, not only in a drawing.

Stack

The server side I worked in was Laravel, with JavaScript for the application UI and for the parts of the tooling that lived closer to the browser. APIs between the agent tools and the client tools were HTTP, so each side could be deployed on its own schedule. MySQL held the brokerage data those services were allowed to own. Background work stayed off the request path when it talked to anything slow. Authentication and authorization were server-side checks on every read that crossed a team or client boundary. I am not going to invent a longer vendor list than the one I actually used for this engagement.

  • Laravel for the services behind agent and client tools
  • JavaScript for the application UI
  • HTTP APIs between tools that ship separately
  • Server-side authorization on every sensitive read
  • MySQL for the data those services owned

Architecture

The architecture choice was to treat agent tools and client tools as separate applications that share identifiers, not as modules inside one deployable. An agent workflow can query what that agent is allowed to see. A client session can query the slice that was shared with that client. Neither session is a flag on the same mega-query. If a developer later adds a field, they add it in one service and decide explicitly whether the other service should receive it.

That sounds like extra work, and it is, at the start. It removes a class of bugs I have seen in brokerage and CRM code: a join written for an internal report that becomes the query behind a client page. With separate services, that join does not exist in the client path because the client service does not have the tables. The contract is a response shape, reviewed when it changes.

Operationally, each service logs the actor and the listing or client identifier. When something looks wrong, you can tell whether an agent tool or a client tool served it. Deploys are independent. A defect in a new client view does not require rolling back the tool an agent is using in the field that afternoon.

Results

The tools shipped as part of the brokerage's working software, and bhsusa.com remains the public face of the business. I will not publish internal adoption counts or revenue language I do not have on record. What I can say as the developer is that agent workflows and client views no longer had to move in lockstep, and authorization lived in the service that owned the data rather than in a hidden client check.

For a later team, the useful result is the boundary. A new client feature has a place to go. A new agent report does not automatically become visible to a client session. That is a quieter result than a metric on a billboard, and it is the one that keeps a luxury brokerage's software from collapsing into a single admin app again. If you are hiring for similar agent and client products, the Laravel and full-stack pages describe how I take that kind of work on now.

bhsusa.com

Related services

Related case studies

Contact

Email aamirallidev@gmail.com or send a note from the contact section. I typically reply within one business day.