# FRA Atlas: A Project Blog

> Source: <https://dev.to/sahilbhardwaj81/fra-atlas-a-project-blog-16k3>
> Published: 2026-07-08 12:16:37+00:00

*Side note: this is a refreshed version of a blog I had saved in my library, reworked to say it better.*

A few months ago, our team took on a project that sounded, on paper, fairly straightforward. Build an AI-powered WebGIS and decision support system for the Forest Rights Act, 2006, for the Ministry of Tribal Affairs. Call it FRA Atlas. Give it a district-level risk atlas, an interactive map, a forest-fire early-warning module, and a water-aware crop recommender, all inside one React application, styled after india.gov.in with the tricolor palette and the right typefaces. A checklist of features. A scope document. A deadline.

It was only once we actually sat down with the Forest Rights Act itself that we realized how far "sounds straightforward" was from the truth.

Before we wrote a single line of code, we did what you're supposed to do. We read up on FRA 2006. We understood, in the abstract, that it was about recognizing the rights of forest-dwelling communities over land they had lived on and depended on for generations. We knew the priority states we were building for, Madhya Pradesh, Tripura, Odisha, Telangana. We knew what a claim was, what a title was, roughly how the process worked on paper.

That was knowing. It let us talk about the project in meetings and sound like we had it handled.

Understanding came later, and it came slower, and it was uncomfortable in a way that knowing never is. Understanding meant sitting with the fact that this wasn't a generic mapping tool with a government theme slapped on top. It meant realizing that a "risk atlas" isn't just a set of colored polygons on a map, it's an attempt to represent something as serious as whether a community's claim to their own land is likely to be recognized or lost in bureaucratic backlog. Once that sank in, the choice to build it on K-Means clustering and PCA to produce a district-level risk index stopped being a modeling decision and started being an accountability decision, because every cluster boundary we drew was implicitly telling someone whether their district counted as high risk or not.

The same thing happened with the fire-warning module. On paper it looked like a bolt-on feature, a Random Forest and XGBoost ensemble with an LSTM layered in, feeding ROC and PR curves to a Fire Alert page. It would have been easy to treat it as a separate product living inside the same app. But once we understood the land itself, forest-dwelling communities whose legal claim to that land was still being processed, still depended on that forest for water, for grazing, for firewood, the fire model stopped being a side feature and became part of the same risk story the atlas was already telling. And the crop recommender, a deterministic agronomy rule engine we built to be ML-scoring-ready behind a FastAPI service, existed for the same reason: a patta-holder's land is only worth having recognized if it can actually sustain them afterward. Risk, fire, and water weren't three separate modules anymore. They were three views of one question, whether a community's claim to this land would hold, and whether the land would hold up its end of it.

That shift, from knowing the requirements to understanding the reason the requirements existed, changed how we approached everything after. Once we actually understood what we were building and why, decisions that had felt arbitrary started making sense, and decisions we'd made too quickly started looking wrong. We ended up redesigning parts of the risk-scoring logic not because the first version was technically broken, but because it was correct in a way that missed the point.

We think this is the part nobody tells you when you're starting out. You assume the hard part of a project like this is the tech, the React architecture, the GIS layers, the model behind the recommender. It isn't. The hard part is closing the gap between what you know about a problem and what you actually understand about it, and that gap doesn't close by reading more documentation. It closes slowly, usually while you're in the middle of building something and realize the thing you're building doesn't match the thing that's actually needed.

This is also just what we believe as problem solvers now, past this one project. Understanding the problem at its core does most of the work of figuring out what actually needs to be built, and what needs to be built around it. Once you understand the core of a problem properly, the architecture starts suggesting itself, the feature list starts sorting itself into what matters and what's decoration, and the scope stops feeling like a checklist someone handed you and starts feeling like a set of conclusions you'd have reached yourself. Most of what looks like a technical decision later turns out to have been an understanding decision earlier, one that just hadn't been named yet.

It's tempting to describe a project like this as a coding challenge with some research on the side. That's backwards. The research was the harder half, and it tested us in places we didn't expect it to.

Technical availability was one front. We didn't have access to live, authoritative FRA claims data at the granularity we wanted, so the risk atlas runs on a static dataset spanning roughly five hundred districts, and the fire-forecast module works off a similarly static set of around two hundred and eighty records. That's not a limitation we chose for convenience, it's a limitation the actual availability of government data forced on us, and understanding that early changed how we architected the whole system. We built with fallbacks in mind from the start, so the crop recommender's rule engine, for instance, runs entirely client-side in JavaScript and only calls out to a FastAPI service for ML-based scoring when that service is reachable. If the backend isn't available, the app still works, just with the deterministic rules instead of the learned scoring layer.

