# ارتباط `farm_data`، `location_data` و فیلدهای وابسته

این سند ساختار فعلی داده‌ها در پروژه را توضیح می‌دهد و هم‌زمان دو قاعده کسب‌وکاری مورد تایید را به‌عنوان مبنای توسعه ثبت می‌کند:

1. برای محاسبه‌های عمومی هوش مصنوعی مثل `RAG` و `crop_simulation` باید از داده‌های تجمیع‌شده کل بلوک‌های بزرگِ تعریف‌شده توسط کشاورز استفاده شود.
2. اگر برای یک مزرعه هیچ بلاکی تعریف نشده باشد، حالت پیش‌فرض باید شامل `1 بلوک بزرگ` و `1 بلوک کوچک‌تر داخل همان بلوک بزرگ` باشد.

این سند بر اساس ساختار فعلی کد در `farm_data/`, `location_data/`, `weather/`, `rag/`, `crop_simulation/`, `irrigation/` و `plant/` نوشته شده است.

---

## 1) نقش هر app در معماری داده

### `farm_data`

این app رکورد canonical مزرعه برای مصرف لایه AI را نگه می‌دارد. مهم‌ترین رکورد آن `SensorData` است.

وظیفه‌های اصلی:

- نگه‌داری شناسه مزرعه (`farm_uuid`)
- اتصال مزرعه به `SoilLocation`
- نگه‌داری payload سنسورها
- نگه‌داری snapshot گیاه‌ها برای مصرف AI
- اتصال به روش آبیاری و آب‌وهوا
- ساخت خروجی تجمیعی مزرعه با `get_farm_details()`

### `location_data`

این app مدل مکانی مزرعه و ساختار بلاک‌ها را نگه می‌دارد.

وظیفه‌های اصلی:

- نگه‌داری مرکز هندسی مزرعه (`SoilLocation`)
- نگه‌داری مرز کل مزرعه (`farm_boundary`)
- نگه‌داری بلاک‌های اصلی کشاورز (`block_layout.blocks`)
- نگه‌داری subdivision هر بلاک (`BlockSubdivision`)
- نگه‌داری grid سلول‌ها و داده‌های سنجش‌ازدور
- ساخت snapshotهای بلاکی و تجمیعی برای مصرف downstream

### `weather`

پیش‌بینی آب‌وهوا را برای هر `SoilLocation` نگه می‌دارد. مزرعه از طریق `center_location` به forecast متصل می‌شود.

### `plant`

مدل اصلی گیاه‌ها را نگه می‌دارد، اما برای لایه AI در `farm_data` یک read-model به نام `PlantCatalogSnapshot` ساخته شده است.

### `irrigation`

جدول مرجع روش‌های آبیاری را نگه می‌دارد و `farm_data.SensorData` به یکی از آن‌ها متصل می‌شود.

### `rag` و `crop_simulation`

این دو app مصرف‌کننده داده‌اند، نه مالک اصلی داده. یعنی داده اصلی را از `farm_data`, `location_data`, `weather`, `plant` و snapshotهای تجمیعی می‌گیرند.

---

## 2) موجودیت‌های اصلی و ارتباط بین آن‌ها

نمای کلی:

```text
Farm (business id = farm_uuid)
   |
   v
farm_data.SensorData
   |-- FK --> location_data.SoilLocation
   |-- FK --> weather.WeatherForecast (optional cached/latest link)
   |-- FK --> irrigation.IrrigationMethod (optional)
   |-- JSON --> sensor_payload
   |-- M2M legacy --> plant.Plant
   |-- 1:N canonical --> farm_data.FarmPlantAssignment --> farm_data.PlantCatalogSnapshot

location_data.SoilLocation
   |-- JSON --> farm_boundary
   |-- int  --> input_block_count
   |-- JSON --> block_layout
   |-- 1:N --> BlockSubdivision
   |-- 1:N --> RemoteSensingRun
   |-- 1:N --> AnalysisGridCell
   |-- 1:N --> WeatherForecast
   |-- 1:N --> NdviObservation

BlockSubdivision
   |-- belongs to --> SoilLocation
   |-- identifies --> one main block (block_code)
   |-- stores --> source_boundary / centroid_points / subdivision_summary

RemoteSensingRun
   |-- belongs to --> SoilLocation
   |-- scoped by --> block_code
   |-- produces --> AnalysisGridObservation + RemoteSensingSubdivisionResult

RemoteSensingSubdivisionResult
   |-- belongs to --> RemoteSensingRun
   |-- scoped by --> block_code
   |-- produces --> RemoteSensingClusterBlock + RemoteSensingClusterAssignment
```

---

## 3) تعریف دقیق موجودیت‌ها

## 3.1) `farm_data.SensorData`

این مدل در عمل رکورد اصلی مزرعه برای مصرف AI است.

فیلدهای مهم:

- `farm_uuid`
  - شناسه یکتای مزرعه
  - primary key
  - شناسه business-level بین appها

- `center_location`
  - `ForeignKey` به `location_data.SoilLocation`
  - هر مزرعه دقیقاً به یک location مرکزی وصل است
  - نام legacy آن در بعضی جاها هنوز به‌صورت `location` دیده می‌شود، ولی canonical همان `center_location` است

- `weather_forecast`
  - `ForeignKey` اختیاری به `weather.WeatherForecast`
  - آخرین forecast مرتبط با location را cache می‌کند
  - اگر خالی باشد، سرویس‌ها معمولاً از روی `center_location.weather_forecasts` آخرین رکورد را پیدا می‌کنند

- `sensor_payload`
  - `JSONField`
  - ساختار چندسنسوری دارد
  - نمونه:

```json
{
  "sensor-7-1": {
    "soil_moisture": 22.4,
    "soil_temperature": 18.1,
    "nitrogen": 31.0
  },
  "leaf-sensor": {
    "leaf_wetness": 11.0,
    "leaf_temperature": 19.3
  }
}
```

- `plants`
  - relation قدیمی به `plant.Plant`
  - برای سازگاری عقب‌رو نگه داشته شده
  - canonical برای AI نیست

- `irrigation_method`
  - `ForeignKey` اختیاری به `irrigation.IrrigationMethod`

- `created_at`, `updated_at`
  - زمان ساخت و آخرین به‌روزرسانی رکورد مزرعه

نکته مهم:

- `SensorData` مالک geometry مزرعه نیست.
- geometry و بلاک‌ها در `location_data` نگه‌داری می‌شوند.
- `SensorData` فقط به `SoilLocation` وصل می‌شود.

---

## 3.2) `farm_data.PlantCatalogSnapshot`

این مدل snapshot خواندنی از کاتالوگ گیاه Backend است تا سرویس‌های AI مستقیم به app اصلی گیاه وابسته نباشند.

فیلدهای مهم:

- `backend_plant_id`
- `name`
- `slug`
- `icon`
- `description`
- `metadata`
- `health_profile`
- `irrigation_profile`
- `growth_profile`
- `growth_stage`, `growth_stages`
- `is_active`
- `source_updated_at`

این مدل source of truth اصلی گیاه در کل سیستم نیست، ولی source of truth لایه AI برای گیاهِ sync‌شده است.

---

## 3.3) `farm_data.FarmPlantAssignment`

رابط canonical بین مزرعه و snapshot گیاه است.

فیلدهای مهم:

- `farm` -> `SensorData`
- `plant` -> `PlantCatalogSnapshot`
- `position`
- `stage`
- `metadata`

کاربرد:

- تعیین ترتیب گیاه‌های مزرعه
- تعیین stage اختصاصی برای گیاه در همان مزرعه
- حذف وابستگی مستقیم AI به `SensorData.plants`

---

