File size: 21,240 Bytes
41d16b3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
# DDA Change Detection β€” Implementation Plan (Dev Space Only)

**Document:** Scope of Work β†’ Engineering Plan  
**Client:** DDA (Delhi Development Authority)  
**Target environment:** Hugging Face **`satdetect-dev`** only (`hf-dev` remote, `master` branch)  
**Production (`satdetect`) must not receive these changes until explicit sign-off.**

---

## 1. Executive summary

The SOW transforms the current β€œupload two PNGs β†’ run detection β†’ view history” demo into a **departmental change-monitoring system** with:

- A **persistent image library** (GeoTIFF, hierarchical metadata, search)
- **Library-driven comparison** (Base T1 vs Comparison T2)
- **Async AI detection** with geo-referenced outputs
- **Reports** (browser + PDF + email)
- **Geo-navigation** and **clickable regions**
- **Human review** (Confirmed / False Positive) and **export to departmental systems**

The existing codebase is a strong **Phase-0 foundation**: AdaptFormer-based detection, region classification, overlay UI, email notifier, and history. Roughly **40% of FR-07** exists; **FR-01–FR-06 and FR-08 are largely net-new**.

**Recommended approach:** Implement behind a **`APP_MODE=dda`** feature flag on dev, extend the database and API vertically, and keep production on the current simplified flow indefinitely.

---

## 2. SOW requirements β†’ current state

| ID | Requirement | Current state | Gap severity |
|----|-------------|---------------|--------------|
| **FR-01** | Centralized image library (Zone β†’ Village β†’ Area β†’ Year or Grid) | Zone/Village are free-text dropdowns on upload; images discarded after run except thumbnails | **Large** |
| **FR-02** | GeoTIFF upload + validation + manual georef fallback | PNG/JPEG only, 20 MB, Pillow RGB load | **Large** |
| **FR-03** | Pick Base/Comparison from library or drag from tree | Local file upload only | **Medium** (depends on FR-01) |
| **FR-04** | AI detection as background job; simplified change types; lat/lng per region | Synchronous `/api/detect`; rich internal taxonomy; pixel coords only | **Medium–Large** |
| **FR-05** | In-app notification + report link; PDF export; persistent reports | Email optional; HTML modal report; no PDF; history exists | **Medium** |
| **FR-06** | Navigate to change by lat/lng; Locate action | No geospatial metadata | **Large** (depends on FR-02) |
| **FR-07** | Clickable regions auto-pan viewer; side-by-side Base/Comparison | Region row hover + compare slider partially exist | **Small–Medium** |
| **FR-08** | Confirm / False Positive; submit to dept API or export | Not implemented | **Medium** |

### SOW change-type mapping (canonical output)

Map internal `detection_engine` labels β†’ DDA report types:

| DDA type | Internal sources (examples) |
|----------|------------------------------|
| **New Construction** | New Construction/Building, Temporary Structure, Road/Pavement Change (New) |
| **Demolition** | Demolition/Clearing, Partial/Full Demolition |
| **Extension** | Expansion, Widening, Renovation |
| **Vegetation Change** | Vegetation Change (+ sub-types) |
| **Other** | Water Body, Bare Land/Soil, Unclassified |

Store both `dda_change_type` (report) and `internal_object_type` (model/debug) on each region.

---

## 3. Deployment & branching strategy

```
master (DDA features)  ──push──►  hf-dev  β†’  coderuday21/satdetect-dev
production             ──push──►  hf       β†’  coderuday21/satdetect  (frozen)
```

### Dev-only safeguards

1. **`APP_MODE` env var** on `satdetect-dev`: `dda` enables library, GeoTIFF, jobs, RBAC, review UI. Default / production: `legacy`.
2. **Separate DB file** on dev: `data/dda_app.db` (avoid mixing guest history with library assets).
3. **All new routes** under `/api/dda/*` or gated by `APP_MODE` in `main.py`.
4. **CI checklist** before any production promote: diff must not touch DDA modules unless mode flag documented.

---

## 4. Target architecture

