# توضیح `location_data/apps.py` و `farm_data/apps.py`

این فایل یک توضیح کوتاه ولی کاربردی از دو فایل تنظیمات اپ Django در پروژه می‌دهد:

- `location_data/apps.py`
- `farm_data/apps.py`

همچنین برای فهم بهتر، به فیلدهای مهم مدل‌های مرتبط هم اشاره می‌کند تا معلوم شود این دو app در عمل چه داده‌هایی را مدیریت می‌کنند.

---

## 1) فایل `location_data/apps.py`

این فایل AppConfig مربوط به اپ `location_data` را تعریف می‌کند.

کلاس اصلی:

```python
class SoilDataConfig(AppConfig):
```

### فیلدها و بخش‌ها

#### `default_auto_field = "django.db.models.BigAutoField"`

- مشخص می‌کند اگر در مدل‌های این اپ برای primary key چیزی تعریف نشده باشد، Django به‌صورت پیش‌فرض از `BigAutoField` استفاده کند.
- `BigAutoField` یک شناسه عددی auto-increment بزرگ است.
- این گزینه بیشتر برای مدل‌هایی مفید است که قرار است رکوردهای زیادی داشته باشند.

#### `name = "location_data"`

- نام کامل اپ Django است.
- Django با این مقدار اپ را register می‌کند.
- این مقدار باید با مسیر ماژول اپ یکی باشد.

#### `verbose_name = "Soil Data (SoilGrids)"`

- نام نمایشی اپ در Django admin یا جاهایی است که Django نام انسانی اپ را نشان می‌دهد.
- این مقدار بیشتر جنبه نمایشی دارد و روی منطق برنامه اثر مستقیم ندارد.

---

## propertyها و سرویس‌ها در `location_data/apps.py`

این فایل فقط metadata اپ را نگه نمی‌دارد؛ دو سرویس reusable هم از طریق AppConfig در اختیار بقیه پروژه می‌گذارد.

### `@cached_property def ndvi_health_service(self)`

- این property یک نمونه از `NdviHealthService` می‌سازد.
- import آن از فایل `.ndvi` انجام می‌شود.
- به دلیل `cached_property` فقط یک بار ساخته می‌شود و بعد همان instance دوباره استفاده می‌شود.

کاربرد:

- برای تحلیل یا سرویس‌های مرتبط با NDVI
- جلوگیری از ساخت مکرر object

### `@cached_property def soil_data_adapter(self)`

این property adapter مناسب برای داده خاک را بر اساس تنظیمات پروژه انتخاب می‌کند.

دو adapter پشتیبانی می‌شوند:

- `SoilGridsAdapter`
- `MockSoilDataAdapter`

#### منطق انتخاب provider

مقدار provider از این setting خوانده می‌شود:

```python
settings.SOIL_DATA_PROVIDER
```

اگر وجود نداشته باشد، مقدار پیش‌فرض:

```python
"mock"
```

#### حالت اول: `provider == "soilgrids"`

در این حالت:

- از `SoilGridsAdapter` استفاده می‌شود
- timeout آن از این setting می‌آید:

```python
settings.SOILGRIDS_TIMEOUT_SECONDS
```

اگر این setting هم نباشد، مقدار پیش‌فرض:

```python
60
```

یعنی درخواست به provider واقعی SoilGrids حداکثر 60 ثانیه صبر می‌کند.

#### حالت دوم: `provider == "mock"`

در این حالت:

- از `MockSoilDataAdapter` استفاده می‌شود
- delay آن از این setting می‌آید:

```python
settings.SOIL_MOCK_DELAY_SECONDS
```

اگر این setting هم نباشد، مقدار پیش‌فرض:

```python
0.8
```

یعنی adapter تستی/نمایشی با تاخیر مصنوعی 0.8 ثانیه کار می‌کند.

#### حالت نامعتبر

اگر `SOIL_DATA_PROVIDER` چیزی غیر از `soilgrids` یا `mock` باشد:

- `ValueError` رخ می‌دهد
- یعنی config پروژه اشتباه است و provider شناخته نشده

---

## ارتباط `location_data/apps.py` با فیلدهای واقعی داده

این فایل خودش مدل تعریف نمی‌کند، اما به‌صورت مستقیم برای کار با مدل‌های اپ `location_data` استفاده می‌شود؛ مهم‌ترین آن‌ها این‌ها هستند:

