# توضیح response سنجش‌ازدور

این فایل response زیر را توضیح می‌دهد:

- کد HTTP داخلی: `200`
- پیام: `success`
- وضعیت نهایی تحلیل: `completed`
- منبع response: `database`

این response نشان می‌دهد که pipeline سنجش‌ازدور برای یک مزرعه با موفقیت اجرا شده، داده‌های ماهواره‌ای برای 12 سلول grid ذخیره شده، و در نهایت subdivision داده‌محور با 2 خوشه ساخته شده است.

## جمع‌بندی سریع همین response

- تحلیل مربوط به بازه `2026-04-09` تا `2026-05-09` است.
- درخواست در `2026-05-10T20:17:34Z` شروع شده و در `2026-05-10T20:28:29Z` کامل شده است.
- 12 سلول grid با اندازه `900` مترمربع پردازش شده‌اند.
- feature های استفاده‌شده برای clustering این‌ها هستند:
  - `ndvi`
  - `ndwi`
  - `soil_vv_db`
- هیچ metricی fail نشده است.
- همه 12 observation قابل استفاده بوده‌اند:
  - `usable_observation_count = 12`
  - `fully_null_observation_count = 0`
- نتیجه نهایی clustering برابر `2` خوشه است.

## ساختار کلی response

ساختار سطح بالا این response به صورت زیر است:

```json
{
  "code": 200,
  "msg": "success",
  "data": {
    "status": "completed",
    "source": "database",
    "run": {...},
    "task": {...},
    "location": {...},
    "summary": {...},
    "cells": [...],
    "subdivision_result": {...},
    "pagination": {...}
  }
}
```

هر بخش یک نقش جدا دارد:

- `run`: رکورد اصلی اجرای تحلیل
- `task`: وضعیت orchestration و stageهای Celery/pipeline
- `location`: اطلاعات مزرعه و layout بلوک‌ها
- `summary`: خلاصه آماری observationها
- `cells`: داده خام هر سلول grid
- `subdivision_result`: خروجی clustering و assignment هر سلول
- `pagination`: اطلاعات صفحه‌بندی برای لیست cellها و assignmentها

## بخش `code` و `msg`

- `code = 200`
  - یعنی endpoint با موفقیت جواب داده است.
- `msg = "success"`
  - پیام عمومی موفقیت است.

این دو فیلد بیشتر برای client-side handling مفید هستند.

## بخش `data.status` و `data.source`

- `status = "completed"`
  - یعنی فرآیند تحلیلی کامل شده و نتیجه نهایی آماده است.
- `source = "database"`
  - یعنی response از داده‌های ذخیره‌شده در دیتابیس ساخته شده، نه از اجرای زنده openEO در همان لحظه.

نکته:

- این به معنی آن نیست که openEO استفاده نشده؛ برعکس، openEO قبلاً استفاده شده و خروجی آن در DB persist شده است.
- فقط endpoint فعلی نتیجه را از cache دیتابیسی برگردانده است.

## بخش `run`

بخش `run` رکورد اصلی اجرای remote sensing را توصیف می‌کند.

### فیلدهای پایه

- `id = 1`
  - شناسه اجرای تحلیل
- `block_code = ""`
  - اجرای تحلیل روی block پیش‌فرض/کل محدوده انجام شده است
- `chunk_size_sqm = 900`
  - هر cell حدود 900 مترمربع است
- `temporal_start = "2026-04-09"`
- `temporal_end = "2026-05-09"`
  - بازه زمانی داده‌های ماهواره‌ای

### وضعیت run

- `status = "success"`
  - وضعیت خام دیتابیس
- `status_label = "completed"`
  - نسخه نرمال‌شده برای client
- `pipeline_status = "completed"`
  - وضعیت نهایی قابل نمایش برای frontend
- `stage = "completed"`
  - آخرین stage ثبت‌شده

### featureهای انتخاب‌شده

- `selected_features = ["ndvi", "ndwi", "soil_vv_db"]`

یعنی clustering فقط با این سه feature انجام شده است.

### `requested_cluster_count`

- `requested_cluster_count = null`

یعنی کاربر تعداد cluster را مستقیماً مشخص نکرده و سیستم آن را خودش انتخاب کرده است.

## بخش `run.metadata`

این بخش metadata کامل اجرای pipeline را نگه می‌دارد.

### `scope`

- `scope = "all_blocks"`

یعنی اجرا در scope کل blockهای قابل تحلیل ثبت شده است.

### `service`

این بخش مشخص می‌کند metricها از کدام backend آمده‌اند.

- `backend = "openeo"`
- `backend_url = "https://openeofed.dataspace.copernicus.eu"`
- `collections_used = ["SENTINEL2_L2A", "SENTINEL1_GRD"]`

یعنی:

