Amtalek
An Egyptian property marketplace and the business system the agencies run on, where a listing and an agency’s private stock are one record separated by a switch.
Context
Amtalek is two products sharing one database. The public half is a property marketplace for Egypt: apartments, villas and commercial space for sale and for rent, listed by estate agencies, alongside new developments from the country’s builders, searchable by city, purpose, type, rooms and price, on the web and in a mobile application. The private half is the system those agencies run their businesses on, sold to them by subscription: a CRM for leads and customers, an HR module for staff, tasks and performance, an inventory module for the properties themselves, and an accounting module for salaries, commissions and expenses. The two halves are not adjacent products. A property an agency records in its inventory is the same record a buyer finds on the portal, and the agency decides which of those two things it is. Four surfaces carry all of it: a public website, a mobile application, the dashboard a subscribing agency works in, and an administration dashboard where the platform itself is run.
The problem
A property marketplace lives or dies on supply, and supply belongs to agencies who have no particular reason to give it away. The usual answer is to sell them advertising, which makes the portal a cost the agency resents. Amtalek takes the harder route: sell the agency the software it runs on anyway, and make distribution a property of that software. This is a better business and a harder system. The agency’s inventory is now commercially sensitive, because it includes stock it has not chosen to advertise, deals in progress, owner contact details and what everything is really worth, and the same tables serve a public search engine. Meanwhile the CRM has to be genuinely good, because it is competing with the software an agency would otherwise buy, not with a listings page. And every limit the subscription sells has to be enforced across both halves at once.
The solution
One record for a property, with a switch on it. An agency adds a property to its inventory with documents, photographs, the owner, the price and a status it tracks daily, and then chooses whether it appears on the public search engine and mobile application or stays visible only to its own staff. That single decision is what joins the two products: the marketplace is fed by the tool the agency was already using, and the tool is worth paying for partly because of the marketplace. Around it the subscription meters both sides at once. A package buys CRM seats, supervisor seats, a lead allowance, job postings and CV downloads on the private side, and normal listings, featured listings and project slots on the public side, so one plan governs how much business an agency can run and how visible it is while running it. The public surfaces carry the rest: agency profiles, developer projects with launch pricing, saved favourites, enquiries and a jobs board.
Architecture
A Laravel 10 backend over MySQL with Redis in front of the reads that repeat, in Docker, with Firebase carrying push. The public web is Next.js and TypeScript, the mobile application is Flutter and Dart, and two dashboards sit behind them: one an agency works in, and one the platform is run from. Those are separate surfaces rather than one application wearing two hats, which matters because they answer to different people: the agency dashboard is scoped to a single company, while the administration dashboard sees every company and also sets the limits they are sold. Behind it the arrangement worth describing is that properties, agencies and the people working for them are one dataset addressed by two audiences with opposite expectations. The marketplace wants a fast, heavily filtered, cacheable read over public listings; the CRM wants an authoritative, per-agency, permission-checked view over everything including what is not published. Redis fits the first and is dangerous on the second. Around that sit the modules the subscription sells: leads with their lifecycle, staff with tasks and calculated performance, inventory with instalment plans for units still under construction, and accounts with per-deal commission. What is not recorded is how the entitlement limits in a package are enforced, and where leads arriving from outside the platform enter it.
Read this diagram as text
- Public web
- Next.js and TypeScript. Property search by city, purpose, type, rooms and price, plus agency profiles, developer projects, favourites and enquiries.
- Mobile app
- Flutter and Dart, on iOS and Android. The same search in the hand.
- Agency dashboard
- Where a subscribing agency runs its business: leads, staff, inventory and accounts, scoped to that company and nothing beyond it.
- Admin dashboard
- Where the platform is run rather than any one agency: the agencies themselves and their subscriptions, the developer projects, the public marketplace, and the limits every plan is subject to.
- Laravel 10 API
- Single entry point for the public surfaces and the agency system alike, in Docker.
- Properties & projects
- The record the whole system turns on: photographs, documents, owner, price, daily status, and instalment plans for units under construction. A switch on it decides whether it is a public listing or private stock.
- Leads & customers
- The lead lifecycle from first contact to closed deal, with filtering and ranking. Leads are documented as arriving without manual entry; where they enter from is not recorded.
- Staff & recruitment
- Employees, task assignment, calculated performance, documents, and the job postings and CV searches the same subscription meters.
- Subscription limits
- One plan metering both halves: seats, supervisors, leads, job posts and CV downloads on the private side, listings, featured listings and projects on the public side. How the limits are enforced is not recorded.
- Redis
- Fronts the public reads, which repeat constantly and are anonymous. The agency side is the half that must never end up in a shared response.
- Firebase
- Cloud Messaging, carrying push to the mobile application.
- Accounts & commission
- Salaries, expenses and revenue, and the per-deal commission that reaches back to the agent, the lead and the property that produced it.
- Public web → Laravel 10 API (search, enquire, save)
- Mobile app → Laravel 10 API (search in the hand)
- Agency dashboard → Laravel 10 API (leads, staff, stock, accounts)
- Admin dashboard → Laravel 10 API (agencies, plans, marketplace)
- Laravel 10 API → Properties & projects (public listing or private stock)
- Laravel 10 API → Leads & customers (lead to deal)
- Laravel 10 API → Staff & recruitment (tasks and performance)
- Laravel 10 API → Subscription limits (what this plan allows)
- Laravel 10 API → Redis (anonymous repeated reads)
- Laravel 10 API → Firebase (push delivery)
- Leads & customers → Accounts & commission (closed deal, commission owed)
- Properties & projects → Accounts & commission (instalments)
What makes it interesting
The parts a system like this is actually judged on.
- The whole design rests on one boolean, and it points in two dangerous directions. A property is either public inventory or an agency’s private stock, and the same record can be both over its life. Get the switch wrong in one direction and an agency’s unadvertised portfolio, its owner contacts and its margins are on a public search engine. Get it wrong in the other and a customer who paid for a featured listing silently disappears from the market. There is no forgiving middle, and every query that touches property has to be on the correct side of it.
- The marketplace and the CRM want opposite things from the same tables. A public search is anonymous, heavily filtered, repeated constantly and ideal for caching; an agency view is authenticated, scoped to one company, includes records that must never be cached into a shared response, and has to be authoritative the moment a colleague changes something. Serving both from one dataset means the caching strategy cannot be uniform, and the failure mode of getting it wrong is not a stale page but private inventory served to a stranger.
- Selling the operating system of the business rather than advertising on it changes what the software has to be. An agency will tolerate a mediocre listings page because it is a channel; it will not tolerate a mediocre CRM, because that is where its staff spend the day. So the private half is competing with real business software, and it has to carry leads, tasks, employee performance, recruitment, salaries and commission properly. The marketplace is the reason to adopt it, and the CRM is the reason to stay.
- Subscription limits are enforced across two products at once, which makes entitlement a cross-cutting concern rather than a billing feature. A plan grants a number of CRM seats and supervisors, a lead allowance, job posts and CV downloads on one side, and normal listings, featured listings and project slots on the other. Publishing a property is therefore not only a visibility decision but a quota decision, and the check has to sit wherever a listing is created rather than in a billing page nobody consults. It also produces three tiers of authority over one dataset: an anonymous public, an agency scoped to itself, and an operator who sees every agency and sets the limits they are sold.
- Property is a slow, document-heavy, high-value object, and the data model has to admit that. A record carries photographs, ownership papers, a price that is negotiable, a status that changes over weeks, and for anything under construction an instalment schedule that is closer to a finance product than an attribute. None of that behaves like a catalogue item, and a system designed around fast-moving inventory would model it badly.
- Commission is where the accounting module stops being generic. In this business a deal produces a payment to the company and a share to whoever closed it, so the ledger has to reach back to the lead, the agent and the property that produced it. That links the four modules into one chain rather than four features: a lead becomes a deal, a deal moves a property, a property pays a commission, and a commission belongs to an employee whose measured performance is built from the same events.
- The country sits in the address, which is a decision about the future. Serving from a country subdomain, with a country selector and prices shown in more than one currency, is what a platform does when it expects to be more than one market. That pushes currency, locale and geography into the data model early, and it makes every one of those choices harder to change later than it looks.
Engineering challenges
- One property record serving a public search engine and a private agency portfolio, separated by a single visibility decision
- Opposite caching requirements over the same tables: anonymous and cacheable against authenticated and per-agency
- A CRM good enough to compete with the software an agency would otherwise buy, not with a listings page
- Subscription quotas enforced across both halves, where publishing is a billing decision as much as a visibility one
- Property as a slow, document-heavy asset with instalment plans for units that do not exist yet
- A commission chain tying leads, staff, properties and the ledger into one sequence
- Arabic and English side by side, in a market where the listing text is written by the agency
Integrations
- Firebase: push notification delivery to the mobile application
- External listing platforms: inbound leads are documented as arriving without manual entry; which platforms, and how, is not recorded
Technology
- Laravel 10
- MySQL
- Redis
- Next.js
- TypeScript
- Flutter
- Dart
- Firebase
- Docker