- `location_data.models.SoilLocation`
- `location_data.models.SoilDepthData`
- `location_data.models.NdviObservation`

### فیلدهای مهم `SoilLocation`

#### `latitude`

- عرض جغرافیایی مرکز زمین
- نوع آن `DecimalField` است
- روی آن index وجود دارد
- این نقطه معمولاً مرکز هندسی مزرعه است، نه لزوماً یکی از گوشه‌های مرز

#### `longitude`

- طول جغرافیایی مرکز زمین
- مثل `latitude` برای lookup و resolve کردن داده‌های خاک استفاده می‌شود

#### `task_id`

- شناسه تسک Celery برای پردازش‌های async
- وقتی fetch داده خاک یا پردازش مرتبط در صف باشد، می‌توان با این فیلد وضعیت را track کرد

#### `farm_boundary`

- مرز مزرعه را به‌صورت JSON نگه می‌دارد
- معمولاً به‌شکل `Polygon` یا ساختار corner-based ذخیره می‌شود
- این فیلد خیلی مهم است چون فقط یک نقطه center نگه نمی‌دارید، بلکه شکل کلی زمین هم ثبت می‌شود

#### `created_at` / `updated_at`

- زمان ایجاد و آخرین به‌روزرسانی رکورد

### propertyهای مهم `SoilLocation`

#### `center_latitude`

- فقط alias برای `latitude` است

#### `center_longitude`

- فقط alias برای `longitude` است

#### `is_complete`

- بررسی می‌کند آیا هر سه لایه خاک برای این location ثبت شده‌اند یا نه
- شرط آن این است که تعداد `depths` دقیقاً 3 باشد

### فیلدهای مهم `SoilDepthData`

این مدل برای هر location سه رکورد عمق خاک نگه می‌دارد:

- `0-5cm`
- `5-15cm`
- `15-30cm`

فیلدهای اصلی:

- `soil_location`: ارتباط به `SoilLocation`
- `depth_label`: مشخص می‌کند داده برای کدام عمق است
- `bdod`: چگالی ظاهری خاک
- `cec`: ظرفیت تبادل کاتیونی
- `cfvo`: حجم قطعات درشت خاک
- `clay`: درصد رس
- `nitrogen`: مقدار نیتروژن
- `ocd` و `ocs`: شاخص‌های کربن آلی
- `phh2o`: pH خاک
- `sand`: درصد شن
- `silt`: درصد سیلت
- `soc`: کربن آلی خاک
- `wv0010`: رطوبت حجمی در فشار 10 kPa
- `wv0033`: رطوبت در حدود ظرفیت زراعی
- `wv1500`: رطوبت در نقطه پژمردگی دائم

این فیلدها برای شبیه‌سازی، آبیاری، و تخمین وضعیت واقعی خاک مهم هستند.

### فیلدهای مهم `NdviObservation`

- `location`: ارتباط با `SoilLocation`
- `observation_date`: تاریخ مشاهده
- `mean_ndvi`: میانگین NDVI
- `ndvi_map`: داده مکانی NDVI
- `vegetation_health_class`: کلاس سلامت پوشش گیاهی
- `satellite_source`: منبع تصویر مثل `sentinel-2`
- `cloud_cover`: درصد پوشش ابر
- `metadata`: داده تکمیلی

---

## نکته مهم: grid بندی زمین انجام می‌شود

بله، در لایه داده و سنجش از دور، مفهوم grid بندی وجود دارد.

اما این grid بندی در پروژه بیشتر در این دو سطح دیده می‌شود:

### 1) grid در NDVI map

در `location_data/remote_sensing.py` داده NDVI به‌صورت grid محاسبه و ذخیره می‌شود.

یعنی:

- تصویر ماهواره‌ای به خانه‌های کوچک‌تر تقسیم می‌شود
- برای هر خانه مقدار NDVI محاسبه می‌شود
- خروجی در `ndvi_map` معمولاً به‌شکل grid نگه‌داری می‌شود

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

### 2) grid/cell در adapter خاک

در `location_data/soil_adapters.py` هم منطق cell/grid دیده می‌شود، مخصوصاً در adapterهای mock یا interpolation-based.

یعنی:

- مختصات lat/lon به cellهای شبکه‌ای نگاشت می‌شود
- در بعضی محاسبات از `grid_x` و `grid_y` استفاده می‌شود
- این کمک می‌کند داده خاک برای ناحیه‌های نزدیک، رفتار مکانی منطقی‌تری داشته باشد

