← All work

IBS — a property-management platform, end to end

Intelligent Broker System runs the daily business of property-management companies in the UAE: units, contracts, cheques, receipts, legal cases and reports, with portals for landlords and tenants. I’m the main developer on its .NET backend and its Angular front ends.

Role
Main full-stack developer
Period
Jan 2020 – present
Backend
.NET 10, EF Core, SQL Server, Azure
Frontend
Angular 21, Angular Material
My part

What I did

The current platform was started in 2024 to replace an older ASP.NET Web Forms system. For the first stretch, a senior backend developer and a senior frontend developer set the direction and reviewed my work. Since then I’ve carried most of the design and delivery: new modules, the database, the background jobs, the customer portals and the releases.

In numbers: about 1,600 of the backend’s 3,400 commits are mine, the most of anyone, and since January 2025 it’s more than 80%. On the Angular agent portal it’s 516 of 547; the landlord and tenant portals are almost entirely mine.

System map

How the pieces fit

One API and one database behind every client, with slow work handed to background functions.

Shipped through Azure DevOps pipelines. All projects share one central package list, which keeps the .NET and Angular versions current — both are on the latest major.

Scope

What the product covers

  • Properties & unitsinventory, status, occupancy
  • Contractsnew, renewal, approval, termination
  • Paymentscheques, deposits, batches, plans
  • Receiptsgenerated PDFs with VAT QR
  • Final clearancemove-out settlement
  • Management contractslandlord ↔ agency terms
  • Legal casesdisputes and their history
  • Vendors & vendor contractsmaintenance suppliers
  • Bookings & appointmentstenant branch visits
  • Reports & dashboardsMIS, rent forecasts, charts
  • Owners Gatelandlord portal and app API
  • Tenant portaltenant web and app API
  • Integrationslistings, office queue sync
  • Users & securityroles, Google sign-in, 2FA
Decisions

Problems, and what I did about them

The code is private, so here is the reasoning instead.

Layers that know only what they need

Problem
One codebase serves the agent portal, two customer portals, the mobile apps and the background jobs. If business rules depend on SQL Server or Azure, every one of those pays for it.
Decision
Clean Architecture: Api (HTTP only), Core (features, rules, validation), Persistence (EF Core, SQL Server, auditing), Infrastructure (files, PDFs, email), and a SharedKernal of types everyone uses. Each feature is one folder in Core.
Result
The Azure Functions register the same Core and Persistence services as the API, so a contract PDF built in a background job follows exactly the rules the web portal does.

Slow work leaves the request

Problem
Contract PDFs, receipts, ZIP exports, emails and WhatsApp messages are slow and can fail for reasons outside our control. Doing them inside an API call makes the clerk wait and turns a provider outage into a failed save.
Decision
The API saves, drops a message on an Azure Storage queue and returns. Queue-triggered Azure Functions do the work and retry on their own, and the finished file lands in Blob storage for the portal to pick up.
Result
Saving a contract is instant, and a mail-server hiccup no longer undoes anything.

Search requests that can’t outgrow the URL

Problem
Filters with many selections were sent as query strings. On the deposit-batch list one filter alone reached 2.1 KB — past the 2 KB limit of IIS and most firewalls.
Decision
A written rule: lists use GET by default; as soon as a filter contains a list it becomes POST …/search with the filter in the body and paging still in the URL. Every filter has a validator that caps list sizes.
Result
Long filters no longer hit server limits, and paging stays visible in logs.

Every change has an author

Problem
This is money and legal contracts. ‘Who changed this cheque date?’ needs an answer months later — without the audit table slowing down the main database.
Decision
Auditing is wired into the EF Core save pipeline, so every entity change is recorded with its user and before/after values. A timer-triggered Function moves old audit rows out to Azure Table Storage on a schedule.
Result
Complete history, and a main database that stays lean.

Three kinds of users, three front doors

Problem
Agency staff, landlords and tenants need different data, different sign-in and different levels of trust.
Decision
Separate Angular apps and API modules for each audience, each with its own security service. Staff can sign in with Google; the landlord and tenant portals have two-factor sign-in with trusted devices that a scheduled job cleans up.
Result
A landlord can never reach staff endpoints, even by mistake.

Rules written down, not remembered

Problem
With one main developer, knowledge that lives only in my head is a risk to the company.
Decision
Each repo has a short conventions file: how endpoints are named, how errors are shaped, how dates are stored, how soft-deletes work — and why. When a feature is removed, I write down how to bring it back.
Result
New developers — and AI coding tools — produce code that matches what’s there.
Stack

Tools in this project

  • C#
  • .NET 10
  • ASP.NET Core
  • EF Core
  • SQL Server
  • ASP.NET Identity
  • JWT
  • FluentValidation
  • Ardalis.Specification
  • AutoMapper
  • QuestPDF
  • Serilog
  • Azure Functions
  • Azure Storage
  • Azure SignalR
  • Application Insights
  • Angular 21
  • Angular Material
  • RxJS
  • ngx-translate
  • ECharts / Chart.js
  • Azure DevOps