## 3.4) `farm_data.SensorParameter`

تعریف metadata هر پارامتر سنسوری است.

فیلدهای مهم:

- `sensor_key`
- `code`
- `name_fa`
- `unit`
- `data_type`
- `metadata`

کاربرد:

- ساخت schema داینامیک برای `sensor_payload`
- ثبت سنسورهای جدید بدون migration

---

## 3.5) `location_data.SoilLocation`

این مدل نقطه مرکزی و ساختار فضایی مزرعه را نگه می‌دارد.

فیلدهای مهم:

- `latitude`
- `longitude`
  - مرکز هندسی مزرعه
  - روی این دو فیلد constraint یکتایی وجود دارد

- `task_id`
  - شناسه taskهای async

- `farm_boundary`
  - مرز کل مزرعه
  - معمولاً به شکل GeoJSON polygon ذخیره می‌شود

- `input_block_count`
  - تعداد بلاک‌های اصلی تعریف‌شده توسط کشاورز

- `block_layout`
  - ساختار کامل بلاک‌های اصلی و زیر‌بلاک‌های داخلی
  - مهم‌ترین فیلد spatial-read-model برای AI

- `created_at`, `updated_at`

نکته مهم:

- `SoilLocation` خود مزرعه نیست.
- `SoilLocation` نمای مکانی مزرعه است.
- مزرعه business-level با `farm_uuid` در `SensorData` شناسایی می‌شود.

---

## 3.6) `location_data.BlockSubdivision`

این مدل subdivision یک بلاک اصلی را نگه می‌دارد.

فیلدهای مهم:

- `soil_location`
- `block_code`
- `source_boundary`
- `chunk_size_sqm`
- `grid_points`
- `centroid_points`
- `grid_point_count`
- `centroid_count`
- `status`
- `metadata`
- `elbow_plot`

تفسیر:

- هر رکورد `BlockSubdivision` به یک `main block` تعلق دارد.
- `block_code` همان شناسه بلاک اصلی کشاورز است.
- `centroid_points` معمولاً نماینده زیر‌بلاک‌های داخلی است.

---

## 3.7) `location_data.RemoteSensingRun`

هر run سنجش‌ازدور برای یک location و معمولاً برای یک `block_code` اجرا می‌شود.

فیلدهای مهم:

- `soil_location`
- `block_subdivision`
- `block_code`
- `provider`
- `chunk_size_sqm`
- `temporal_start`
- `temporal_end`
- `status`
- `metadata`
- `error_message`

اگر `block_code` خالی باشد، run در سطح کل farm/location تفسیر می‌شود.
اگر `block_code` مقدار داشته باشد، run مربوط به همان بلاک اصلی است.

---

## 3.8) `location_data.AnalysisGridCell`

سلول‌های شبکه تحلیلی برای سنجش‌ازدور هستند.

فیلدهای مهم:

- `soil_location`
- `block_subdivision`
- `block_code`
- `cell_code`
- `chunk_size_sqm`
- `geometry`
- `centroid_lat`
- `centroid_lon`

این‌ها لایه پایین‌تر از main block هستند و برای محاسبات remote sensing استفاده می‌شوند.

---

## 3.9) `location_data.AnalysisGridObservation`

خروجی متریک‌های سنجش‌ازدور برای هر cell در یک بازه زمانی است.

فیلدهای مهم:

- `cell`
- `run`
- `temporal_start`
- `temporal_end`
- `ndvi`
- `ndwi`
- `soil_vv`
- `soil_vv_db`
- `dem_m`
- `slope_deg`
- `metadata`

این داده‌ها raw یا نیمه‌تجمیع‌شده‌اند و هنوز در سطح مزرعه نیستند.

---

## 3.10) `location_data.RemoteSensingSubdivisionResult`

نتیجه خوشه‌بندی داده‌محور برای یک run و یک بلاک است.

فیلدهای مهم:

- `run`
- `soil_location`
- `block_subdivision`
- `block_code`
- `chunk_size_sqm`
- `cluster_count`
- `selected_features`
- `metadata`

---

## 3.11) `location_data.RemoteSensingClusterBlock`

این مدل زیر‌بلاک‌های KMeans/cluster-based را نگه می‌دارد.

فیلدهای مهم:

- `uuid`
- `result`
- `soil_location`
- `block_subdivision`
- `block_code`
- `sub_block_code`
- `cluster_label`
- `centroid_lat`
- `centroid_lon`
- `geometry`
- `cell_count`
- `cell_codes`
- `metadata`

نکته مهم:

- این زیر‌بلاک‌ها با `main block` فرق دارند.
- `block_code` = بلاک اصلی والد
- `sub_block_code` = زیر‌بلاک داخلی ساخته‌شده با خوشه‌بندی

---

## 3.12) `weather.WeatherForecast`

پیش‌بینی هواشناسی برای یک `SoilLocation` است.

فیلدهای مهم:

- `location`
- `forecast_date`
- `temperature_min`
- `temperature_max`
- `temperature_mean`
- `precipitation`
- `precipitation_probability`
- `humidity_mean`
- `wind_speed_max`
- `et0`
- `weather_code`
- `fetched_at`

نکته:

- آب‌وهوا به location وصل است، نه مستقیم به farm_uuid.
- `SensorData.weather_forecast` فقط shortcut/cache است.

---

## 3.13) `irrigation.IrrigationMethod`

مدل مرجع روش آبیاری است.

فیلدهای مهم:

- `name`
- `category`
- `description`
- `water_efficiency_percent`
- `water_pressure_required`
- `flow_rate`
- `coverage_area`
- `soil_type`
- `climate_suitability`

هر مزرعه می‌تواند صفر یا یک روش آبیاری انتخاب‌شده داشته باشد.

---

## 4) منبع اصلی هر نوع داده

| نوع داده | مالک اصلی | فیلد/مدل canonical | توضیح |
|---|---|---|---|
| شناسه مزرعه | `farm_data` | `SensorData.farm_uuid` | شناسه business-level |
| مرکز مکانی مزرعه | `location_data` | `SoilLocation.latitude/longitude` | centroid هندسی |
| مرز کل مزرعه | `location_data` | `SoilLocation.farm_boundary` | شکل کل زمین |
| تعداد بلاک‌های اصلی | `location_data` | `SoilLocation.input_block_count` | تعداد بلاک‌های کشاورز |
| ساختار بلاک‌ها | `location_data` | `SoilLocation.block_layout` | بلاک‌های اصلی + sub-block metadata |
| تعریف subdivision هر بلاک | `location_data` | `BlockSubdivision` | state و مرز هر بلاک |
| داده سنسور | `farm_data` | `SensorData.sensor_payload` | source مستقیم از مزرعه/سنسور |
| schema پارامترهای سنسور | `farm_data` | `SensorParameter` | metadata فیلدهای sensor_payload |
| گیاه‌های مزرعه | `farm_data` | `FarmPlantAssignment` | canonical برای AI |
| catalog گیاه | `farm_data` | `PlantCatalogSnapshot` | snapshot sync شده |
| forecast هوا | `weather` | `WeatherForecast` | در سطح location |
| داده سنجش‌ازدور سلولی | `location_data` | `AnalysisGridObservation` | خام/نیمه‌خام |
| تجمیع بلاک اصلی | `location_data` | snapshotهای `satellite_snapshot.py` | برای AI |
| روش آبیاری | `irrigation` | `IrrigationMethod` | جدول مرجع |

---

## 5) دو سطح بلاک که نباید با هم قاطی شوند

در این پروژه دو سطح جدا داریم:

### سطح اول: `main block`

این همان بلاک بزرگی است که کشاورز تعریف می‌کند.