### نتیجه مهم

خود مدل `SoilLocation` یک مرکز زمین را نگه می‌دارد، ولی مرز مزرعه و NDVI grid باعث می‌شوند سیستم فقط point-based نباشد.

یعنی:

- مرکز زمین برای lookup سریع و اتصال به داده خاک/هوا استفاده می‌شود
- مرز مزرعه برای شکل واقعی زمین ذخیره می‌شود
- grid بندی برای تحلیل مکانی، مخصوصاً در NDVI، انجام می‌شود

---

## مرکز زمین چطور از مرز مزرعه به‌دست می‌آید

در `farm_data/services.py` از روی `farm_boundary`، مرکز هندسی polygon محاسبه می‌شود.

پس flow کلی این‌طور است:

1. مرز مزرعه ارسال می‌شود
2. polygon نرمال می‌شود
3. centroid هندسی آن محاسبه می‌شود
4. یک `SoilLocation` برای center ساخته یا پیدا می‌شود
5. بعد داده خاک، NDVI و هوا به این location متصل می‌شوند

پس زمین فقط با یک نقطه خام ثبت نمی‌شود؛ اول مرز دارد، بعد center از روی آن به‌دست می‌آید.

---

## متدهای کمکی `location_data/apps.py`

### `get_ndvi_health_service()`

- خروجی `self.ndvi_health_service` را برمی‌گرداند
- یک accessor ساده برای گرفتن سرویس NDVI است

### `get_soil_data_adapter()`

- خروجی `self.soil_data_adapter` را برمی‌گرداند
- بقیه بخش‌های پروژه از این متد برای گرفتن adapter فعال استفاده می‌کنند
/
---

## فیلدها و settingهای مهم مرتبط با `location_data/apps.py`

### فیلدهای AppConfig

- `default_auto_field`: نوع primary key پیش‌فرض مدل‌ها
- `name`: نام داخلی اپ
- `verbose_name`: نام نمایشی اپ

### settingهای استفاده‌شده

- `SOIL_DATA_PROVIDER`: انتخاب provider فعال خاک
- `SOILGRIDS_TIMEOUT_SECONDS`: timeout برای provider واقعی SoilGrids
- `SOIL_MOCK_DELAY_SECONDS`: تاخیر مصنوعی برای provider mock

---

## 2) فایل `farm_data/apps.py`

این فایل AppConfig مربوط به اپ `farm_data` را تعریف می‌کند.

کلاس اصلی:

```python
class FarmDataConfig(AppConfig):
```

### فیلدها

#### `default_auto_field = "django.db.models.BigAutoField"`

- مثل اپ قبلی، تعیین می‌کند primary key پیش‌فرض مدل‌های این اپ از نوع `BigAutoField` باشد.

#### `name = "farm_data"`

- نام داخلی و ماژول اپ Django است.
- برای شناسایی اپ در `INSTALLED_APPS` و registry داخلی Django استفاده می‌شود.

#### `label = "sensor_data"`

- label داخلی اپ در registry Django است.
- این فیلد زمانی مهم می‌شود که:
  - بخواهید نام registry اپ با `name` فرق داشته باشد
  - یا از تداخل نام اپ‌ها جلوگیری کنید
- در این پروژه، اپ `farm_data` با label داخلی `sensor_data` شناخته می‌شود.

نکته:

- `label` باید در کل پروژه یکتا باشد.
- این مقدار ممکن است در migrationها، relationها یا lookupهای app registry اثر داشته باشد.

#### `verbose_name = "farm-data"`

- نام نمایشی اپ است.
- بیشتر برای admin و نمایش انسانی استفاده می‌شود.

---

## نکته مهم درباره `farm_data/apps.py`

برخلاف `location_data/apps.py`، این فایل:

- `cached_property` ندارد
- service locator ندارد
- adapter یا provider انتخاب نمی‌کند

یعنی فعلاً فقط نقش config پایه اپ را دارد.

---

## ارتباط `farm_data/apps.py` با فیلدهای واقعی داده

این app بیشتر داده‌های farm-level و sensor-level را نگه می‌دارد. مهم‌ترین مدل‌هایش:

- `farm_data.models.SensorData`
- `farm_data.models.SensorParameter`
- `farm_data.models.ParameterUpdateLog`