Research was the other front, and a much bigger one than we expected. Getting the K-Means clustering and PCA pipeline right for the risk index meant actually understanding what factors should count toward a district's risk in the first place, which meant reading around FRA implementation data, not just the model documentation. Getting the fire-warning ensemble right, Random Forest and XGBoost alongside an LSTM, meant understanding enough fire ecology and seasonal patterns in these regions to know whether the ROC and PR curves we were staring at actually meant something or were just numbers that looked respectable. None of that research showed up in a commit log. All of it showed up in whether the models were saying something true.

Here's roughly how it all sits together once the dust settled:

```
┌─────────────────────────────────────────────────────────────┐
│                        FRA Atlas (React SPA)                 │
├───────────────┬───────────────┬──────────────┬──────────────┤
│  Dashboard /   │  Fire Alert   │  Crop         │  Reports      │
│  Map / DSS /   │  /fire        │  Recommender  │  /reports     │
│  Analytics     │               │  /crops       │               │
├───────────────┼───────────────┼──────────────┴──────────────┤
│  Chatbot       │  Prediction   │  (shared across all pages)   │
│  /assistant    │  Model        │                               │
│                │  /sustain     │                               │
├───────────────┴───────────────┴──────────────────────────────┤
│ FRA risk data   │ Fire forecast  │ Crop rule engine (JS) ──┐   │
│ (static JSON,   │ (static JSON,  │  ↕ falls back to ↕       │   │
│  500 districts) │  280 records)  │ FastAPI /recommend ──────┘   │
└─────────────────────────────────────────────────────────────┘
```

The Chatbot and the sustainability Prediction Model sit slightly apart from the four main pages in that diagram on purpose. They're not tied to one dataset or one page the way the Fire Alert or Crop Recommender modules are, they draw on the understanding built across the whole system, the legal detail from the Act, the risk signals from the atlas, the sustainability question from the crop layer. In a real sense they were the last two pieces to become trustworthy, because they were the two pieces that most directly exposed whether we understood everything underneath them or were just wiring modules together and hoping the seams held.

Somewhere in the middle of the project we also built a chatbot meant to answer questions about the Forest Rights Act directly, along with a prediction model attempting to judge whether a given claim would sustain, whether it would actually hold up. Of everything we built, this is the piece that most bluntly exposed how much of the Act we still only knew rather than understood.

A dashboard can get away with a shaky understanding of the law underneath it, because the visuals do a lot of the talking. A chatbot can't. The moment you're generating an answer to "does this claim qualify," you find out immediately whether you actually understand the eligibility conditions or whether you'd just been nodding along to summaries of them. We rewrote the chatbot's underlying logic more than once, not because the code broke, but because our own understanding of the Act kept getting sharper the longer we sat with it, and every sharper understanding made the previous version of the chatbot look naive. The sustainability prediction model had the same effect in reverse, it forced us to be honest about how much genuine signal we had versus how much we were inferring, because a model that quietly overstates its own confidence is worse than no model at all when the answer affects someone's land.

If the dashboard and the risk atlas taught us that knowing and understanding are different, the chatbot is what proved it, out loud, in front of us, every time it gave an answer we weren't fully sure we'd earned.

We had a timeline. Like most timelines on a first attempt at something this scoped, it was wrong in the way that only becomes obvious once you're already committed to it. Four interconnected modules, real government design constraints, real data, and a small team without the bandwidth that a project like this probably deserved. We didn't have enough hands, and we didn't have enough hours, and no amount of enthusiasm was going to quietly fix either of those things.

What made it harder wasn't just the shortage of time or people. It was that we kept discovering, midway through, that we understood the problem less than we'd thought, and every one of those discoveries cost us time we didn't have to spare. Understanding, as it turns out, doesn't arrive on schedule. It arrives when it arrives, usually right after you thought you were done.

The other thing that shaped this project, maybe as much as the deadline did, was that we didn't all see the solution the same way. Different people on the team had different instincts about how the risk atlas should weigh its factors, how much of the interface should lean on the map versus on plain data views, how far the AI components should go in making recommendations versus simply surfacing information for a human to decide. None of these disagreements were about right and wrong exactly. They were about different mental models of the same problem, which in hindsight makes sense, because we were all still individually working through the gap between knowing and understanding, just at different speeds and from different angles.

It felt like a storm at the time. It didn't feel productive in the moment, sitting in a discussion that circled the same disagreement for the third time. But looking back, we think those arguments were actually where most of the real understanding got built. Nobody has the full picture alone on a project this layered, and the friction between different opinions was, uncomfortably, how the picture became more complete.

If we were starting FRA Atlas again, we don't think we'd try to avoid any of this. We don't think it's avoidable. We'd just go in knowing that the checklist of features is the easy part to see and the hardest part to actually finish, because underneath every feature on that list is a real problem that has to be understood, not just implemented. The deadline will feel wrong almost immediately. The team will disagree, sometimes loudly. And somewhere in the middle of all of it, if you're paying attention, you'll notice the moment you stopped just knowing the problem and started understanding it. That moment is usually where the real work begins.

*A small note: the English here has been cleaned up with AI help so it reads clearly, but everything said is ours, written by me from what our whole team actually lived through building this.*