محل نگه‌داری:

- `SoilLocation.block_layout["blocks"]`
- `BlockSubdivision.block_code`
- `RemoteSensingRun.block_code`

مثال:

- `block-1`
- `north-field`
- `greenhouse-a`

### سطح دوم: `sub block`

این زیر‌بلاک داخلی است که یا:

- از subdivision اولیه ساخته می‌شود
- یا از خوشه‌بندی داده‌محور remote sensing/KMeans ساخته می‌شود

محل نگه‌داری:

- `BlockSubdivision.centroid_points`
- `block_layout["blocks"][i]["sub_blocks"]`
- `RemoteSensingClusterBlock`
- `satellite_snapshot["satellite_sub_blocks"]`
- `satellite_snapshot["sensor_sub_blocks"]`

مثال:

- `sub-block-1`
- `cluster-0`
- `cluster-1`

قانون مهم:

- `main block` سطح تصمیم‌گیری کشاورز است.
- `sub block` سطح تحلیل داخلی سیستم است.
- برای AI عمومی باید جمع‌بندی روی `main block`ها انجام شود، نه این‌که مستقیماً یک `sub block` به‌عنوان نماینده کل مزرعه در نظر گرفته شود.

---

## 6) ساختار `block_layout`

`SoilLocation.block_layout` مهم‌ترین read-model فضایی برای کل سیستم است.

شکل عمومی:

```json
{
  "input_block_count": 1,
  "default_full_farm": true,
  "algorithm_status": "pending",
  "blocks": [
    {
      "block_code": "block-1",
      "order": 1,
      "source": "default",
      "boundary": {},
      "needs_subdivision": null,
      "sub_blocks": []
    }
  ]
}
```

کلیدهای مهم:

- `input_block_count`
  - تعداد بلاک‌های اصلی کشاورز

- `default_full_farm`
  - اگر فقط یک بلاک اصلی وجود داشته باشد معمولاً `true` است

- `algorithm_status`
  - وضعیت محاسبات بعدی روی layout
  - معمولاً `pending` یا `completed`

- `blocks`
  - لیست بلاک‌های اصلی

هر آیتم `blocks`:

- `block_code`
  - شناسه یکتای بلاک اصلی

- `order`
  - ترتیب نمایش/تحلیل

- `source`
  - معمولاً `input` یا `default`

- `boundary`
  - مرز همان بلاک اصلی

- `needs_subdivision`
  - آیا این بلاک نیاز به subdivision داخلی دارد

- `sub_blocks`
  - لیست زیر‌بلاک‌های داخلی

در بعضی مرحله‌ها این layout با فیلدهای تکمیلی enrich می‌شود:

- `subdivision_summary`
- `analysis_grid_summary`
- `aggregated_metrics`

---

## 7) جریان ساخت و به‌روزرسانی داده

## 7.1) وقتی `POST /api/farm-data/` صدا زده می‌شود

این endpoint مزرعه را از دید AI upsert می‌کند.

جریان:

1. `farm_uuid` و `farm_boundary` دریافت می‌شود.
2. در `resolve_center_location_from_boundary()` centroid مزرعه محاسبه می‌شود.
3. یک `SoilLocation` بر اساس centroid ساخته یا پیدا می‌شود.
4. `input_block_count` و `block_layout` اولیه تنظیم می‌شوند.
5. اگر ایجاد جدید باشد و فقط یک بلاک وجود داشته باشد، برای `block-1` یک subdivision اولیه هم می‌تواند ساخته شود.
6. forecast آب‌وهوا از روی location resolve می‌شود.
7. رکورد `SensorData` ساخته یا آپدیت می‌شود.
8. payload سنسورها merge می‌شود.
9. plant assignmentها و irrigation method در صورت ارسال sync می‌شوند.

نکته:

- این endpoint بیشتر مزرعه را به `SoilLocation` وصل می‌کند.
- تعریف دقیق مرز هر main block معمولاً از مسیر `location_data` می‌آید، نه از `farm_data`.