### فیلدهای مهم `SensorData`

#### `farm_uuid`

- شناسه یکتای مزرعه
- primary key این مدل است
- هر رکورد `SensorData` نماینده یک مزرعه است

#### `center_location`

- ارتباط به `location_data.SoilLocation`
- یعنی این مزرعه به یک location مرکزی وصل است
- از همین نقطه مرکزی برای weather/soil/simulation استفاده می‌شود

#### `weather_forecast`

- ارتباط اختیاری با `weather.WeatherForecast`
- اگر موجود باشد، forecast منتخب یا آخرین forecast به مزرعه وصل می‌شود

#### `sensor_payload`

- مهم‌ترین فیلد این مدل است
- داده سنسورها به‌صورت JSON نگه‌داری می‌شود
- ساختار معمول آن شبیه این است:

```json
{
  "sensor-7-1": {
    "soil_moisture": 25.5,
    "soil_temperature": 22.3,
    "soil_ph": 7.2
  }
}
```

مزیت این ساختار:

- چند سنسور در یک مزرعه پشتیبانی می‌شود
- هر سنسور می‌تواند فیلدهای خاص خودش را داشته باشد
- schema سنسورها rigid نیست

#### `plants`

- رابطه چندبه‌چند با `plant.Plant`
- یعنی یک farm می‌تواند چند گیاه مرتبط داشته باشد

#### `irrigation_method`

- روش آبیاری انتخاب‌شده برای مزرعه
- برای recommendation و planning مهم است

#### `created_at` / `updated_at`

- زمان ایجاد و آخرین ویرایش رکورد

### propertyهای مهم `SensorPayloadMixin`

مدل `SensorData` از `SensorPayloadMixin` ارث می‌گیرد و این helperها را دارد:

#### `_payload()`

- payload را فقط وقتی dict معتبر باشد برمی‌گرداند

#### `get_sensor_block(sensor_key=None)`

- اگر `sensor_key` بدهید، همان بلوک سنسور را برمی‌گرداند
- اگر ندهید، اولین بلوک معتبر را برمی‌گرداند

#### `get_metric(metric_name, sensor_key=None)`

- یک metric خاص را از payload پیدا می‌کند
- اول در sensor مشخص‌شده می‌گردد
- اگر پیدا نشد، در بقیه blockها جستجو می‌کند

#### propertyهای آماده

این propertyها shortcut هستند:

- `soil_moisture`
- `soil_temperature`
- `soil_ph`
- `electrical_conductivity`
- `nitrogen`
- `phosphorus`
- `potassium`

یعنی به‌جای parse دستی JSON، مستقیم می‌توان این متریک‌ها را خواند.

### فیلدهای مهم `SensorParameter`

این مدل dictionary پارامترهای سنسور را نگه می‌دارد.

#### `sensor_key`

- کلید سنسور مثل `sensor-7-1`

#### `code`

- کد پارامتر مثل `soil_moisture`

#### `name_fa`

- نام فارسی پارامتر

#### `unit`

- واحد پارامتر مثل `%` یا `dS/m`

#### `data_type`

- نوع داده مثل `float`, `int`, `string`, `bool`

#### `metadata`

- داده تکمیلی برای UI یا validation
- مثلاً:
  - بازه مجاز
  - توضیح
  - تنظیمات نمایش

### فیلدهای مهم `ParameterUpdateLog`

- `parameter`: ارتباط به `SensorParameter`
- `action`: نوع عملیات مثل `added` یا `modified`
- `payload`: خلاصه تغییرات
- `updated_at`: زمان ثبت لاگ

این مدل برای audit و پیگیری تغییرات پارامترها مفید است.

---

## جمع‌بندی

### `location_data/apps.py`

- هم metadata اپ را نگه می‌دارد
- هم سرویس و adapter در اختیار پروژه می‌گذارد
- هم از settingها برای انتخاب provider واقعی یا mock استفاده می‌کند
- و در عمل با location center، مرز مزرعه، داده لایه‌های خاک و gridهای NDVI کار می‌کند

### `farm_data/apps.py`

- فقط config پایه AppConfig را تعریف می‌کند
- نقش آن بیشتر register کردن اپ با نام و label مشخص است
- اما داده‌های اصلی مزرعه مثل `farm_uuid`، `sensor_payload`، گیاه، روش آبیاری و اتصال به center location در مدل‌های همین app نگه‌داری می‌شوند