```mermaid
flowchart TB
    subgraph ui [Frontend SPA]
        LIB[Image Library Tree + Search]
        CMP[Comparison Picker T1/T2]
        JOB[Job Status / Notifications]
        RPT[Report Viewer + PDF]
        REV[Review Confirmed / FP]
    end

    subgraph api [FastAPI]
        AUTH[RBAC Auth]
        IMG[Image Library API]
        DET[Detection Job API]
        RPTAPI[Report + Export API]
        DEPT[Department Export Adapter]
    end

    subgraph data [Storage]
        DB[(SQLite / PostgreSQL)]
        FS[File Store: GeoTIFF + pyramids + overlays]
        JQ[Job Queue Table]
    end

    subgraph proc [Processing]
        GEO[rasterio ingest + CRS normalize]
        PIPE[detection_engine.run_detection]
        GEOOUT[Region centroid β†’ lat/lng]
    end

    LIB --> IMG
    CMP --> DET
    DET --> JQ
    JQ --> proc
    proc --> DB
    proc --> FS
    JOB --> DET
    RPT --> RPTAPI
    REV --> DEPT
    AUTH --> api
```

---

## 5. Data model (new & extended)

### 5.1 Hierarchy (FR-01)

Two organization modes (user selects at library root):

**A. Administrative (default for DDA Delhi)**  
`Zone` β†’ `Village` β†’ `Area` β†’ `Year` β†’ `[ImageAsset…]`

**B. Grid**  
`GridId` (e.g. `G-12-04`) β†’ `Year` β†’ `[ImageAsset…]`

Implement as normalized tables (not hardcoded JS):

```text
zones(id, name, mode)           -- mode: admin | grid_parent
villages(id, zone_id, name)     -- nullable for grid mode
areas(id, village_id, name)
library_years(id, area_id, year) -- optional grouping node; images also store year directly
```

For MVP, **Area** can be a free-text field on `ImageAsset` if DDA taxonomy is not finalized.

### 5.2 `ImageAsset` (FR-01, FR-02)

| Column | Purpose |
|--------|---------|
| `id`, `uuid` | Primary identifiers |
| `zone_id`, `village_id`, `area_name`, `year`, `grid_id` | Hierarchy |
| `capture_date` | Required metadata |
| `source` | `satellite` \| `drone` |
| `format` | `geotiff` |
| `file_path`, `thumb_path`, `preview_path` | Storage |
| `crs`, `bounds_json` | Geo metadata (WGS84 bbox) |
| `width`, `height`, `file_size_bytes` | Validation |
| `has_georef` | bool |
| `manual_location_json` | Fallback corner coords + notes if no embedded georef |
| `uploaded_by`, `created_at` | Audit |

### 5.3 `DetectionJob` (FR-04 async)

| Column | Purpose |
|--------|---------|
| `id`, `status` | `queued` \| `running` \| `completed` \| `failed` |
| `base_image_id`, `comparison_image_id` | FK β†’ ImageAsset |
| `method`, `params_json` | Detection settings |
| `run_id` | FK β†’ DetectionRun when done |
| `error_message`, `started_at`, `completed_at` | Job lifecycle |
| `notify_email`, `notify_in_app` | FR-05 |

### 5.4 Extend `DetectionRun`

Add: `base_image_id`, `comparison_image_id`, `job_id`, `report_pdf_path`, `status` (`draft` \| `published`).

### 5.5 Extend region JSON schema

Each region gains:

```json
{
  "ddaChangeType": "New Construction",
  "confidence": 0.87,
  "areaSqM": 142.5,
  "centroid": { "x": 412, "y": 288 },
  "latLng": { "lat": 28.6139, "lng": 77.2090 },
  "bbox": { "x": 380, "y": 260, "w": 64, "h": 56 },
  "reviewStatus": "pending",
  "reviewedBy": null,
  "reviewedAt": null
}
```

### 5.6 `RegionReview` + export batch (FR-08)

```text
region_reviews(id, run_id, region_id, status, reviewer_id, notes, submitted_at)
export_batches(id, run_id, format, payload_path, dept_api_response, created_at)
```