---

## 7.2) وقتی `POST /api/location-data/` صدا زده می‌شود

این endpoint ساختار مزرعه از دید spatial را ذخیره می‌کند.

جریان:

1. `lat`, `lon`, `farm_boundary`, `blocks` دریافت می‌شود.
2. `SoilLocation` بر اساس همان lat/lon ذخیره یا پیدا می‌شود.
3. `input_block_count` و `block_layout` با لیست `blocks` به‌روزرسانی می‌شوند.
4. `_sync_defined_blocks()` برای هر `main block` یک `BlockSubdivision` با `status="defined"` می‌سازد یا به‌روزرسانی می‌کند.
5. اگر بلاکی حذف شده باشد، subdivision و state تحلیل قبلی آن پاک می‌شود.
6. اگر boundary بلاکی تغییر کند، state تحلیل سنجش‌ازدور آن invalidate می‌شود.

پس:

- `location_data` مالک تعریف بلاک‌های اصلی است.
- `farm_data` مالک رکورد مزرعه برای AI است.

---

## 7.3) وقتی `get_farm_details()` ساخته می‌شود

این تابع خروجی canonical مزرعه را برای appهای دیگر تولید می‌کند.

خروجی شامل این بخش‌هاست:

- `center_location`
- `weather`
- `sensor_payload`
- `sensor_schema`
- `soil`
- `plant_ids`
- `plants`
- `plant_assignments`
- `irrigation_method`
- `created_at`, `updated_at`

بخش `soil` از ادغام این دو منبع ساخته می‌شود:

- snapshotهای سنجش‌ازدور
- sensor_payload

قاعده فعلی merge:

- اگر برای یک metric داده سنسور وجود داشته باشد، روی داده remote sensing override می‌شود.
- اگر چند سنسور مقدار متعارض بدهند:
  - برای داده عددی average گرفته می‌شود
  - برای داده غیرعددی distinct values برمی‌گردد

---

## 8) snapshotهای مکانی و معنای آن‌ها

در `location_data/satellite_snapshot.py` چند نوع snapshot مهم ساخته می‌شود:

### `build_location_satellite_snapshot(location, block_code="")`

یک snapshot برای یک scope خاص می‌سازد:

- اگر `block_code` خالی باشد: snapshot عمومی location/farm
- اگر `block_code` پر باشد: snapshot همان main block

### `build_location_block_satellite_snapshots(location)`

برای همه `main block`های ثبت‌شده snapshot می‌سازد.

خروجی هر بلاک شامل این‌هاست:

- `resolved_metrics`
- `metric_sources`
- `satellite_metrics`
- `sensor_metrics`
- `sensor_sub_blocks`
- `satellite_sub_blocks`
- `sub_block_count`

### `build_farmer_block_aggregated_snapshot(location)`

خروجی تجمیعی سطح مزرعه بر اساس همه `main block`های کشاورز است.

این مهم‌ترین تابع برای قانون کسب‌وکاری تو است، چون:

- اگر چند main block وجود داشته باشد، میانگین آن‌ها را در سطح farmer-block می‌سازد
- `aggregation_strategy` آن `farmer_block_mean` است
- برای AI عمومی از نظر مفهومی این همان سطح درست مصرف داده است

---

## 9) قانون canonical برای محاسبه‌های عمومی AI

برای سرویس‌های عمومی هوش مصنوعی مثل:

- `RAG`
- `crop_simulation`
- `fertilization`
- `irrigation`
- `farm_alerts`
- هر سرویسی که قرار است از کل وضعیت مزرعه حرف بزند

باید سطح داده canonical این باشد:

### سطح مجاز

- کل مزرعه بر اساس تجمیع `main block`های کشاورز

### تابع پیشنهادی canonical

- `build_farmer_block_aggregated_snapshot(location, sensor_payload=...)`