- `ndvi` و `ndwi` از Sentinel-2
- `soil_vv` از Sentinel-1
- `soil_vv_db` به صورت مشتق‌شده از `soil_vv`

### `job_refs`

این‌ها شناسه jobهای openEO هستند:

- `ndvi`
- `ndwi`
- `soil_vv`

این شناسه‌ها برای trace کردن jobهای backend خیلی مهم‌اند.

### `failed_metrics`

- `failed_metrics = []`

یعنی هیچ metricی fail نشده است.

### `payload_diagnostics`

برای هر metric یک summary از payload خام openEO ذخیره شده:

- `returned_cell_count = 12`
- `payload_keys_sample = ["0", "1", "2", "3", "4"]`
- `available_features = []`

تعبیر این بخش:

- backend برای هر metric 12 نتیجه برگردانده
- payload به صورت positional/list-based بوده، نه با `cell_code`های صریح
- `available_features = []` طبیعی است، چون payload از نوع لیستی عددی بوده و structure دیکشنری feature-based نداشته است

## بخش `run.metadata.summary`

این خلاصه اجرایی run است:

- `source = "openeo"`
- `status = "completed"`
- `cell_count = 12`
- `processed_cell_count = 12`
- `created_observation_count = 12`
- `updated_observation_count = 0`
- `existing_observation_count = 0`
- `failed_metric_count = 0`
- `cluster_count = 2`
- `subdivision_result_id = 1`

معنی عملی:

- همه 12 سلول تازه ساخته و پردازش شده‌اند
- چیزی از قبل reuse نشده
- pipeline بدون failure تا انتها رفته

## بخش `timestamps`

این timestamps جریان کامل pipeline را نشان می‌دهند:

- `queued_at`: زمان queue شدن task
- `started_at`: زمان شروع واقعی task
- `preparing_analysis_grid_at`: زمان شروع ساخت grid
- `analysis_grid_ready_at`: زمان آماده شدن grid
- `analysis_cells_selected_at`: زمان انتخاب cellهای هدف
- `fetching_remote_metrics_at`: زمان شروع fetch از openEO
- `remote_metrics_fetched_at`: زمان تکمیل دریافت metricها
- `observations_persisted_at`: زمان ذخیره observationها در DB
- `clustering_completed_at`: زمان تکمیل clustering
- `completed_at`: زمان پایان کامل pipeline

برای این response:

- start: `2026-05-10T20:17:34.570353+00:00`
- complete: `2026-05-10T20:28:29.469326+00:00`

پس کل فرآیند حدود 10 دقیقه و 55 ثانیه طول کشیده است.

## بخش `stage_details`

این بخش مهم‌ترین قسمت برای debugging و فهم pipeline است.

### `analysis_grid_ready`

```json
{
  "created": true,
  "total_count": 12,
  "created_count": 12,
  "existing_count": 0
}
```

یعنی:

- grid analysis تازه ساخته شده
- 12 سلول جدید ایجاد شده

### `analysis_cells_selected`

```json
{
  "force_refresh": false,
  "total_cell_count": 12,
  "existing_cell_count": 0,
  "cell_count_to_process": 12
}
```

یعنی:

- force refresh فعال نبوده
- هیچ cell cache‌شده‌ای برای reuse وجود نداشته
- هر 12 سلول باید از openEO پردازش می‌شدند

### `fetching_remote_metrics`

این بخش دو چیز را نشان می‌دهد:

- `target_cells`
  - لیست سلول‌هایی که برایشان metric گرفته شده
- `metric_progress`
  - وضعیت پیشرفت metricها

در این response:

- `total_metrics = 3`
- metricهای کامل‌شده:
  - `ndvi`
  - `ndwi`
  - `soil_vv_db`

نکته:

- job_ref `soil_vv_db` در اصل به job مربوط به `soil_vv` map شده، چون `soil_vv_db` metric مشتق‌شده است.

### `remote_metrics_fetched`

این بخش metadata سرویس را بعد از fetch نگه می‌دارد و تأیید می‌کند:

- metricها از openEO آمده‌اند
- هیچ metricی fail نشده
- برای هر metric 12 سلول نتیجه برگشته

### `observations_persisted`

این بخش نشان می‌دهد داده‌ها با موفقیت در DB ذخیره شده‌اند:

- `created_count = 12`
- `updated_count = 0`
- `matched_cell_count = 12`
- `usable_observation_count = 12`
- `fully_null_observation_count = 0`
- `unmatched_db_cell_codes = []`
- `unmatched_payload_cell_codes = []`

این یکی از مهم‌ترین بخش‌های response است، چون ثابت می‌کند:

- matching بین payload و سلول‌های DB کامل بوده
- هیچ observation خالی persist نشده
- تمام cellها usable بوده‌اند

### `clustering_completed`

این بخش خروجی clustering را خلاصه می‌کند:

