14 KiB
Crop Zoning Backend Handoff
این سند برای انتقال منطق موجود در src/views/dashboards/farm/cropZoning/cropZoningUtils.ts از فرانتاند به بکاند تهیه شده است تا تیم بکاند بتواند APIهای لازم را بهصورت پایدار و قابل توسعه پیادهسازی کند.
هدف
منطق فعلی در فرانتاند دو کار اصلی انجام میدهد:
- تولید گرید مربعی از روی یک پلیگان مزرعه
- اختصاص محصول پیشنهادی به هر زون بر اساس یک الگوریتم Rule-based موقت
هدف انتقال به بکاند این است که:
- تولید زونها در یک نقطه مرکزی و قابل اعتماد انجام شود
- منطق پیشنهاد محصول از فرانت حذف شود
- APIها قابل استفاده برای ذخیره، بازخوانی، و توسعه مدل تصمیمگیری واقعی باشند
- در آینده بتوان الگوریتم Rule-based را با مدل دادهمحور یا ML جایگزین کرد بدون تغییر زیاد در فرانت
منطق فعلی فرانت
فایل فعلی شامل دو تابع اصلی است:
1) createGridFromPolygon
ورودی:
- یک
GeoJSON Feature<Polygon> - مقدار
cellSideKmبا مقدار پیشفرض0.15
خروجی:
- یک
FeatureCollection<Polygon>شامل سلولهای مربعی داخل پلیگان - برای هر سلول فقط
properties.indexثبت میشود
رفتار:
- با استفاده از bounding box پلیگان، گرید مربعی ساخته میشود
- فقط بخشهای داخل پلیگان نگه داشته میشوند (
mask) - هر سلول یک اندیس ترتیبی میگیرد
2) createZonedGrid
ورودی:
- یک
GeoJSON Feature<Polygon> - مقدار
cellSideKmبا مقدار پیشفرض0.15
خروجی:
- یک
FeatureCollection<Polygon, ZoneFeatureProperties>
برای هر زون این فیلدها تولید میشوند:
zoneIdcropmatchPercentwaterNeedestimatedProfitreasoncriteria
منطق تخصیص محصول فعلی از تابع ruleBasedCropAssignment میآید.
جزئیات الگوریتم فعلی تخصیص محصول
الگوریتم فعلی موقت و نمایشی است و به داده واقعی مزرعه متصل نیست.
ورودی الگوریتم
index: شماره زونcoords: مختصات پلیگان سلول
نحوه محاسبه
یک seed مصنوعی از این دادهها ساخته میشود:
- اندیس زون
- اولین latitude
- اولین longitude
فرمول فعلی:
seed = index * 7 + floor(lat * 100) + floor(lng * 100)
محصولات ممکن
در وضعیت فعلی فقط این محصولات استفاده میشوند:
wheatcanolasaffron
منطق انتخاب
- محصول با
seed % numberOfCropsانتخاب میشود - درصد تطابق (
matchPercent) بین 60 تا 94 تولید میشود waterNeed،estimatedProfitوreasonاز روی محصول انتخابی از یک map ثابت خوانده میشوندcriteriaنیز بهصورت ساختگی از seed تولید میشود
نکته مهم
این الگوریتم:
- deterministic است
- اما علمی/عملیاتی نیست
- صرفاً برای نمایش UI مناسب بوده
- نباید به همان شکل نهایی در production باقی بماند مگر موقت و با برچسب mock/demo
پیشنهاد معماری بکاند
بهتر است بکاند این منطق را در دو لایه جدا کند:
لایه 1: Zone Generation
مسئول تولید گرید از روی پلیگان مزرعه
لایه 2: Crop Recommendation / Zone Evaluation
مسئول تخصیص محصول و ویژگیهای تحلیلی به هر زون
این جداسازی مهم است چون در آینده ممکن است:
- گرید ثابت بماند اما مدل پیشنهاد محصول عوض شود
- یا زونها ذخیره شوند ولی recommendation دوباره محاسبه شود
APIهای پیشنهادی
API 1: Generate Initial Zones
Purpose تولید گرید اولیه از روی محدوده مزرعه
Method
POST /api/crop-zoning/zones/initial
Request Body
{
"farm_id": 123,
"cell_side_km": 0.15,
"boundary": {
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[51.0,35.0],[51.1,35.0],[51.1,35.1],[51.0,35.1],[51.0,35.0]]]
},
"properties": {}
}
}
Behavior
- اعتبارسنجی GeoJSON انجام شود
- Polygon معتبر بودن بررسی شود
- گرید مربعی با اندازه
cell_side_kmساخته شود - فقط سلولهای داخل boundary برگردانده شوند
- برای هر زون یک شناسه یکتا تولید شود
- در صورت نیاز زونها در DB ذخیره شوند
Response پیشنهادی
{
"farm_id": 123,
"cell_side_km": 0.15,
"zones": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[51.0,35.0],[51.01,35.0],[51.01,35.01],[51.0,35.01],[51.0,35.0]]]
},
"properties": {
"zone_id": "zone-0",
"index": 0
}
}
]
}
}
API 2: Run Crop Recommendation For Zones
Purpose اختصاص محصول پیشنهادی و شاخصها به زونهای تولید شده
Method
POST /api/crop-zoning/zones/recommend
Request Body پیشنهادی
{
"farm_id": 123,
"algorithm": "rule_based_v1",
"zones": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[51.0,35.0],[51.01,35.0],[51.01,35.01],[51.0,35.01],[51.0,35.0]]]
},
"properties": {
"zone_id": "zone-0",
"index": 0
}
}
]
}
}
Behavior
- اگر فعلاً داده واقعی وجود ندارد، همان الگوریتم موقت
rule_based_v1پیادهسازی شود - خروجی برای هر زون شامل crop recommendation و تحلیلها باشد
- اگر زونها از قبل در DB هستند، امکان ارسال فقط
farm_idهم میتواند اضافه شود
Response پیشنهادی
{
"farm_id": 123,
"algorithm": "rule_based_v1",
"zones": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[51.0,35.0],[51.01,35.0],[51.01,35.01],[51.0,35.01],[51.0,35.0]]]
},
"properties": {
"zone_id": "zone-0",
"index": 0,
"crop": "wheat",
"match_percent": 82,
"water_need": "۴۵۰۰-۵۵۰۰ m³/ha",
"estimated_profit": "۱۵-۲۵ میلیون/هکتار",
"reason": "دمای مناسب، خاک حاصلخیز، دسترسی به آب کافی",
"criteria": [
{ "name": "دما", "value": 78 },
{ "name": "بارش", "value": 66 },
{ "name": "خاک", "value": 72 },
{ "name": "آب", "value": 81 }
]
}
}
]
}
}
API 3: Get Saved Zoning Result
Purpose دریافت آخرین نتیجه زونبندی ذخیره شده برای مزرعه
Method
GET /api/crop-zoning/farms/:farmId/zones
Use case
- هنگام ورود مجدد کاربر به صفحه
- جلوگیری از محاسبه مجدد غیرضروری
- نمایش نسخه ذخیرهشده recommendation
Response
- همان ساختار
FeatureCollectionenriched شده با properties کامل هر زون
ساختار داده پیشنهادی
Zone entity
حداقل فیلدهای پیشنهادی برای هر زون:
idfarm_idzone_indexgeometry(GeoJSON Polygon یا نوع spatial معادل)cell_side_kmcreated_atupdated_at
Zone recommendation entity
اگر recommendation جدا ذخیره شود:
idzone_idalgorithm_versioncropmatch_percentwater_needestimated_profitreasoncriteria(JSON)created_at
اگر simplicity مهمتر است، میتوان recommendation را مستقیماً روی جدول zone نیز ذخیره کرد.
قرارداد خروجی پیشنهادی برای فرانت
برای کم کردن تغییرات فرانت، بهتر است response نهایی نزدیک به ساختار فعلی باشد.
ساختار هر feature
{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": []
},
"properties": {
"zone_id": "zone-0",
"index": 0,
"crop": "wheat",
"match_percent": 82,
"water_need": "۴۵۰۰-۵۵۰۰ m³/ha",
"estimated_profit": "۱۵-۲۵ میلیون/هکتار",
"reason": "...",
"criteria": [
{ "name": "دما", "value": 78 }
]
}
}
نکته naming
در فرانت فعلی بعضی فیلدها camelCase هستند:
zoneIdmatchPercentwaterNeedestimatedProfit
اگر بکاند snake_case برمیگرداند، فرانت باید mapper داشته باشد. برای سادهتر شدن integration یکی از این دو رویکرد انتخاب شود:
- بکاند موقتاً همان naming فرانت را برگرداند
- یا فرانت یک adapter ثابت برای map کردن response داشته باشد
پیشنهاد بهتر:
- بکاند از قرارداد استاندارد خودش مثل
snake_caseاستفاده کند - فرانت mapper داشته باشد
پیشنهاد برای نسخه اول پیادهسازی
برای فاز اول، این scope کافی است:
فاز 1
- تولید گرید از polygon در بکاند
- پیادهسازی الگوریتم mock با نام
rule_based_v1 - برگرداندن FeatureCollection کامل
- امکان ذخیره نتیجه برای هر farm
فاز 2
- استفاده از دادههای واقعی مثل:
- نوع خاک
- منابع آب
- اقلیم
- شیب زمین
- سوابق کشت
- نسخهبندی الگوریتم recommendation
- بازمحاسبه recommendation بدون بازتولید geometry
شبهکد بکاند برای الگوریتم موقت
for each zone in zones:
coords = zone.geometry.coordinates
lat = coords[0][0][1] or 35
lng = coords[0][0][0] or 51
seed = zone.index * 7 + floor(lat * 100) + floor(lng * 100)
crops = [wheat, canola, saffron]
crop = crops[abs(seed) % len(crops)]
match_percent = 60 + (abs(seed) % 35)
water_need = map by crop
estimated_profit = map by crop
reason = map by crop
criteria = generated from seed
Validation requirements
بکاند بهتر است این موارد را validate کند:
boundary.type == Featuregeometry.type == Polygon- polygon ring بسته باشد
- مختصات معتبر longitude/latitude باشند
cell_side_km > 0- تعداد زونها از یک سقف منطقی بیشتر نشود
پیشنهاد محدودیت
برای جلوگیری از payload سنگین:
- حداقل
cell_side_kmتعریف شود - یا حداکثر تعداد زون مجاز تعریف شود
- اگر مزرعه خیلی بزرگ باشد response مناسب خطا داده شود
Error responses پیشنهادی
400 Bad Request
برای:
- GeoJSON نامعتبر
- polygon نامعتبر
- cell size نامعتبر
404 Not Found
برای:
- farm پیدا نشد
422 Unprocessable Entity
برای:
- boundary معتبر است ولی برای zoning قابل استفاده نیست
چیزی که باید از فرانت حذف یا ساده شود
بعد از آماده شدن API بکاند، این بخشها از فرانت باید حذف/کم شوند:
- استفاده مستقیم از
createZonedGrid - استفاده مستقیم از
ruleBasedCropAssignment - تولید mock recommendation در کلاینت
و فرانت فقط این مسئولیتها را نگه میدارد:
- ارسال boundary
- دریافت FeatureCollection از API
- نمایش زونها روی نقشه
- نمایش جزئیات recommendation
پیشنهاد نهایی برای تیم بکاند
اگر بخواهیم کمریسک و سریع جلو برویم:
- ابتدا فقط endpoint تولید zone + recommendation را با الگوریتم mock فعلی بسازید
- response را GeoJSON-based نگه دارید
- شناسه و نسخه الگوریتم را در خروجی قرار دهید
- بعداً recommendation engine را از geometry generation جدا کنید
خلاصه اجرایی
منطق فعلی فرانت یک implementation موقت برای:
- ساخت grid از polygon مزرعه
- اختصاص crop recommendation نمایشی به هر zone
پیشنهاد میشود بکاند:
- این منطق را به API منتقل کند
- geometry generation و recommendation را از هم جدا نگه دارد
- در فاز اول همان رفتار deterministic فعلی را با نام
rule_based_v1پیادهسازی کند - خروجی را بهصورت
GeoJSON FeatureCollectionبرگرداند تا فرانت با کمترین تغییر از آن استفاده کند