### 5.7 RBAC (FR-01, FR-02)

Extend `User`:

```text
role: viewer | uploader | analyst | admin
```

| Role | View library | Upload | Run detection | Review/submit |
|------|--------------|--------|---------------|---------------|
| viewer | βœ“ | | | |
| uploader | βœ“ | βœ“ | | |
| analyst | βœ“ | βœ“ | βœ“ | βœ“ |
| admin | βœ“ | βœ“ | βœ“ | βœ“ + manage hierarchy |

**Dev Space:** Re-enable login UI when `APP_MODE=dda`. Production stays guest/no-login.

---

## 6. API design (dev / DDA mode)

### 6.1 Image library

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/api/dda/hierarchy` | Tree: zones β†’ villages β†’ areas β†’ years (+ counts) |
| `GET` | `/api/dda/images` | Filter: `zone`, `village`, `area`, `year`, `date_from`, `date_to`, `grid_id`, `q` |
| `POST` | `/api/dda/images/upload` | Multipart GeoTIFF + metadata form |
| `GET` | `/api/dda/images/{id}` | Metadata + thumb URL |
| `GET` | `/api/dda/images/{id}/preview` | Downsampled PNG/Web tile for viewer |
| `DELETE` | `/api/dda/images/{id}` | Admin only |

**Upload validation (FR-02):**

1. Extension `.tif` / `.tiff`
2. Max size: **500 MB dev** (configurable; DDA responsible for suitable resolution per SOW)
3. `rasterio.open()` β€” verify readable, extract CRS/transform
4. If no georef: require `manual_bounds` (SW/NE lat-lng) + `capture_date` before commit
5. Generate 512px thumbnail + 2048px preview for UI
6. Return `{ id, status: "success" | "failed", errors[] }`

### 6.2 Comparison & detection jobs

| Method | Path | Description |
|--------|------|-------------|
| `POST` | `/api/dda/jobs` | Body: `{ baseImageId, comparisonImageId, method?, notifyEmail? }` β†’ `{ jobId }` |
| `GET` | `/api/dda/jobs/{id}` | Status + progress + runId when complete |
| `GET` | `/api/dda/jobs` | User's recent jobs (in-app notification feed) |
| `POST` | `/api/dda/detect` | **Legacy sync path** for small previews only (keep for HF debugging) |

**Job runner logic:**

```text
POST /jobs β†’ insert DetectionJob(queued)
           β†’ return 202 + jobId
Background worker thread:
  1. Load ImageAsset paths via rasterio
  2. Align pair (same CRS; reproject if needed)
  3. Windowed read β†’ RGB numpy arrays (max 1600px for DL)
  4. run_detection(...)
  5. For each region: pixel centroid β†’ lat/lng via transform
  6. Map object types β†’ ddaChangeType
  7. Save DetectionRun + overlay + update job completed
  8. Fire notification (in-app row + optional email with report link)
```

**HF timeout mitigation:** Job endpoint returns immediately; worker runs in-process with status polling. For GeoTIFFs >60s, use **pyramid preview** for detection (DDA supplies suitable resolution) and store full metadata separately. Document in UI: β€œAnalysis uses optimized resolution; full GeoTIFF retained in library.”

### 6.3 Reports (FR-05)

| Method | Path | Description |
|--------|------|-------------|
| `GET` | `/api/dda/reports/{run_id}` | Full report JSON (existing shape + geo fields) |
| `GET` | `/api/dda/reports/{run_id}/pdf` | Generate/download PDF |
| `POST` | `/api/dda/reports/{run_id}/notify` | Email with link to report |

**PDF engine:** `weasyprint` or `reportlab` β€” HTML template reuse from `templates/ChangeDetection.html`.

**In-app notification:** Bell icon + `/api/dda/jobs?status=completed&unseen=true`.

### 6.4 Geo-navigation (FR-06, FR-07)

No external map SDK required for MVP β€” **image viewer geo mode**:

- Report shows `lat, lng` per region
- **Locate** button: pan/zoom canvas to bbox center at 200% zoom, pulse highlight
- Optional Phase 2: Leaflet minimap with footprint rectangle

Frontend already has region hover β†’ bbox highlight; extend to **click row β†’ scroll viewer + zoom**.

Side-by-side: keep existing compare slider; add locked **T1 | T2 | Overlay** tabs when images loaded from library.

### 6.5 Review & departmental export (FR-08)

| Method | Path | Description |
|--------|------|-------------|
| `PATCH` | `/api/dda/reports/{run_id}/regions/{region_id}` | `{ reviewStatus: confirmed \| false_positive, notes? }` |
| `POST` | `/api/dda/reports/{run_id}/submit` | Submit confirmed only |
| `GET` | `/api/dda/reports/{run_id}/export.{csv\|xlsx\|pdf}` | Structured export |

**Department adapter pattern:**

```python
class DepartmentExporter(Protocol):
    def submit(self, run: DetectionRun, regions: list) -> ExportResult: ...

