Selected work
Real estate · Top 1% brokerage in Canada · 2025-present

The website was thesmallest part of it

An operating system for a top 1% brokerage in Canada: an owned site with AI where it earns its keep, an admin the team opens every morning, and the automations and tests that keep both honest.

Platform buildAI featuresInternal toolingAutomationTesting
0
Channels in one board, one timeframe control
0×
Bilingual publishing a day, unattended
0
Monitor sets that check output, not exit codes
0
Languages, end to end, including the admin
The situation

The funnel worked. Running it did not. Performance lived in five dashboards nobody opened together, the content calendar lived in a spreadsheet, and every improvement, however small, went through me.

A growth system that only one person can operate is not a system. It is a dependency.

What I built

Four surfaces, all inside the site’s own admin so there is nothing extra to log into, and a layer of automation underneath that runs whether anyone is watching or not.

Everything below is the real layout with invented numbers. The client’s figures are not mine to publish.

The everyday view

Five channels, one timeframe control, one place. Sessions, leads, conversion and a thirty-day delta per channel, pulled every morning and pushed to Telegram as a digest so the team reads it before they open a laptop.

Sixteen time windows, eight rolling and eight calendar, against previous period or year on year. Two rules make it trustworthy. The snapshot ships resolved date ranges rather than date maths the app re-derives, so a headline figure can never disagree with the table under it. And every source anchors to its own latest complete day, never to today, because Search Console finalises about three days late: a today-anchored week gives it four days of data and three of silence, and draws a 40% collapse that never happened.

Real limits are shown rather than filled in with zeros. One source only holds 175 days, so year-on-year is disabled for it and the reason is printed on the card. Another caps account metrics at 30 days, so those hide on longer ranges while the per-post metrics, which do roll up correctly, stay. A dashboard that quietly invents the numbers it cannot fetch is worse than one with gaps.

Channel Room · last 30 daysRepresentative data
ChannelSessionsLeadsConv.Δ 30dTrend
Organic search1,412845.9%+38%
Paid social2,6801314.9%+12%
Email318278.5%-4%
Direct944394.1%+9%
Referral207115.3%+2%
The content cockpit

The calendar generates itself. Hooks and captions are drafted in the owner’s voice in both English and Farsi, queued three times a day, and held for approval or released automatically. Everything is editable, and everything is undoable.

Studio · content calendarRepresentative data
Mon
Market report, September numbers
PublishedFA
Listing walkthrough, Unionville
PublishedEN
Tue
Why the average price is the wrong number
ScheduledFA
Wed
Open house, Saturday
ScheduledEN
Neighbourhood guide, part 3
DraftFA
Thu
Buyer question: what is a status certificate
ScheduledEN
Fri
Weekly recap
DraftFA
Closing, 268 Pasadena
ScheduledEN
The morning queue

The part I am most pleased with. Every night the system reads its own analytics, logs and error traces and writes back a short list: what broke, what is wasteful, what is missing. Each item arrives already written as an instruction, so acting on it is a paste rather than a project.

Eighteen rules, not a model, and that is deliberate. A model rewords the same finding differently every day, so nothing ever reads as still open, and it will invent findings the data cannot support. Rules give each finding a stable identity, which is the only thing that makes “opened five days ago”, “new today” and “resolved” mean anything.

Every rule carries a minimum-volume gate. A 100% form-abandon rate across three starts is noise, and a queue that cries wolf gets ignored, which costs more than the finding was worth.

This morning’s queue · 3 itemsRepresentative data
Bug

Listing pages render the walkability card empty above Highway 7

Fix the walkability card returning empty north of Highway 7. Check the geo lookup bounds first, then the cache warm step.
Optimise

Sold listings still cost a full render on every request

Sold listings have no live data left to fetch. Move them to a static render and confirm the cache header changes from MISS to HIT.
Enhance

Buyers who saved three or more listings never get a follow-up

Add a saved-search digest for contacts with three or more saved listings and no activity in fourteen days. Send through the existing lifecycle path, not a new one.
What keeps it honest

Automations that report success while producing nothing are worse than automations that fail loudly. Every monitor checks the artifact, not the exit code: did the post publish, did the file contain rows, did the digest actually send. When a job stops, the system restarts it and says so.

This exists because of a specific failure. An outage sat unfixed for 47 hours behind an alerting system that was working perfectly and had nobody on the other end. Alerts are not a fix, they are a request for someone to be awake. So the repair loop runs every five minutes: it reads the freshness log, diagnoses with a read-only agent, applies exactly one action from a fixed menu, then re-runs the real job and checks for fresh output before it calls itself done.

Twenty-one checks in total, ten on the website and eleven on the automations. Two traps worth naming: a job can touch a file without writing anything to it, so freshness by timestamp alone lies, and a log read mid-write looks like a truncated failure. Both are checked for.

Automation health · overnightRepresentative data
Nightly listing syncoutput verified 03:12
Daily bilingual blogpublished 06:40, both languages
Social publisherrecovered after 1 retry, 07:02
Lead routing12 routed, 0 unassigned
Report mailersent 07:00, 4 recipients
Telegram · 07:00

Overnight: all clear.

Social publisher stopped at 02:41 and restarted itself at 02:44. One post went out 3 minutes late. No content lost.

4 new listings, 1 relisted, 2 sold and removed. 3 items in this morning’s queue.

AI where it earns its keep
  • A concierge on the site that answers from the listing data itself, so it can say what a specific property costs to carry rather than improvising. It is wrapped in a cost fortress, because an unmetered model endpoint on a public page is a billing incident waiting to happen: a daily spend ledger, per-IP rate limits, a hard turn cap counted before the history is truncated rather than after, prompt caching, and a kill switch. It also has no tool that can reach gated sold data, so it cannot leak what it cannot fetch.
  • A valuation take on every listing page, checked continuously against recorded sold prices. When it drifts, that shows up in the morning queue like any other defect.
  • Draft copy in the admin in two languages, in a voice built from thousands of the owner’s own sent messages rather than a generic assistant tone.
  • No AI on anything a wrong answer would make expensive. Pricing advice, legal wording and anything a client acts on stays human.
How I test it
  • Tests are proved by breaking the thing they cover. A test that stays green when you sabotage the code was never testing anything.
  • Checks verify against the source of truth, not against the specification. Documents drift; the data does not.
  • Every check guards the constraint that actually hurts. Paid-API cost under load, for one, after a background job quietly wrote to the database every fifteen seconds and put the deploy pipeline over quota.
What is next

It has a roadmap, which is the difference between a project and an operating system. Currently queued: an autonomous agent that drafts and schedules the whole content week for approval, a bilingual voice caller that qualifies inbound leads into the CRM, and self-hosted walkability data so one third-party rate limit cannot take a feature down.

Straight answer

What this does not do

It does not replace judgement. It surfaces the decisions faster and removes the excuse of not knowing, but somebody still has to choose what to build and what to leave. The morning queue is a list of candidates, not a plan, and roughly a third of what it proposes is not worth doing.