### دلیل

- این تابع داده‌ها را از سطح `main block` بالا می‌آورد
- اگر مزرعه چند بلاک اصلی داشته باشد، یک بلاک یا یک sub-block به اشتباه نماینده کل مزرعه نمی‌شود
- با خواسته کسب‌وکاری تو هم‌راستا است

### سطحی که نباید مبنای AI عمومی باشد

- یک `sub_block` تکی
- یک `cluster-0` یا `cluster-1` به‌تنهایی
- snapshot خام location بدون درنظرگرفتن بلاک‌های اصلی کشاورز، مگر فقط به‌عنوان fallback

---

## 10) وضعیت پیش‌فرض وقتی بلاک تعریف نشده است

قاعده مورد تایید:

- اگر کشاورز هنوز بلاک‌ها را تعریف نکرده باشد:
  - یک `main block` پیش‌فرض وجود دارد
  - داخل آن هم یک `sub block` پیش‌فرض وجود دارد

### نمایش منطقی مورد انتظار

```json
{
  "input_block_count": 1,
  "default_full_farm": true,
  "algorithm_status": "pending",
  "blocks": [
    {
      "block_code": "block-1",
      "order": 1,
      "source": "default",
      "boundary": {},
      "needs_subdivision": false,
      "sub_blocks": [
        {
          "sub_block_code": "sub-block-1"
        }
      ]
    }
  ]
}
```

### تفسیر این قانون

- `block-1` نماینده کل مزرعه است
- `sub-block-1` حداقل واحد داخلی برای این‌که downstreamها همیشه ساختار یکنواخت ببینند

### نکته درباره وضعیت فعلی کد

کد فعلی به‌صورت پیش‌فرض `1 main block` را به‌خوبی می‌سازد، اما وجود `1 sub-block` پیش‌فرض باید به‌عنوان قانون توسعه حفظ و در همه entry pointها یکدست شود.

---

## 11) ارتباط این داده‌ها با appهای دیگر

## 11.1) `rag`

`rag` معمولاً context مزرعه را از `farm_data` می‌گیرد.

نقاط مهم:

- `rag.chat.build_rag_context()` از `get_farm_details()` استفاده می‌کند
- `rag.user_data.build_user_soil_text()` علاوه بر داده‌های مزرعه، از:
  - `build_farmer_block_aggregated_snapshot()`
  - `build_location_block_satellite_snapshots()`
  استفاده می‌کند

نتیجه:

- برای RAG عمومی، سطح درست context باید تجمیع `main block`ها باشد
- جزئیات بلاکی و زیر‌بلاکی فقط برای explanation تکمیلی مناسب‌اند

## 11.2) `crop_simulation`

`crop_simulation` از این داده‌ها استفاده می‌کند:

- `SensorData`
- `center_location`
- forecastهای هوا
- snapshotهای خاک/سنجش‌ازدور
- plant profile
- irrigation method

قاعده مورد انتظار:

- اگر خروجی برای کل مزرعه است، ورودی خاک/سنسور باید از تجمیع `main block`های کشاورز بیاید
- نه از یک location snapshot ساده یا یک sub-block خاص

## 11.3) `weather`

سرویس‌های هواشناسی به `SensorData.center_location` متکی هستند و forecast را از `WeatherForecast`های همان location می‌خوانند.

## 11.4) `soile`

تحلیل‌های خاک و anomaly detection از `load_farm_context()` و snapshotهای location استفاده می‌کنند. برای use-caseهای farm-wide، باید همان rule تجمیع `main block`ها رعایت شود.

## 11.5) `farm_alerts`

این app از `load_farm_context()` و `get_farm_details()` استفاده می‌کند. بنابراین هر تغییری در canonical farm context مستقیماً روی alertها اثر می‌گذارد.

---

## 12) تفاوت `farm_boundary` با `block boundary`