class ApiExporter(DepartmentExporter):      # DEPT_API_URL + DEPT_API_KEY
class FileExporter(DepartmentExporter):     # CSV/XLSX fallback
```

False positives: persist in `region_reviews` with `status=false_positive` for future training export (`/api/dda/training/export` β€” admin only, Phase 2).

---

## 7. GeoTIFF processing pipeline (accurate logic)

### 7.1 Ingest

```python
def ingest_geotiff(path: Path) -> GeoImageMeta:
    with rasterio.open(path) as src:
        crs = src.crs
        bounds = transform_bounds(src.crs, "EPSG:4326", *src.bounds)
        has_georef = crs is not None and src.transform != rasterio.identity()
        # Prefer RGB or first 3 bands; handle 1-band grayscale
        preview = read_downsampled(src, max_side=2048)
    return meta
```

**Dependencies to add (dev only branch):** `rasterio`, `pyproj` (GDAL wheels on Docker).

### 7.2 Pair compatibility check (before job starts)

| Check | Action |
|-------|--------|
| Same CRS or reproject T2 β†’ T1 CRS | Reproject comparison raster |
| Overlapping bounds | Warn if <50% overlap |
| Band count | Harmonize to RGB |
| Resolution ratio | Warn if >2Γ— GSD difference |

### 7.3 Pixel β†’ lat/lng

```python
def region_centroid_latlng(region_bbox, transform, crs):
    cx = region_bbox.x + region_bbox.w / 2
    cy = region_bbox.y + region_bbox.h / 2
    lng, lat = rasterio.transform.xy(transform, cy, cx, offset="center")
    if crs != EPSG:4326:
        lng, lat = transform_coords(crs, 4326, lng, lat)
    return lat, lng