- `cluster_count = 2`
- `used_cell_count = 12`
- `skipped_cell_count = 0`
- `subdivision_result_id = 1`

و پارامترهای KMeans:

- `max_k = 10`
- `n_init = 10`
- `random_state = 42`
- `selection_strategy = "elbow"`
- `selected_k = 2`

یعنی سیستم با روش elbow، مقدار `K = 2` را بهترین انتخاب دیده است.

## بخش `task`

بخش `task` نسخه task-oriented همین اجرا را نشان می‌دهد.

### `current_stage`

- `current_stage = "completed"`

یعنی دیگر stage فعالی وجود ندارد و task بسته شده است.

### `stages`

این آرایه تاریخچه stageها را نگه می‌دارد:

- `queued`
- `preparing_analysis_grid`
- `analysis_grid_ready`
- `analysis_cells_selected`
- `fetching_remote_metrics`
- `remote_metrics_fetched`
- `observations_persisted`
- `clustering_completed`
- `completed`

این ترتیب دقیق pipeline را نشان می‌دهد.

### `metric_progress`

این بخش برای UI بسیار مفید است:

- `total_metrics = 3`
- `completed_metric_count = 3`
- `failed_metrics = []`
- `active_metric = null`

پس هیچ metric نیمه‌کاره یا fail شده‌ای باقی نمانده است.

### `celery`

این بخش وضعیت Celery task را نشان می‌دهد:

- `state = "SUCCESS"`
- `ready = true`
- `successful = true`
- `failed = false`

و در `info` هم خلاصه اجرایی برگردانده شده:

- 12 سلول پردازش شده
- 12 observation ساخته شده
- 2 cluster تولید شده

## بخش `location`

این بخش context مکانی تحلیل را نشان می‌دهد.

### اطلاعات پایه

- `id = 1`
- `lon = "50.000000"`
- `lat = "50.000000"`
- `input_block_count = 1`

### `farm_boundary`

یک polygon مربعی کوچک اطراف مختصات 50,50 است.

### `block_layout`

در `blocks` دو ورودی دیده می‌شود:

1. block پیش‌فرض:
   - `source = "default"`
   - `block_code = "block-1"`

2. block تولیدشده از remote sensing:
   - `source = "remote_sensing"`
   - `block_code = ""`
   - `needs_subdivision = true`
   - دارای 2 زیر‌بلوک (`cluster-0`, `cluster-1`)

این یعنی سیستم علاوه بر block اولیه، یک layout تحلیلی جدید هم بر اساس داده‌های remote sensing ساخته است.

### `analysis_grid_summary`

- `cell_count = 12`
- `chunk_size_sqm = 900`

یعنی farm boundary به 12 cell با اندازه 900 مترمربع شکسته شده است.

### `satellite_snapshots`

دو snapshot وجود دارد:

1. برای `block-1`
   - `status = "missing"`
   - یعنی برای آن block خاص snapshot مستقلی وجود ندارد

2. برای `block_code = ""`
   - `status = "completed"`
   - `run_id = 1`
   - `cell_count = 12`
   - `resolved_metrics`:
     - `ndvi = 0.686502`
     - `ndwi = -0.598028`
     - `soil_vv_db = -13.374155`

این اعداد همان summary ساده‌ی metrics در کل محدوده هستند.

## بخش `summary`

این بخش خلاصه آماری کل observationها است:

```json
{
  "cell_count": 12,
  "ndvi_mean": 0.686502,
  "ndwi_mean": -0.598028,
  "soil_vv_db_mean": -13.374155
}
```

معنی:

- 12 سلول در summary لحاظ شده‌اند
- میانگین `ndvi` حدود `0.6865`
- میانگین `ndwi` حدود `-0.5980`
- میانگین `soil_vv_db` حدود `-13.3742`

## بخش `cells`

این آرایه، داده خام هر سلول را نگه می‌دارد.

هر item شامل این‌ها است:

- `cell_code`
- `block_code`
- `chunk_size_sqm`
- `centroid_lat`
- `centroid_lon`
- `geometry`
- `temporal_start`
- `temporal_end`
- `ndvi`
- `ndwi`
- `soil_vv`
- `soil_vv_db`
- `metadata`

### مثال از یک cell

برای اولین سلول:

- `cell_code = loc-1__block-farm__chunk-900__r0000c0000`
- `ndvi = 0.6622872683737013`
- `ndwi = -0.583760056230757`
- `soil_vv = 0.0290423126684294`
- `soil_vv_db = -15.369688`

این یعنی این cell هم داده خام خطی Sentinel-1 (`soil_vv`) را دارد، هم نسخه dB آن (`soil_vv_db`).

### `cells[].metadata`

metadata هر سلول شامل این‌ها است:

- `run_id`
- `job_refs`
- `backend_name`
- `backend_url`
- `collections_used`
- `failed_metrics`
- `payload_diagnostics`

این metadata برای traceability خیلی مفید است، چون مشخص می‌کند این observation از کدام run و کدام jobهای openEO آمده است.

## بخش `subdivision_result`

این بخش خروجی اصلی clustering را نشان می‌دهد.

### فیلدهای پایه

- `id = 1`
- `cluster_count = 2`
- `selected_features = ["ndvi", "ndwi", "soil_vv_db"]`
- `skipped_cell_codes = []`

یعنی:

- نتیجه نهایی clustering دو خوشه دارد
- هیچ cellی حذف نشده

### `metadata.scaler_means`

میانگین هر feature قبل از scaling:

- `ndvi = 0.6865018435098507`
- `ndwi = -0.5980279920277772`
- `soil_vv_db = -13.374155250000005`

### `metadata.scaler_scales`

انحراف معیار/scale هر feature:

- `ndvi = 0.018948282260331236`
- `ndwi = 0.012494317547431832`
- `soil_vv_db = 0.87754098540943`

### `metadata.imputer_statistics`

چون imputer از نوع median بوده:

- median `ndvi`
- median `ndwi`
- median `soil_vv_db`

برای این run ذخیره شده‌اند، حتی اگر در این مورد missing value نداشته‌ایم.

### `metadata.missing_value_counts`

```json
{
  "ndvi": 0,
  "ndwi": 0,
  "soil_vv_db": 0
}
```

این خیلی مهم است، چون نشان می‌دهد برای featureهای clustering هیچ داده‌ی گم‌شده‌ای وجود نداشته است.

### `metadata.inertia_curve`

این آرایه SSE را برای Kهای مختلف نگه می‌دارد:

- `k=1 => sse=36`
- `k=2 => sse=14.987928`
- ...
- `k=10 => sse=0.140512`

سیستم از این curve برای انتخاب elbow استفاده کرده و در نهایت `k=2` را برداشته است.

### `metadata.cluster_summaries`

خلاصه هر cluster:

- `cluster-0`
  - `cell_count = 9`
  - `centroid_lat = 49.999995`
  - `centroid_lon = 50.000223`

- `cluster-1`
  - `cell_count = 3`
  - `centroid_lat = 50.000174`
  - `centroid_lon = 49.99985`

یعنی تقسیم‌بندی نهایی مزرعه به دو زیر‌بلوک 9تایی و 3تایی انجام شده است.

### `assignments`

این آرایه برای هر cell مشخص می‌کند:

- عضو کدام cluster است
- raw feature value آن چیست
- scaled feature value آن چیست

مثلاً:

- `loc-1__block-farm__chunk-900__r0000c0000`
  - `cluster_label = 1`
  - `raw_feature_values.ndvi = 0.662287...`
  - `raw_feature_values.ndwi = -0.583760...`
  - `raw_feature_values.soil_vv_db = -15.369688`

این بخش برای تحلیل این‌که چرا یک cell داخل یک cluster خاص افتاده بسیار مفید است.

## بخش `pagination`

این بخش صفحه‌بندی را برای دو لیست نشان می‌دهد:

- `cells`
- `assignments`

در هر دو مورد:

- `page = 1`
- `page_size = 100`
- `total_items = 12`
- `total_pages = 1`
- `has_next = false`
- `has_previous = false`

یعنی تمام داده‌ها در یک صفحه جا شده‌اند.

## نتیجه نهایی این response

اگر بخواهیم این response را در یک جمله خلاصه کنیم:

- سیستم در تاریخ `2026-05-10` یک تحلیل سنجش‌ازدور موفق روی 12 سلول grid انجام داده، metricهای `ndvi`, `ndwi`, `soil_vv_db` را بدون missing value ذخیره کرده، و مزرعه را با روش elbow-based KMeans به 2 زیر‌بلوک تقسیم کرده است.

## مهم‌ترین فیلدها برای استفاده عملی

اگر فقط چند بخش برای frontend یا debugging مهم باشد، این‌ها از همه مهم‌ترند:

- `data.status`
- `data.run.selected_features`
- `data.run.metadata.summary`
- `data.run.metadata.stage_details.observations_persisted`
- `data.summary`
- `data.cells`
- `data.subdivision_result.metadata.cluster_summaries`
- `data.subdivision_result.assignments`

## برداشت فنی از سلامت این run

این response از نظر pipeline یک run سالم را نشان می‌دهد:

- status نهایی `completed` است
- Celery در `SUCCESS` است
- هیچ metricی fail نشده
- همه cellها match شده‌اند
- هیچ observationی null کامل نیست
- clustering روی همه سلول‌ها اجرا شده
- output نهایی subdivision ساخته شده

پس این response نمونه‌ی یک اجرای موفق و کامل remote sensing subdivision است.
