One housing project, 146 homes: 114 in the middle of their rows and 32 on the corners. Each home gets a set of metal items, a main gate, a side gate on the corners, railings, louvres on some house types, and every item passes through seven steps: measuring on site, ordering steel, fabrication, grinding and sealing, primer, installation and touch-up.
The workers report each step from their phones, in Chinese, Bengali or Burmese. Their app runs inside Telegram, the records sit in a cloud database, and the owner follows every block and every home on a web dashboard without making a call. We built it for our own metal fabrication floor and it has been in daily use since.
Most of what we learned in September 2026 came from four mistakes, all of them our own.
A block of ten homes should offer ten
On 4 September the owner opened the screen that assigns work in the factory. The quantity list offered 1, 2, 3, 4, 5, 6, 8, 10, 12, 20, 30 and 50. The block he had picked, B12, has ten homes. The item was louvres, which go on every home in that block, so the true maximum was ten. For the side gate, which only corner homes take, it was two.
He asked why the list was not built from the database. He was right. Every number the list needed was already in it, and the screen that workers use to report finished jobs had been counting from it all along. The factory screen used a fixed list someone thought was close enough.
A wrong list is worse than an ugly one, because people act on it. An order for 30 louvres from that screen would have sent the floor to cut 30 and the steel to be bought for 30.
We changed three things that day:
- The block list shows only blocks where the item fits, with the number of homes beside each name: "B12 · 10".
- The quantity stops at what the records allow for that block and that item.
- The server refuses the impossible order on its own. A list on a screen can be bypassed or out of date; the server is the last place that can say no.
We also split one message into two. "We cannot count this" and "this item is not counted per home" used to show the same thing on screen, a blank maximum. They are different facts, and the second one is normal: work for another company has no homes in our records. The screen now says which one it is.
The total matters as much as the count
The same day, a check of every list against the database turned up a bigger number problem. The database said louvres go on all 146 homes. The bill of quantities, the contract's own count, said 70. The difference, 76, is exactly the number of type A homes, and louvres belong to type B only.
That one field let workers report louvres on homes that never get them, and it put 76 jobs that did not exist into the project's total. When we corrected it, the project's progress moved from 4.2% to 4.7% overnight. Nobody worked faster. The total had shrunk to the truth.
If a progress figure is going to reach a client, check the denominator against the bill of quantities before anyone reads the percentage.
Two screens deciding the same thing will drift apart
On 17 September a worker on another project finished one of the two homes in his block, reported it, and could not report the second. Tapping the block again to add the second home cleared his selection instead. The server had the right data the whole time. The trap was in the screen.
While fixing it we checked every project for the same kind of trap, and found one the owner had not reported. The workers' app and the owner's dashboard each decide which items a home gets, in separate code. After the louvres fix, the app judged from the house type recorded for each home. In the 146-home project the type was recorded for each block instead, so the app decided that none of the 70 type B homes took louvres, and nobody could report them. The dashboard looked fine. A hard-coded line there happened to give the right answer.
The fix was one rule, used by both: when a block has no type recorded per home, every home takes the block's type. Before shipping it we listed what the dashboard decided for every home in the five projects tracked per home, 2,209 pairs of home and item, and compared the list before and after. The only judgments that moved were those 70 louvres, and no screen on the dashboard changed at all. That comparison is now a tool we keep.
Old screens keep calling the new server
On 4 September the server's answer changed shape: the list of blocks went from plain names to name-and-count pairs, so the new screen could print "B12 · 10". We shipped the new screen at the same time and tested both together.
The owner's phone was not running the new screen. He had opened the app from an old Telegram message, and Telegram served him the page it had kept from before. That old page printed the new answer as text, and every block on his list read [object Object].
Nothing crashed. That was the danger. Our tests always pair the newest screen with the newest server; people in the field do not. Telegram only changes the version a message opens when a new message is sent.
The rule since then: a field the app already reads never changes shape. New information goes into a new field, and a new screen that cannot find it falls back to the old one and says what it does not know.
What to ask before you buy a site-tracking system
- Where do its lists come from? Every choice a worker or supervisor taps should be counted from your project's records, per block and per home.
- Does the server refuse what the records rule out, or only the screen?
- Is the progress total built from your bill of quantities, and who checks it when the drawings and the bill disagree?
- What happens when someone opens an old version of the app?
- Can it tell "we do not know" from "this does not apply"?
We build these systems for other companies now, starting from their own records. A private review looks at how the work moves in yours.
Nicasia Digital Solutions