```

### 7.4 Area in mΒ²

Use pixel area Γ— GSDΒ² from transform (for projected CRS in meters).

---

## 8. Frontend plan (dev UI)

Replace single upload card with **tabbed workflow** when `APP_MODE=dda`:

### Tab 1 β€” Image Library
- Left: collapsible tree (Zone β†’ Village β†’ Area β†’ Year)
- Right: grid of thumbnails + metadata
- Upload modal: GeoTIFF + form (hierarchy, capture date, source, manual bounds if needed)
- Search bar + filters

### Tab 2 β€” Change Detection
- Two slots: **Base (T1)** | **Comparison (T2)**
- Drag image from library OR picker dialog
- Show thumb + capture date for each
- Run β†’ job submitted β†’ progress spinner β†’ auto-open report on complete

### Tab 3 β€” Reports & Review
- List of completed runs
- Open report β†’ regions table with DDA types, lat/lng, confidence, area
- **Locate** per row; click row β†’ pan viewer
- Toggle Confirmed / False Positive
- Submit to department / Download export

### Tab 4 β€” Notifications
- Job completion feed (FR-05 in-app)

**Auth screens:** Login/register return on dev only (`APP_MODE=dda`).

---

## 9. Implementation phases

### Phase 0 β€” Foundation (3–4 days)
- [ ] `APP_MODE` flag + route gating in `main.py`
- [ ] Alembic-style migrations or existing startup migrations for new tables
- [ ] `rasterio` in `requirements.txt` + Docker GDAL base image update (dev Dockerfile branch)
- [ ] Seed script: import current `DELHI_ZONES` into DB
- [ ] Dev README section

### Phase 1 β€” Image library (FR-01, FR-02) (5–7 days)
- [ ] Models: hierarchy + ImageAsset
- [ ] Upload API + validation + thumbnail generation
- [ ] Library tree + search UI
- [ ] RBAC: uploader vs viewer

### Phase 2 β€” Library-based comparison (FR-03) (2–3 days)
- [ ] T1/T2 picker from library
- [ ] Drag-and-drop from tree to comparison slots
- [ ] Preview + capture date display

### Phase 3 β€” Async detection + geo output (FR-04, FR-06) (5–6 days)
- [ ] DetectionJob worker + polling API
- [ ] GeoTIFF β†’ RGB pipeline integration with `detection_engine`
- [ ] DDA change type mapping + lat/lng + area mΒ² on regions
- [ ] Job failure handling + user messaging

### Phase 4 β€” Reports & notifications (FR-05) (3–4 days)
- [ ] In-app notification feed
- [ ] Report page (browser)
- [ ] PDF export
- [ ] Email with report deep link

### Phase 5 β€” Interactive viewer (FR-07) (2–3 days)
- [ ] Locate button + click-to-pan/zoom
- [ ] Side-by-side T1/T2/overlay modes
- [ ] Region highlight sync (extend existing hover logic)

### Phase 6 β€” Review & export (FR-08) (4–5 days)
- [ ] Per-region review state
- [ ] CSV/XLSX/PDF export of confirmed changes
- [ ] Department API adapter (config-driven)
- [ ] False-positive archive for training

### Phase 7 β€” Hardening & UAT (3–5 days)
- [ ] Load test with sample GeoTIFFs from DDA
- [ ] Alignment QA on drone vs satellite pairs
- [ ] Security review (auth, upload limits, path traversal)
- [ ] Deploy checklist for `satdetect-dev`

**Total estimate:** ~25–35 working days (1 senior dev), assuming DDA provides sample GeoTIFFs and hierarchy taxonomy early.

---

## 10. Hugging Face dev constraints & mitigations

| Constraint | Impact | Mitigation |
|------------|--------|------------|
| ~60s HTTP timeout (cpu-basic) | Sync detect fails on large TIFF | Async jobs + immediate 202 response; detection on downsampled preview |
| Ephemeral disk | Library loss on rebuild | HF persistent storage volume; document backup to S3 optional |
| No GPU | Slow DL | Keep AdaptFormer on CPU tiles; cap image size; queue one job at a time |
| 50 GB space limit | Large GeoTIFF library | Per-file quota; admin purge; external blob store Phase 2 |
| Single worker | No true queue | SQLite job lock; one `running` job at a time |

**Dockerfile (dev):** Switch base to `osgeo/gdal:ubuntu-small` or install `libgdal` in existing image.

---

## 11. File / module layout (new code)

```text
app/
β”œβ”€β”€ dda/
β”‚   β”œβ”€β”€ __init__.py
β”‚   β”œβ”€β”€ config.py              # APP_MODE, limits, DEPT_API_*
β”‚   β”œβ”€β”€ models_library.py      # ImageAsset, hierarchy ORMs
β”‚   β”œβ”€β”€ models_jobs.py         # DetectionJob, RegionReview, ExportBatch
β”‚   β”œβ”€β”€ geotiff_io.py          # rasterio ingest, reproject, preview
β”‚   β”œβ”€β”€ geo_regions.py         # pixelβ†’lat/lng, area mΒ²
β”‚   β”œβ”€β”€ change_type_map.py     # internal β†’ DDA types
β”‚   β”œβ”€β”€ job_runner.py          # async detection worker
β”‚   β”œβ”€β”€ library_routes.py      # FR-01, FR-02 API
β”‚   β”œβ”€β”€ jobs_routes.py         # FR-04 API
β”‚   β”œβ”€β”€ reports_routes.py      # FR-05, PDF
β”‚   β”œβ”€β”€ review_routes.py       # FR-08
β”‚   └── dept_export.py         # adapter pattern
β”œβ”€β”€ static/js/dda/
β”‚   β”œβ”€β”€ library.js
β”‚   β”œβ”€β”€ comparison.js
β”‚   β”œβ”€β”€ jobs.js
β”‚   └── review.js
└── templates/
    β”œβ”€β”€ index.html             # legacy (production)
    └── index_dda.html         # dev SPA shell
