Ujjain Police's hospitality compliance ran on paper C-Forms and WhatsApp photographs. With Simhastha 2028 expected to bring crores of pilgrims into a city of this size, the manual system was not going to bend — it was going to break, in the specific way paper systems break: quietly, and only visible after the fact.
The constraint that shaped the architecture
There was no budget for a field-sales team, and no authority to compel adoption on a deadline. That single constraint decided most of the design.
A system hotels are asked to use has to be faster than the thing it replaces on the very first try. A receptionist at 11pm with a queue at the desk will go back to paper the moment the software makes them wait. So the hotel-side app had to be free, work on a phone, and never block on the police-side workload — which is the opposite of how compliance software usually gets built, where the regulator's dashboard is the product and the regulated party gets whatever is left.
Architecture
Two interfaces over one domain model:
| Layer | Choice | Why |
|---|---|---|
| Backend | .NET 9 + EF Core 9 | Long support horizon; this is a system a police department will run for a decade, not a startup MVP |
| Database | SQL Server 2022 | Already the standard in the department's environment — introducing a second database dialect into a government estate is a cost someone pays later |
| Frontend | Angular 18 | Two distinct apps — hotel and police — sharing components and one auth model |
| Hosting | Windows EC2 + IIS | Matches the operational skills actually available for handover |
Hotels enter guest details once. Police get jurisdiction-level dashboards with foreign-guest tagging, so a station sees its own load rather than the whole city's.
The engineering problem worth writing about
By the time the guest table passed half a million rows, the check-in report — the screen police staff open most — had degraded to 0.88 seconds. That is still "fast" by the standards of most internal dashboards, and it is exactly the kind of number a team talks itself out of fixing.
We profiled it instead of guessing. The report was built as a view with the filter and the sort split across the join, which meant the query planner could not use the index it looked like it should use, and was resolving the full set before paging it. The cost showed up as 37,840 logical reads per execution — the database reading tens of thousands of pages to return one screen of rows.
The fix was structural rather than clever: seek GuestDetails on the (HotelID, CreatedAt) index first, page that down to the rows actually being displayed, and only then hydrate those rows with their joins. Same output, different order of operations.
| Before | After | |
|---|---|---|
| Logical reads per report | 37,840 | 1,245 |
| Response time | 0.88s | 0.13s |
| Database work | — | ~30× less |
The response time is the number a user notices. The logical reads are the number that decides whether this still works at ten lakh guest records, which is where the platform is heading. Cutting page reads by 30× buys years of headroom that adding hardware would only have rented.
Adoption
No field sales. One launch event with senior police leadership, then SHO-led nudges and word of mouth. 400+ hotels within the first nine months — effectively every licensed hotel in the city at that point — and 1,153 today.
The reason that worked is not marketing. It is that the hotel side was genuinely free, genuinely faster than the paper form, and did not require a hotel to buy anything or install anything.
Where it stands
The deployment is the reference model for state-level expansion ahead of Simhastha 2028. It runs 24×7 with real users at the front desk, which means every change ships against a live compliance workload — and that constraint, more than any framework choice, is what the architecture was built for.