این دو نباید با هم اشتباه شوند:

### `farm_boundary`

- مرز کل زمین
- در `SoilLocation.farm_boundary`
- فقط یکی برای هر location

### `blocks[i].boundary`

- مرز هر بلاک اصلی کشاورز
- در `SoilLocation.block_layout["blocks"]`
- به‌ازای هر main block یک boundary

نتیجه:

- `farm_boundary` = outer shell کل مزرعه
- `block boundary` = تقسیم داخلی همان مزرعه

---

## 13) تفاوت `center_location` با `farm_uuid`

### `farm_uuid`

- شناسه business-level مزرعه
- در `SensorData`
- چیزی است که APIهای AI بیشتر با آن کار می‌کنند

### `center_location`

- شناسه مکانی centroid-based
- در `SoilLocation`
- چیزی است که weather, remote sensing, block layout و geometry به آن وصل‌اند

یک `farm_uuid` به یک `center_location` وصل می‌شود، اما معنا و مسئولیتشان متفاوت است:

- `farm_uuid` = هویت مزرعه
- `center_location` = هویت مکانی مزرعه

---

## 14) فیلدهایی که downstreamها باید canonical از آن‌ها بخوانند

اگر سرویسی بخواهد داده مزرعه را بخواند، اولویت canonical این‌طور است:

### هویت مزرعه

- `SensorData.farm_uuid`

### geometry و ساختار بلاک

- `SensorData.center_location`
- `SensorData.center_location.farm_boundary`
- `SensorData.center_location.block_layout`

### داده سنسور

- `SensorData.sensor_payload`

### schema سنسور

- `farm_data.SensorParameter`

### گیاه

- `FarmPlantAssignment` + `PlantCatalogSnapshot`

### آب‌وهوا

- `SensorData.weather_forecast` اگر موجود بود
- در غیر این صورت `center_location.weather_forecasts`

### summary خاک/remote sensing برای کل مزرعه

- `build_farmer_block_aggregated_snapshot(...)`

### summary برای هر main block

- `build_location_block_satellite_snapshots(...)`

### summary برای زیر‌بلاک‌ها

- `satellite_sub_blocks` و `sensor_sub_blocks`

---

## 15) نمونه خلاصه مفهومی برای یک مزرعه

```text
farm_uuid = شناسه اصلی مزرعه
center_location = centroid و ساختار spatial مزرعه
farm_boundary = مرز کل زمین
block_layout = بلاک‌های اصلی تعریف‌شده توسط کشاورز
block_subdivisions = وضعیت subdivision هر بلاک اصلی
analysis_grid = سلول‌های داخلی برای سنجش‌ازدور
remote_sensing = متریک‌های سلولی و تجمیع‌شده
sensor_payload = سنسورهای واقعی نصب‌شده در مزرعه
plants = گیاه‌های sync شده برای AI
weather = forecastهای location
irrigation_method = روش آبیاری انتخاب‌شده
AI general context = farmer-block aggregated snapshot + sensor payload + weather + plant + irrigation
```

---

## 16) جمع‌بندی نهایی

اگر بخواهیم یک قانون ساده و پایدار برای کل سیستم تعریف کنیم:

- `farm_data` مالک رکورد AI-facing مزرعه است.
- `location_data` مالک geometry، بلاک‌ها، subdivision و remote sensing است.
- `weather` مالک forecastهای location است.
- `plant` و snapshotهای آن مالک context گیاهی مزرعه‌اند.
- `irrigation` مالک روش آبیاری است.

و از نظر محاسبات عمومی AI:

- سطح تصمیم‌گیری باید `کل main block`های کشاورز باشد.
- `sub_block`ها فقط جزئیات داخلی و تحلیلی هستند.
- اگر بلاکی تعریف نشده بود، مدل ذهنی و داده‌ای پیش‌فرض باید `1 main block + 1 sub-block داخلی` باشد.