```

Wire routers in `main.py`:

```python
if os.getenv("APP_MODE") == "dda":
    app.include_router(library_routes.router, prefix="/api/dda")
    ...
```

Set on **`satdetect-dev`** Space: `APP_MODE=dda`.  
Leave **`satdetect`** unset β†’ legacy behavior.

---

## 12. Testing strategy

| Layer | Tests |
|-------|-------|
| GeoTIFF ingest | Unit: georef / no-georef / 1-band / 4-band samples |
| Pair validation | CRS mismatch, non-overlap |
| Job lifecycle | queued β†’ running β†’ completed/failed |
| lat/lng accuracy | Known corner coords β†’ centroid within tolerance |
| DDA type mapping | Snapshot tests on classified regions |
| RBAC | Role forbidden on upload/delete |
| PDF | Report renders all mandatory fields |
| E2E | Upload 2 TIFFs β†’ job β†’ report β†’ confirm β†’ CSV export |

Use `scripts/validate_detection.py` extended with GeoTIFF fixtures.

---

## 13. Risks & dependencies

| Risk | Owner | Mitigation |
|------|-------|------------|
| DDA GeoTIFF quality / GSD | DDA (per SOW) | Pre-upload validation messages |
| No departmental API spec | DDA IT | File export fallback (FR-08) |
| Area taxonomy not finalized | DDA | Configurable hierarchy admin UI |
| Model accuracy on drone imagery | Shared | Alignment warnings; false-positive review loop |
| HF CPU timeout | Engineering | Async jobs + downsample policy |

**Blocked until DDA provides:**
1. Sample GeoTIFF pairs (georeferenced + one without georef)
2. Zone/Village/Area master list (or confirm Delhi list)
3. Department API spec OR confirm export-only
4. Grid definition if grid mode required at launch

---

## 14. Out of scope (explicit)

- Training/fine-tuning new DL models (use existing AdaptFormer + review feedback archive for Phase 2)
- Full GIS desktop analysis (QGIS replacement)
- Real-time satellite ingestion feeds
- Mobile native apps
- Production deployment of DDA features (until UAT sign-off)

---

## 15. Immediate next steps

1. **Create `satdetect-dev` Space env:** `APP_MODE=dda`
2. **Phase 0 PR** to `master` β†’ `git push hf-dev master:main`
3. **Request from DDA:** 3 sample GeoTIFF pairs + hierarchy spreadsheet
4. **Implement Phase 1** (library + upload) β€” highest dependency for all other FRs

---

## Appendix A β€” Legacy endpoint compatibility

Keep existing endpoints working in legacy mode:

| Legacy | DDA equivalent |
|--------|----------------|
| `POST /api/detect` (multipart files) | `POST /api/dda/jobs` (library IDs) |
| `GET /api/history` | `GET /api/dda/reports` |
| Guest user | RBAC users with roles |

No breaking changes to production API contract.

---

## Appendix B β€” Sample job response

```json
{
  "jobId": 42,
  "status": "completed",
  "runId": 108,
  "reportUrl": "/api/dda/reports/108",
  "summary": {
    "regionsCount": 7,
    "changePercentage": 2.34,
    "byType": {
      "New Construction": 3,
      "Vegetation Change": 2,
      "Other": 2
    }
  }
}
```

---

*Plan version 1.0 β€” derived from **Scope of Work_Change Detection-For Team.docx** (FR-01 through FR-08).*